GPU: преобразование координат вершин с плавающей точкой в ​​фиксированную точку. Как?

По сути, я пытаюсь понять, как работают графические процессоры, когда дело доходит до преобразования координат с плавающей вершиной в числа с фиксированной точкой во время растеризации.

Я прочитал эту прекрасную статью, которая уже многое объясняет, но это также смущает меня. Таким образом, статья объясняет это, потому что мы используем 32-битные целые числа и функцию ребра, которая в следующем виде (a - b)*(c - d) - (e - f)*(g - h)Мы ограничены диапазоном [-16384,16383]. Я понимаю, как мы добираемся до этого числа. Вот мои вопросы:

  1. Во-первых, это говорит о том, что координаты вершин могут быть отрицательными. Однако я не понимаю, что технически на этом этапе координаты вершин находятся в растровом пространстве, и все треугольники должны были быть обрезаны раньше. Таким образом, технически должны быть только координаты вершин в диапазоне [0, ширина изображения] для x-координаты и [0, высота изображения] для y-координаты? Так почему же координаты отрицательны?
  2. Поэтому автор объясняет, что диапазон слишком ограничен [-16384,16383]. Действительно, если у вас есть 2048 пикселей в ширину и вы используете 256 подпикселей, тогда координата точки в x должна быть 4194048. Таким образом, вы получите переполнение. Автор продолжает и объясняет, как они делают это на GPU, чтобы обойти эту проблему, но я просто не понимаю. Если бы кто-то также мог объяснить, как это практически делается на GPU, то было бы здорово.

1 ответ

Решение
  1. Во-первых, это говорит о том, что координаты вершин могут быть отрицательными. Однако я не понимаю, что технически на этом этапе координаты вершин находятся в растровом пространстве, и все треугольники должны были быть обрезаны раньше. Таким образом, технически должны быть только координаты вершин в диапазоне [0, ширина изображения] для x-координаты и [0, высота изображения] для y-координаты? Так почему же координаты отрицательны?

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

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

Вдобавок к этому, в зависимости от реализации, центр экрана может быть определен как (0,0) внутри для целей отсечения вычислений, что означает, что что-либо на левой стороне экрана будет иметь отрицательную координату X,

  1. Поэтому автор объясняет, что диапазон слишком ограничен [-16384,16383]. Действительно, если у вас есть 2048 пикселей в ширину и вы используете 256 подпикселей, тогда координата точки в x должна быть 4194048. Таким образом, вы получите переполнение. Автор продолжает и объясняет, как они делают это на GPU, чтобы обойти эту проблему, но я просто не понимаю. Если бы кто-то также мог объяснить, как это практически делается на GPU, то было бы здорово.

Примечание: я не инженер по графическим процессорам, и это только концептуальный ответ высокого уровня:

Ключевая фраза в объяснении, приведенном в статье, - поэтапная оценка. Посмотрите на orient2d уравнение:

int orient2d(const Point2D& a, const Point2D& b, const Point2D& c)
{
    return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}

Точки a а также b вершины треугольника, а точка c координата экрана. Для данного треугольника вершины треугольника будут оставаться неизменными, пока вы выполняете итерацию по диапазону координат экрана, только точка c изменения. Инкрементная оценка означает, что вы просто рассчитываете то, что изменилось по сравнению с предыдущей оценкой уравнения.

Предположим, мы оцениваем уравнение один раз и получаем результат w0:

w0 = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);

затем c.x увеличивается на величину s (шаг за пиксель). Новая ценность w0 будет:

w0_new = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x+s-a.x);

Вычитая первое уравнение из второго, получаем:

w0_new - w0 = -(b.y-a.y)*s;

-(b.y-a.y)*s является постоянным значением для данного треугольника, потому что s одинаковое количество каждый раз (один пиксель), и a а также b как уже упоминалось, тоже постоянны. Мы можем вычислить его один раз и сохранить в переменной w0_step) и тогда расчет сводится к:

w0_new = w0 + w0step;

Вы можете сделать это для w1 а также w2, а также сделать аналогичную вещь для c.y шаг. Причина, по которой это обеспечивает большую точность, состоит в том, что уравнение на пиксель больше не содержит умножения с фиксированной точкой, что является причиной переполнения. Графический процессор может выполнять высокоточное вычисление один раз для каждого треугольника (например, в 64 битах), а затем выполнять более низкую точность для одного пикселя (например, 32 бита).

Другие вопросы по тегам