Различные векторы OpenGL/GLSL: как избежать звездообразования вокруг вершин?

В OpenGL 2.1 я передаю позицию и вектор нормали в свой вершинный шейдер. Затем вершинный шейдер устанавливает varying вектору нормали, так что теоретически он линейно интерполирует нормали по каждому треугольнику. (Что, как я понимаю, является основой затенения Фонга.)

Во фрагментном шейдере я использую нормаль с законом Ламберта для расчета диффузного отражения. Это работает, как и ожидалось, за исключением того, что интерполяция между вершинами выглядит забавно. В частности, я наблюдаю эффект звездообразования, когда по краям между вершинами есть заметные «горячие точки».

Вот пример, не из моей собственной визуализации, но демонстрирующий точно такой же эффект (см. золотую сферу внизу страницы): http://pages.cpsc.ucalgary.ca/~slongay/pmwiki-2.2.1/pmwiki.php?n=CPSC453W11.Lab12

Википедия говорит, что это проблема с затенением Горо. Но насколько я понимаю, интерполируя нормали и выполняя пофрагментный расчет освещения, я использую модель Фонга, а не Гуро. Это правильно?

Если бы я использовал гораздо более мелкую сетку, я полагаю, что эти звездообразования были бы гораздо менее заметны. Но является ли добавление большего количества треугольников единственным способом решить эту проблему? Я бы подумал, что есть способ получить плавную интерполяцию без эффекта звездообразования. (Я определенно видел идеально гладкое затенение на грубых сетках в других местах, например, в 3d Studio Max. Но, возможно, они делают что-то более сложное, чем просто интерполяция нормалей.)


person rlkw1024    schedule 31.12.2011    source источник


Ответы (2)


Это не точно эффект. То, что вы видите, является одной из двух вещей.

  1. Результат того, что нормали не нормализованы перед их использованием во фрагментном шейдере.

  2. Оптическая иллюзия, создаваемая столкновением линейных градиентов по краям треугольников. Действительно.

    Раздел "Градиент имеет значение" внизу этой страницы (примечание: в интересах полного раскрытия, это мой учебник) подробно объясняет это явление. Простое диффузное отражение Ламберта с использованием интерполированных нормалей эффективно создает более или менее линейный свет поперек треугольника. Треугольник с другим набором нормалей будет иметь другой градиент. Он будет непрерывным C0 (цвета по краям одинаковы), но не непрерывным C1 (цвета вдоль двух градиентов меняются с разной скоростью).

    Человеческое зрение улавливает подобные градиентные различия и выделяет их. Таким образом, мы видим их как бескомпромиссные, хотя на самом деле это не так.

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

person Nicol Bolas    schedule 31.12.2011
comment
№ 2 подходит для моей ситуации. Отличное объяснение! Это имеет смысл. Кстати, ваш учебник был чрезвычайно полезен для меня за последние несколько месяцев. (Думаю, это доказывает, что я должен прочитать все, поскольку раздел, на который вы указываете, действительно отвечает на мой вопрос.) - person rlkw1024; 01.01.2012
comment
Итак, просто чтобы уточнить, когда вы предлагаете использовать карту нормалей, я предполагаю, что вы имеете в виду передачу ее фрагментному шейдеру через модуль текстуры? - person rlkw1024; 01.01.2012
comment
@Jarrett: Да, это идея. Но это немного сложнее. Это то, о чем я планирую поговорить в уроке 18. Кроме того, обратите внимание, что наличие хорошей карты диффузной текстуры помогает; если вы рисуете сплошными цветами, легко заметить градиент. Если у вас есть текстура, градиент труднее увидеть. - person Nicol Bolas; 01.01.2012

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

person Chris Dodd    schedule 31.12.2011
comment
Они точно нормализовались. - person rlkw1024; 01.01.2012
comment
Очень неприятный баг, т. Однажды я искал несколько часов. - person RecursiveExceptionException; 01.10.2016