Подтвердить что ты не робот

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

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

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

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

Diagonal lines visible in the rendered result

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Есть несколько трюков, которые вы можете сделать, чтобы немного упростить процесс.

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

Ответ 2

Хорошо... поскольку вы используете технику Бент-нормалей, лучший способ увеличить результат - до-тесселятная сетка и пересчет с сеткой с более высокой тесселяцией.

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