OpenGL: Как я избегаю погрешностей округления при определении ультрафиолетовых координат

Я пишу 2D игру с помощью OpenGL. Когда я хочу блитировать часть структуры как спрайт, я использую glTexCoord2f (u, v) для определения ультрафиолетовых координат, с u и v, вычисленным как это:

GLfloat u = (GLfloat)xpos_in_texture/(GLfloat)width_of_texture;
GLfloat v = (GLfloat)ypos_in_texture/(GLfloat)height_of_texture;

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

Что может быть сделано об этом? В данный момент я вычитаю значение 'эпсилона' из правых краев и базовых краев прямоугольника, и это, кажется, работает, но это походит на ужасный клудж. Есть ли какие-либо лучшие решения?

6
задан R Samuel Klatchko 27 February 2010 в 04:32
поделиться

3 ответа

Выполните деление как двойное, округлите результат вниз до желаемого уровня точности, затем преобразуйте его в GLFloat.

0
ответ дан 17 December 2019 в 04:45
поделиться

Ваши xpos / ypos должны быть основаны на от 0 до (ширина или высота) - 1, а затем:

GLfloat u = (GLfloat)xpos_in_texture/(GLfloat)(width_of_texture - 1);
GLfloat v = (GLfloat)ypos_in_texture/(GLfloat)(height_of_texture - 1);
-1
ответ дан 17 December 2019 в 04:45
поделиться

Скорее всего, ваша проблема связана не с ошибками округления, а с непониманием того, как OpenGL сопоставляет тексели с пикселями. Если вы замечаете ошибки "off-by-one", это, вероятно, потому, что ваши UV, позиции вершин или ваша проекционная матрица/пара видовых экранов не выровнены там, где они должны быть.

Для упрощения я буду говорить только о 1D, и буду считать, что вы используете проекцию и видовой экран, которые отображают координаты X,Y на эквивалентное расположение пикселей (т.е. glOrtho(0,width,0,height,zmin,zmax) и glViewport(0,width,0,height)).

Скажем, вы хотите нарисовать 5 текселей (начиная с 0 для простоты) вашей 64-широкой текстуры, отображающейся на 10 пикселях (масштаб 2) вашего экрана, начиная с пикселя 20.

Чтобы добиться этого, нарисуйте треугольник с координатами X 20 и 30, и U (из пары UV) 10/64 и 15/64. Растеризация OpenGL создаст 10 пикселей для затенения с координатами X 20.5, 21.5, ... 29.5. Обратите внимание, что позиции не являются полными целыми числами. OpenGL растеризует в середине пикселя.

Аналогично, он сгенерирует U-координаты 10.25/64, 10.75/64, 11.25/64, 11.75/64 ... 14.25/64, 14.75/64. Заметим еще раз, что координаты текселей, приведенные к позициям текселей в пространстве текстур, не являются полными целыми числами. OpenGL делает выборку из середины расположения текселей, так что это нормально.

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

В целом, если вы будете следовать общим принципам, которые я изложил, вы никогда не увидите артефактов.

  1. Используйте Ortho и Viewport точно по размеру буфера кадра
  2. Используйте позиции X, X+width точно
  3. Используйте UVs, которые соответствуют именно тем текселям, которые вы хотите (если вы хотите 10 текселей, начиная с текселя 0, используйте U=0 до U=10.

Если у вас в математике где-то есть -1, то это, скорее всего, неправильно (для позиции или UVs).

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

4
ответ дан 17 December 2019 в 04:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: