Преобразование координат экрана в нормализованные координаты устройства металла - PullRequest
1 голос
/ 08 октября 2019

Я пытаюсь визуализировать 2D-треугольник, используя прикосновения пользователя. Итак, я позволю пользователю трогать три точки на экране, и эти точки будут использоваться в качестве вершин треугольника.

1 Ответ

2 голосов
/ 08 октября 2019

Вы уже знаете, что вам нужно возвращать координаты пространства клипа (технически не нормализованные координаты устройства ) из вашего вершинного шейдера. Вопрос в том, как и где перейти от координат UIKit к координатам пространства клипа Metal.

Давайте начнем с определения этих различных пространств. Обратите внимание, что ниже я на самом деле am для простоты использую координаты NDC, поскольку в данном конкретном случае мы не представляем перспективу, возвращая позиции вершин с w != 1. (Здесь я имею в виду w координату позиции пространства клипа; в следующем обсуждении w всегда относится к ширине вида).

UIKit to Metal NDC transform

Мы передаем вершины в наш вершинный шейдер в любом удобном для вас пространстве (это часто называют модельным пространством ). Поскольку мы работаем в 2D, нам не нужны обычные серии преобразований в мировое пространство, а затем в пространство глаз. По сути, координаты вида UIKit - это наше модельное пространство, мировое пространство и пространство глаз все в одном.

Нам нужна какая-то матрица ортографической проекции для перемещения из этого пространства в пространство клипа. Если мы уберем ненужные части, связанные с осью z, и предположим, что источником границ нашего вида является (0, 0), мы получим следующее преобразование:

UIKit to NDC transformation as a matrix

Мы могли бы передать эту матрицу в наш вершинный шейдер или выполнить преобразование перед отправкой вершин в графический процессор. Учитывая, как мало данных, на самом деле это не имеет значения в данный момент. На самом деле, использование матрицы вообще немного расточительно, поскольку мы можем просто преобразовать каждую координату с помощью пары умножений и сложения. Вот как это может выглядеть в вершинной функции Metal:

float2 inverseViewSize(1.0f / width, 1.0f / height); // passed in a buffer
float clipX = (2.0f * in.position.x * inverseViewSize.x) - 1.0f;
float clipY = (2.0f * -in.position.y * inverseViewSize.y) + 1.0f;
float4 clipPosition(clipX, clipY, 0.0f, 1.0f);

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

Some sample points transformed

Эти точки выглядят правильнымиИтак, мы закончили. Если вас беспокоит очевидное искажение, вызванное этим преобразованием, обратите внимание, что оно точно отменяется преобразованием области просмотра , которое происходит до растеризации.

...