Этот тип однопроходной техники в пространстве обзора обязательно приведет к худшим результатам, чем метод обычной экструзии, но для того, чтобы он вообще работал, вам нужно получить контроль над своими координатными пространствами.
Какова цель здесь?Что ж, мы хотим заметить, когда нормаль поверхности почти перпендикулярна к направлению обзора, и обойти наши обычные расчеты освещения, вместо этого возвращая сплошной цвет силуэта.
Определение перпендикулярности обычно означает взятие точкипродуктов, но в (+ + вверх, правша) поле зрения, направление просмотра просто (0, 0, -1), V
просто (0, 0, 1), и произведение точек между Vи нормаль пространства-представления является просто компонентом z
нормали пространства-представления.
Имея эти знания в руках, нам просто нужно убедиться, что мы передаем пространство зрения, нормальное для нашегоправильно фрагментируйте шейдер.
Во-первых, измените имя нормали, которую мы выделяем из вершинного шейдера, на eyeNormal
, чтобы мы знали, в каком пространстве мы работаем. Затем он вычисляется как
out.eyeNormal = (scn_node.modelViewTransform * float4(in.normal, 0)).xyz;
(где мы делаем простое предположение, что матрица MV не содержит неравномерного масштабирования или сдвига).Нормализовать как обычно в фрагментном шейдере:
float3 normal = normalize(in.eyeNormal);
Избавиться от этого троичного мусора;логическое выражение имеет логический тип, который просто прекрасно преобразуется в float
:
float edgeFactor = normal.z <= 0.3;
Обратите внимание, что, поскольку мы работаем в пространстве представления, на самом деле мы не увидим фрагменты, имеющие normal.z < 0
таким образом, мы также отбрасываем abs
.
Наконец, поскольку мы не будем сохранять какие-либо циклы с таким ранним выходом, мы можем использовать функцию mix
для выбора между освещенным цветом и цветом краякак мы вернемся:
return mix(float4(ambientTerm + diffuseTerm, 1.0), float4(1, 1, 0, 1), edgeFactor);
И вот, у вас это есть, грубые силуэты за полцены: