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

Posted

技术标签:

【中文标题】如何检测 MTKView 中鼠标按下事件发生的位置?【英文标题】:How do you detect where a mouse down event occurred in an MTKView? 【发布时间】:2019-04-07 01:53:50 【问题描述】:

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

NSView mouseDown 中,只需调用以下命令即可轻松获取鼠标按下事件发生位置的本地坐标:

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

鉴于该局部点,确定在渲染场景的上下文中鼠标按下的位置需要哪些步骤?

现在,我只是在MTKView 中渲染一个 2D 平面。 2D 平面可以在 z 轴上缩放、平移和旋转。由于场景非常简单,我可以在某种程度上强制解决方案,但我想知道更正确的方法是什么。

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

很少有 Metal 教程或参考资料详细讨论鼠标输入和坐标系如何交互。任何见解将不胜感激。

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

【问题讨论】:

这通常称为 pickinghit-testing。这是beenwrittenaboutextensively,虽然在金属中并不常见。它的要点是您计算从屏幕坐标到世界空间的变换(产生一条射线),然后在射线和世界中对象的包围体之间执行相交测试。跨度> 知道正确的搜索词会有很大帮助,谢谢。 【参考方案1】:

在这个问题的部分提示下,我写了an article 关于这个你可能会觉得有用的主题。示例代码在 Swift 中,但概念很容易转移。

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

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

【讨论】:

非凡!感谢您的跟进和持续的 MBE 贡献。矩阵数学需要一些时间来理解,但是一个工作示例(在 macOS 上不少于)对社区来说是一个巨大的好处。

以上是关于如何检测 MTKView 中鼠标按下事件发生的位置?的主要内容,如果未能解决你的问题,请参考以下文章

如何检测fabric js动画对象上的鼠标按下事件

Event事件

Java - 检测鼠标是不是在屏幕上的任何位置按下

JavaFX:如何在屏幕上的任何位置检测鼠标/键事件?

在 MouseDown 事件处理程序中检测 Ctrl+Left(鼠标按钮)

js各事件使用详解