Как сделать билинейную интерполяцию нормалей над квадроциклом?

Я работаю над движком, похожим на Minecraft, в качестве хобби-проекта, чтобы посмотреть, насколько далеко можно продвинуть концепцию воксельных ландшафтов на современном оборудовании и OpenGL >= 3. Итак, вся моя геометрия состоит из четырехугольников или квадратов, если быть точным.

Я построил raycaster для оценки окружающего затенения и использовал технику «изогнутых нормалей» для освещения. Так что мои нормали не перпендикулярны к четырехугольнику и не имеют единичной длины; скорее, они указывают примерно на пространство, где происходит наименьшая окклюзия, и становятся короче, когда квадроцикл получает меньше света. Преимущество этого метода в том, что он требует только одноразового расчета окклюзии и практически бесплатен во время рендеринга.

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

Диагональные линии, видимые в результате визуализации

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

Я могу придумать некоторые обходные пути:

  1. Вставьте нормали в текстуру RGB 2x2 и позвольте процессору текстур выполнить билинейную интерполяцию. Это происходит за счет поиска текстуры во фрагментном шейдере. Мне также нужно было бы упаковать все эти мини-текстуры в более крупные для эффективности.

  2. Используйте атрибуты вершин, чтобы прикрепить все 4 нормали к каждой вершине. Также прикрепите к каждой вершине некоторые коэффициенты [0..1], очень похожие на текстурные координаты, и выполните билинейную интерполяцию во фрагментном шейдере. Это происходит за счет передачи шейдеру 4 нормалей вместо 1.

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

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

Любые идеи, как еще подойти к этой проблеме? Если нет, то какой из двух вышеперечисленных методов будет лучшим?


person Thomas    schedule 11.02.2012    source источник
comment
GL_QUADS устарел в opengl 3   -  person LAX1DUDE    schedule 09.09.2018


Ответы (2)


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

Боюсь, решения, которые вы себе представляете, — лучшее, чего вы можете достичь. И независимо от того, что вы выберете, вам нужно будет передать [0..1] коэффициенты от вершины к шейдеру (включая текстуры 2x2. Они вам нужны для текстурных координат).

Тем не менее, есть некоторые хитрости, которые вы можете сделать, чтобы несколько упростить этот процесс.

  • Использование идентификатора вершины может помочь вам найти, какой вершинный «угол» передать от вершинного шейдера к фрагментному (наши значения [0..1]). Простой битовый тест на младших 2 битах может дать вам знать, какой угол пройти вниз, без фактического ввода данных вершины. При упаковке данных текстуры вам все равно нужно передать идентификатор внутри текстуры, так что это может быть спорным.
  • если вы используете текстуры 2x2 для интерполяции, есть (были?) некоторые ошибки. Некоторые интерполяторы текстур не обязательно обеспечивают высокоточную интерполяцию, если источник изначально имеет низкую точность. Это может потребовать от вас изменить тип данных текстуры на что-то более точное, чтобы избежать артефактов полос.
person Bahbar    schedule 11.02.2012

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

Другим способом могут быть некоторые трюки с пиксельным шейдером... один из возможных способов - вы можете интерполировать текстуру самостоятельно (и не использовать встроенный интерполятор) в пиксельном шейдере, что может вам очень помочь. И вы не ограничены только билинейной интерполяцией, вы могли бы сделать лучше, Ф.е. бикубическая интерполяция ;)

person ZarakiKenpachi    schedule 11.02.2012
comment
Я не хочу увеличивать плотность сетки, так как пытаюсь вытолкнуть как можно больше блоков. Я знаю, как интерполировать текстуры самостоятельно, но я не хочу хранить свои нормали в текстуре, если могу помочь - отсюда и этот вопрос! - person Thomas; 13.02.2012