如何检测 MTKView 中发生鼠标按下事件的位置?
How do you detect where a mouse down event occurred in an MTKView?
这可能更像是一个通用的图形编程问题,但目前这是在 macOS 上使用 Apple 的 Metal 框架的上下文中。
在 NSView mouseDown
中,只需调用以下命令即可轻松获取鼠标按下事件发生位置的本地坐标:
NSPoint localPoint = [self convertPoint:event.locationInWindow fromView:nil];
给定该局部点,需要执行哪些步骤来确定在渲染场景的上下文中发生鼠标按下的位置?
目前,我只是在 MTKView
中渲染 2D 平面。二维平面可以在 z 轴上缩放、平移和旋转。我可以用蛮力来解决这个问题,因为场景太简单了,但我想知道更正确的方法是什么。
感觉好像我必须在我的 Objective-C 代码中复制一些顶点着色器逻辑,以确保正确应用所有变换。但是我不太确定应用旋转时这个世界是如何工作的。
很少有 Metal 教程或参考资料谈论鼠标输入和坐标系如何交互。任何见解将不胜感激。
在此示例中,如果用户单击橙色平面,您如何确定该特定对象内的归一化坐标? (在此示例中,它可能类似于 [0.8, 0.9])
受此问题的部分提示,我就此主题撰写了 an article,您可能会觉得有用。示例代码在 Swift 中,但概念很容易转移。
这是一个 Objective-C 算法的草图,用于在 macOS 上从屏幕-space 坐标转换为世界-space 坐标:
// Get viewport dimensions
CGFloat width = view.bounds.size.width;
CGFloat height = view.bounds.size.height;
// Convert from AppKit view coordinates to Metal viewport coordinates
CGPoint location = [view convertPoint:event.locationInWindow toView:nil];
location.y = height - location.y;
// Compute clip-to-view and view-to-world matrices
simd_float4x4 inverseProjectionMatrix = simd_inverse(projectionMatrix);
simd_float4x4 inverseViewMatrix = simd_inverse(viewMatrix);
// Convert from screen coordinates to clip-space coordinates
float clipX = (2 * location.x) / width - 1;
float clipY = 1 - (2 * location.y) / height;
simd_float4 clipCoords = (simd_float4){ clipX, clipY, 0, 1 };
// Determine direction of picking ray in view space
simd_float4 eyeRayDir = simd_mul(inverseProjectionMatrix, clipCoords);
eyeRayDir.z = -1;
eyeRayDir.w = 0;
// Determine direction of picking ray in world space
simd_float4 worldRayDir = simd_mul(inverseViewMatrix, eyeRayDir);
worldRayDir = simd_normalize(worldRayDir);
// Determine origin of picking ray in world space
simd_float4 eyeRayOrigin = (simd_float4){ 0, 0, 0, 1};
simd_float4 worldRayOrigin = simd_mul(inverseViewMatrix, eyeRayOrigin);
...do intersection testing against object bounds...
这可能更像是一个通用的图形编程问题,但目前这是在 macOS 上使用 Apple 的 Metal 框架的上下文中。
在 NSView mouseDown
中,只需调用以下命令即可轻松获取鼠标按下事件发生位置的本地坐标:
NSPoint localPoint = [self convertPoint:event.locationInWindow fromView:nil];
给定该局部点,需要执行哪些步骤来确定在渲染场景的上下文中发生鼠标按下的位置?
目前,我只是在 MTKView
中渲染 2D 平面。二维平面可以在 z 轴上缩放、平移和旋转。我可以用蛮力来解决这个问题,因为场景太简单了,但我想知道更正确的方法是什么。
感觉好像我必须在我的 Objective-C 代码中复制一些顶点着色器逻辑,以确保正确应用所有变换。但是我不太确定应用旋转时这个世界是如何工作的。
很少有 Metal 教程或参考资料谈论鼠标输入和坐标系如何交互。任何见解将不胜感激。
在此示例中,如果用户单击橙色平面,您如何确定该特定对象内的归一化坐标? (在此示例中,它可能类似于 [0.8, 0.9])
受此问题的部分提示,我就此主题撰写了 an article,您可能会觉得有用。示例代码在 Swift 中,但概念很容易转移。
这是一个 Objective-C 算法的草图,用于在 macOS 上从屏幕-space 坐标转换为世界-space 坐标:
// Get viewport dimensions
CGFloat width = view.bounds.size.width;
CGFloat height = view.bounds.size.height;
// Convert from AppKit view coordinates to Metal viewport coordinates
CGPoint location = [view convertPoint:event.locationInWindow toView:nil];
location.y = height - location.y;
// Compute clip-to-view and view-to-world matrices
simd_float4x4 inverseProjectionMatrix = simd_inverse(projectionMatrix);
simd_float4x4 inverseViewMatrix = simd_inverse(viewMatrix);
// Convert from screen coordinates to clip-space coordinates
float clipX = (2 * location.x) / width - 1;
float clipY = 1 - (2 * location.y) / height;
simd_float4 clipCoords = (simd_float4){ clipX, clipY, 0, 1 };
// Determine direction of picking ray in view space
simd_float4 eyeRayDir = simd_mul(inverseProjectionMatrix, clipCoords);
eyeRayDir.z = -1;
eyeRayDir.w = 0;
// Determine direction of picking ray in world space
simd_float4 worldRayDir = simd_mul(inverseViewMatrix, eyeRayDir);
worldRayDir = simd_normalize(worldRayDir);
// Determine origin of picking ray in world space
simd_float4 eyeRayOrigin = (simd_float4){ 0, 0, 0, 1};
simd_float4 worldRayOrigin = simd_mul(inverseViewMatrix, eyeRayOrigin);
...do intersection testing against object bounds...