From 177a5f13f0208e88aa3d4e8576f829db54520454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=90=8C=E6=96=B0?= <3209970865@qq.com> Date: Wed, 12 Jun 2024 10:29:11 +0800 Subject: [PATCH] Feat: use ray cast check mouse over model --- ops.py | 9 ++++++-- utils/ray_cast.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 utils/ray_cast.py diff --git a/ops.py b/ops.py index 7762122..1d446cb 100644 --- a/ops.py +++ b/ops.py @@ -1,7 +1,8 @@ from math import degrees, radians import bpy -from bpy.types import Operator + +from .utils.ray_cast import RayCast def get_node(node_tree=None, match_type=None) -> [bpy.types.Node, ...]: @@ -32,7 +33,7 @@ def check_modal_exit(event): return event.type == "RIGHTMOUSE" and event.value == "RELEASE" -class HdrRotationOperator(Operator): +class HdrRotationOperator(RayCast): bl_idname = 'hdr.rotation' bl_label = 'HDR Rotation' bl_options = {'UNDO'} @@ -68,6 +69,9 @@ def invoke(self, context, event): self.start_x = event.mouse_region_x if context.area and context.area.type == "VIEW_3D": + if self.get_mouse_location_ray_cast(context, event): + # mouse over model + return {'FINISHED', 'PASS_THROUGH'} if self.use_scene_world: if len(self.nodes) == 0: self.report({'WARNING'}, "World Environment Not Mapping Node,Please add a Mapping node") @@ -87,6 +91,7 @@ def invoke(self, context, event): return {'FINISHED', 'PASS_THROUGH'} def modal(self, context, event): + # print(event.value, event.type, event.value_prev, event.type_prev) if check_modal_exit(event): modal_exit() return {'FINISHED'} diff --git a/utils/ray_cast.py b/utils/ray_cast.py new file mode 100644 index 0000000..697178d --- /dev/null +++ b/utils/ray_cast.py @@ -0,0 +1,57 @@ +import bpy +import gpu +import numpy as np +from bpy.types import Operator +from gpu.types import Buffer + + +class RayCast(Operator): + + @staticmethod + def get_gpu_buffer(xy, wh=(1, 1), centered=False) -> Buffer: + """ 用于获取当前视图的GPU BUFFER + :params xy: 获取的左下角坐标,带X 和Y信息 + :type xy: list or set + :params wh: 获取的宽度和高度信息 + :type wh: list or set + :params centered: 是否按中心获取BUFFER + :type centered: bool + :return bpy.gpu.Buffer: 返回活动的GPU BUFFER + """ + + if isinstance(wh, (int, float)): + wh = (wh, wh) + elif len(wh) < 2: + wh = (wh[0], wh[0]) + + x, y, w, h = int(xy[0]), int(xy[1]), int(wh[0]), int(wh[1]) + if centered: + x -= w // 2 + y -= h // 2 + + depth_buffer = gpu.state.active_framebuffer_get().read_depth(x, y, w, h) + return depth_buffer + + @classmethod + def gpu_depth_ray_cast(cls, x, y, data) -> None: + size = 10 # ray cast pixels + + buffer = cls.get_gpu_buffer([x, y], wh=[size, size], centered=True) + numpy_buffer = np.asarray(buffer, dtype=np.float32).ravel() + min_depth = np.min(numpy_buffer) + data['is_in_model'] = (min_depth != (0 or 1)) + + def get_mouse_location_ray_cast(self, context, event) -> bool: + x, y = (event.mouse_region_x, event.mouse_region_y) + view3d = context.space_data + show_xray = view3d.shading.show_xray + view3d.shading.show_xray = False + data = {} + sp = bpy.types.SpaceView3D + han = sp.draw_handler_add(self.gpu_depth_ray_cast, + (x, y, data), 'WINDOW', + 'POST_PIXEL') + bpy.ops.wm.redraw_timer(type='DRAW', iterations=1) + sp.draw_handler_remove(han, 'WINDOW') + view3d.shading.show_xray = show_xray + return data['is_in_model']