Карта норм пикселей
Как обычно спасибо заранее..
Я использую Pixel Bender для генерации световых эффектов для ландшафта на основе карты высот. Я хотел бы сделать карту нормалей местности и оттуда усеять каждую нормаль к определенному направлению солнца. Довольно стандартная штука на самом деле, но пиксельный бендер играет не очень хорошо. У меня есть этот код:
void
evaluatePixel()
{
float2 pt = outCoord();
pixel3 a = sampleNearest(src,pt);
pixel3 b = sampleNearest(src,float2(pt.x + 1.0, pt.y));
pixel3 c = sampleNearest(src,float2(pt.x, pt.y + 1.0));
float3 v1 = float3(1.0, 0.0, b.r - a.r);
float3 v2 = float3(0.0, 1.0, c.r - a.r);
normalize(v1);
normalize(v2);
float3 n = cross(v1,v2);
dst = pixel3(n.x,n.y,n.z);
}
Я ожидал бы, что это произведет нормальную карту. Чтобы проверить, я предположил, что свет был направлен прямо вниз и просто использовать n.z
в качестве выходного цвета. Это дает сплошной цвет. Если вы возьмете приведенный выше код и запустите его, вы увидите, что, хотя есть расхождение в красном и зеленом, синий всегда заполнен на 255. Почему это? Я ожидаю, что, учитывая v1
а также v2
нормализуются, что это не должно всегда выводить полный синий цвет?
Что я делаю неправильно?!?
1 ответ
Я на самом деле сделал что-то очень похожее с моими картами высот треугольной полосы.
input image3 verts;
output pixel3 triNorms;
void
evaluatePixel()
{
float2 tCoord = outCoord() - 0.5; //move coord from pixel center to lower-left corner
float quadIdx = mod(tCoord[0], 2.0); //potentially faster to use sign(fract(tCoord[0] / 2.0))
float2 vCoord0 = float2(floor(tCoord.x / 2.0), tCoord.y);
float2 vCoord1 = float2(vCoord0.x + 1.0, vCoord0.y + 1.0 - quadIdx);
float2 vCoord2 = float2(vCoord0.x + quadIdx, vCoord0.y + 1.0);
float3 v0 = sampleNearest(verts, vCoord0 + 0.5);
float3 v1 = sampleNearest(verts, vCoord1 + 0.5);
float3 v2 = sampleNearest(verts, vCoord2 + 0.5);
float3 s0 = v1 - v0;
float3 s1 = v2 - v0;
float3 n = cross(s0, s1);
float len = 1.0 / length(n);
n.x *= len;
n.y *= len;
n.z *= len;
triNorms = float3(n.x, n.y, n.z);
}
Это работает удивительно хорошо для меня. Проходит 1,8M вершин менее чем за 100 мс. Просто чтобы прояснить, я определяю свои треугольники как столбцы между вершинами. Это означает, что для каждых 4 вершин есть два треугольника. Я идентифицирую два треугольника на квад с "quadIdx".
Примечание: вы нормализуете, а затем вычисляете крест - это в обратном направлении, вам нужно нормализовать после. Кроме того, я действительно считаю, что нашел ошибку в normalize(). Он создавал NaN там, где я не ожидал. Я реализовал свою собственную нормализацию с помощью length(), и все это прекрасно работает!