Как вы определяете, где произошло событие нажатия мыши в MTKView? - PullRequest
0 голосов
/ 02 ноября 2018

Это может быть больше общим вопросом графического программирования, но сейчас это происходит в контексте использования платформы Apple Metal в macOS.

В NSView mouseDown тривиально получить локальные координаты, где произошло событие нажатия мыши, просто вызвав:

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

Учитывая эту локальную точку, какие шаги необходимо предпринять, чтобы определить, где произошло нажатие мыши в контексте визуализированной сцены?

Пока я просто рендеринг 2D-плоскости в MTKView. 2D-плоскость можно масштабировать, перемещать и поворачивать по оси Z. Я могу несколько грубо заставить решение, потому что сцена очень проста, но мне интересно, что является более правильным подходом.

Такое ощущение, что мне пришлось бы дублировать некоторую логику вершинного шейдера в моем коде Objective-C, чтобы обеспечить правильное применение всех преобразований. Но я не совсем уверен, как этот мир работает, когда применяется вращение.

Очень немногие учебники или справочники по Metal много говорят о вводе мышью и взаимодействии систем координат. Любое понимание будет оценено.

В этом примере, если пользователь щелкнул оранжевую плоскость, как вы определяете нормализованные координаты в этом конкретном объекте? (В этом примере это может быть что-то вроде [0,8, 0,9])

MTKView Diagram

1 Ответ

0 голосов
/ 07 ноября 2018

Отчасти благодаря этому вопросу я написал статью на эту тему, которая может оказаться вам полезной. Пример кода написан на языке 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...
...