如何检测MTKView中的鼠标按下事件发生的位置?

时间:2018-11-02 19:50:55

标签: objective-c macos metal metalkit

这可能更像是一个通用的图形编程问题,但是目前,这是在macOS上使用Apple的Metal框架的背景下。

NSView mouseDown中,只需调用以下命令即可获取发生鼠标按下事件的位置的本地坐标,这很简单。

NSPoint localPoint = [self convertPoint:event.locationInWindow fromView:nil];

给定该局部点,确定在渲染场景的上下文中鼠标按下发生在哪里需要采取什么步骤?

现在,我只是在MTKView中渲染2D平面。二维平面可以在z轴上缩放,平移和旋转。因为场景是如此简单,所以我可以蛮力解决该问题,但是我想知道哪种方法更正确。

感觉就像我必须在我的Objective-C代码中复制一些顶点着色器逻辑一样,以确保正确应用所有变换。但是我不确定在应用旋转时该世界如何工作。

很少有《金属》教程或参考文献谈论鼠标输入以及坐标系如何相互作用。任何见识将不胜感激。

在此示例中,如果用户单击橙色平面,则如何确定该特定对象内的标准化坐标? (在此示例中,可能类似于[0.8,0.9])

MTKView Diagram

1 个答案:

答案 0 :(得分:2)

部分地由这个问题提示,我写了an article对此主题,您可能会觉得有用。示例代码在Swift中,但是概念很容易传递。

以下是用于在macOS上从屏幕空间坐标转换为世界空间坐标的Objective-C算法的草图:

// 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...