Текстуры с виду хорошие, но с недостатком - у них размер не степень двойки.
Я сделал пример с текстурами, которые ты выложил в начале, кроме OCC (честно говоря, не понял, что это).
Но DISP и SPEC - монохромные, я их запихнул в альфаканалы COLOR и NRM текстур, что и тебе советую делать. Дело в том, что семплирование текстуры (texld) - одна из самых тяжёлых инструкций пиксельного шейдера, чем их меньше - тем лучше. А "тусовать" различные каналы в текстурах очень просто, я для этого использую SR2D, вот программа, которой я из четырёх текстур сделал две, там всё предельно просто и понятно:
https://yadi.sk/d/R7i7sbI6b9GEQТеперь к самому ландшафту, вот проект:
https://yadi.sk/d/Yjtp5amIb9L5oИз формата вертекса убрана лишняя пара текстурных координат, направление на свет и позицию камеры передаём в вертексный шейдер без предварительной трансформации, так как ландшафт у нас неподвижен. А вот значения Diffuse, Ambient и Specular теперь передаём не в вертексный, а в пиксельный шейдер, коли уж мы делаем попиксельное освещение.
В VB6 коде больше ничего не поменялось (в классе LandScape добавил генерацию TBN, но это к теме не относится), главное - в шейдерах.
Вертексный шейдер:
- Код: Выделить всё
dp3 oT1.x, v1, c4
dp3 oT1.y, v2, c4
dp3 oT1.z, v3, c4
Эти три инструкции dp3 - это то же самое, что макрос m3x3, но макрос может работать только с последовательностью констант в качестве матрицы, а нам нужна последовательность полей в вертексе v1..v3.
Три вектора, Tangent Binormal и Normal составляют базис, то есть вместе как раз составляют матрицу 3*3, необходимую для поворота вектора в локальную систему координат объекта. Ведь, раз мы используем Normal Map, мы нормали берём из текстуры, их ещё нужно "доворачивать" в зависимости от того, как ориентирована текстурируемая точка на модели. Но мы, как и в прошлом примере, поворачиваем не нормаль, а направление на источник света.
sub r0, c5, v0 - вычислили направление на камеру.
И тоже повернули:
- Код: Выделить всё
dp3 oT2.x, v1, r0
dp3 oT2.y, v2, r0
dp3 oT2.z, v3, r0
Заметь, для передачи векторов из вертексного шейдера в пиксельный мы используем oT1 и oT2, регистры, предназначенные для текстурных координат. Просто кроме них есть только oD0 и oD1, предназначенные для цветовых значений, других каналов для связи вертексного шейдера с пиксельным нет.
Пиксельный шейдер:
texld r0, t0, s0 - семплируем Color текстуру.
texld r1, t0, s1 - семплируем Normal текстуру. Но диапазон возможных значений цвета 0..1, а нам нужно -1..1, ведь это не цвет, а вектор, поэтому приводим диапазон:
mad r1.rgb, r1, c3.x, c3.y - у первого аргумента, приёмника, стоит маска
.rgb. Это потому, что в альфаканале лежит Specular Map, его диапазон приводить не нужно.
Далее нормализуем направления:
- Код: Выделить всё
nrm r2, t1
nrm r3, t2
Направление на источник света у нас было изначально нормализовано, но при интерполяции между вертексами при растеризации длина вектора может несколько измениться (пояснять не нужно?), а направление на камеру у нас вообще не было нормализовано.
На данный момент что имеем в регистрах:
- Код: Выделить всё
// r0 - col + disp map
// r1 - norm + spec map
// r2 - dir to light norm
// r3 - dir to camera norm
Далее:
dp3 r4, r1, r2 - "сравнили" нормаль с направлением на свет.
max r4, r4, c4.x - отсекли значения <0. Теперь в r4 у нас освещённость данной точки (ещё не совсем Diffuse).
Так же, как мы вычисляли спекуляр для модели в прошлом примере, вычисляем и тут:
- Код: Выделить всё
add r6, r2, r3
nrm r5, r6
dp3 r5, r1, r5
mad r5, r5, c3.z, c3.w
max r5, r5, c4.x
mul r5, r5, c2
mul r5, r5, r4
В последней строке значение Specular домножается на величину освещенности, чтобы убрать блики в тех местах, куда не попадает свет.
mul r4, r4, c0 - получили цвет Diffuse.
mad r4, c1, r0.a, r4 - добавили Ambient с учётом карты DISP
mul r4, r4, r0 - домножили на цвет из текстуры.
mad r0, r5, r1.a, r4 - сложили полученный цвет со Specular, умноженным на выборку из Specular Map.
mov oC0, r0 - в бэкбуфер.
Вроде, всё. Попробуй в коде перед рисованием ландшафта обнулять цвета Diffuse, Ambient и Specular, оставляя только один, чтобы увидеть действие этих величин по отдельности.