Статьи
Pixel Shader
 Что такое Pixel Shader
Начиная с DirectX 8.0 Microsoft добавляет новую функцию - Pixel Shader. Это позволило получить новые возможности по преобразованию цвета, наложенных тектур, света, для каждой точки примитива. Pixel shaders - короткие программы, запускаемые во время прорисовки КАЖДОГО пикселя примитива(треугольника), т.е. при вызове DrawPrimitive эта программа будет выполнена столько раз, сколько точек будет в итоге нарисовано.
Эти программы состоят из инструкций(instructions) в формате ASCII текста. Все инструкции можно разделить на арифметические(по пробразованию цвета(diffuse/specular)) и текстурные(преобразование содержимого наложенных текстур). Для получения и записи цветовой информации используют регистры(registers), например, t0-цветовое содержимое текстуры из SetTexture(0, ...) в данной точке, или v0-цвет пикселя из буфера вершин, установленного с помощью SetStreamSource(0, ...). Их значения будут менятся в зависимости от того, какой пиксель примитива в данный момент прорисовывается устройством.
Текст pixel shader'ов похож на ассемблер и компилируется с помощью объекта D3DX из фаила или текстовой строки. Скомпилированный shader передаЈтся Direct3DDevice, и может быть использован во время прорисовки вызовом SetPixelShader. После этого, каждый пиксель будет рисоваться с учЈтом программы shader'а.
 Создание Pixel Shader'a
Для создания PS необходимо выполнить следующие шаги:
 Проверить устройство на наличие поддержки данной технологии.
 Создать буфер вершин.
 Написать сам pixel shader.
 Скомпилировать и передать Direct3DDevice.
 Нарисовать содержимое буфера вершин.
 1. Проверяем версию PS
Существует несколько версий pixel shader'ов (друг от друга они отличаются добавлением новых инструкций). И прежде чем начинать экспириментировать, проверьте какая версия у вас. Сделать это можно так:
Получите информацию о вашем Direct3DDevice.
Dim caps As D3DCAPS8
D3DDevice.GetDeviceCaps caps
Вставте в текст программы слкдующий код (это аналог функции из DirectX 9 для С++). Аргументы major и minor - это первая и вторая цифры версии, которую вы хотите получить(например, 1 и 1 для версии 1.1, или 1 и 4 для версии 1.4).
Function D3DPS_VERSION(ByVal major As Byte, ByVal minor As Byte) As Long
Dim B As D3DXBuffer
Set B = D3DX.CreateBuffer(4)
D3DX.BufferSetData B, 0, 1, 1, minor
D3DX.BufferSetData B, 1, 1, 1, major
D3DX.BufferSetData B, 2, 1, 1, &HFF
D3DX.BufferSetData B, 3, 1, 1, &HFF
D3DX.BufferGetData B, 0, 4, 1, D3DPS_VERSION
Set B = Nothing
End Function
И перед созданием shader'ов выполните следующее, например, для проверки наличия версии 1.1(будем работать именно с ней):
If caps.PixelShaderVersion < D3DPS_VERSION(1, 1) Then
MsgBox "Версия вашего pixel shader'a меньше необходимой"
'Выход из процедуры здесь
End If
PixelShaderVersion возвращает число, содержащее самую последнюю доступную для использования версию, и если оно меньше полученного из функции D3DPS_VERSION, то ничего не получится. :(
 2. СоздаЈм буфер вершин.
В примере будем использовать 1 буфер вершин следующего типа:
Private Const D3DFVF_CUSTOMVERTEX = D3DFVF_XYZ Or D3DFVF_DIFFUSE Or D3DFVF_TEX1
Private Type CUSTOMVERTEX
x As Single
y As Single
z As Single
color As Long
tu As Single
tv As Single
End Type
Private VB as Direct3DVertexBuffer8
Зададим вершины и создадим буфер вершин:
Dim V(3) As CUSTOMVERTEX
v(0).x = -1: v(0).y = -1: v(0).z = 0: v(0).color = &HFF0000FF: v(0).tu = 0: v(0).tv = 1
v(0).x = 1: v(0).y = -1: v(0).z = 0: v(0).color = &HFFFF0000: v(0).tu = 1: v(0).tv = 1
v(0).x = 1: v(0).y = 1: v(0).z = 0: v(0).color = &HFFFFFF00: v(0).tu = 1: v(0).tv = 0
v(0).x = -1: v(0).y = 1: v(0).z = 0: v(0).color = &HFFFFFFFF: v(0).tu = 0: v(0).tv = 0
Set vb = D3DDevice.CreateVertexBuffer(D3DX.GetFVFVertexSize(D3DFVF_CUSTOMVERTEX) * 4, _
0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED)
D3DVertexBuffer8SetData vb, 0, D3DX.GetFVFVertexSize(D3DFVF_CUSTOMVERTEX) * 4, 0, v(0)
 3. Пишем Pixel Shader.
В данном примере напишем простенький PS, который будет добавлять diffuse цвет из буфера вершин к цвету пикселя из текстуры. Создайте текстовый фаил pixelshader.txt в папке с вашей программой и поместите в него следующий текст:
ps.1.1
add r0, t0, v0
ps.1.1 - означает, что мы будем использовать Pixel Shader версии 1.1
add r0, t0, v0 - инструкция, записывающая в первый регистр(аргумент) сумму значений второго и третьего аргументов. В данном случае мы записываем в результирующий регистр r0(т.е. регистр, в котором должен содержаться результат всех наших действий) t0+v0, где t0-цвет пикселя текстуры в данной точке, v0-цвет пикселя из буфера вершины в точке. О других инструкциях, модификаторах и регистрах смотрите далее.
 4. Компилируем Pixel Shader.
Для компиляции нам потребуется D3DX и буфер D3DXBuffer, где будет храниться скомпилированный PS, и строка pError, в которой будет содержаться информация об ошибках компиляции(если они конечно будут).
Dim Buffer As D3DXBuffer
Dim pError As String
Dim PixelShader As Long
Set Buffer = D3DX.AssembleShaderFromFile(App.Path & "\pixelshader.txt", 0, pError, Nothing)
Dim I As Long
Dim f() As Long
I = pData.GetBufferSize / 4 'колличество инструкций в ps в виде Long
ReDim f(I - 1)
D3DX.BufferGetData pData, 0, 4, I, f(0)'переписываем буфер в массив Long
Set pData = Nothing 'очищаем буфер
PixelShader = D3DDevice.CreatePixelShader(f(0))
В случае успешного создания PS значение PixelShader будет отличаться от 0 и равно порядковому номеру этого shadera. Это значение будет использовано в процедуре прорисовки.
 5. Прорисовка
Воспользуемся заранее загруженной текстурой - Tex1. Этот код идЈт в процессе прорисовки сцены.
D3DDevice.SetRenderState D3DRS_LIGHTING, False
D3DDevice.SetVertexShader D3DFVF_CUSTOMVERTEX
D3DDevice.SetStreamSource 0, vb, D3DX.GetFVFVertexSize(D3DFVF_CUSTOMVERTEX)
D3DDevice.SetTexture 0, Tex1
D3DDevice.SetPixelShader PixelShader
D3DDevice.DrawPrimitive D3DPT_TRIANGLEFAN, 0, 2
После прорисовки всего необходимого вызываем SetPixelShader(0) для того, чтобы PS не распространялся на другие примитивы, к которым он не должен быть применЈн.
Теперь запускаем и смотрим что получиться если рисовать...


  ...только цвет из буфера вершин
 |
  ...только текстуру
 |
  ...наложенную текстуру с diffuse цветом
 |
  ...наш PixelShader
 |

Не забывайте в конце программы Выполнять Direct3DDevice.DeletePixelShader(pixelshader), для каждого созданного shader'а.
 Инструкции(Instrctions)
Арифметические инструкции, доступные в Pixel Shader версии 1.1

 ps |
 Объявляет начало инструкций(необхдим для любого shader) ps.X.Y х,y - версия инсткций. |
 add |
 Складывает два регистра add dst, src0, src1 ????dst-результат; src0,src1-складываемые регистры (dst = src0 + src1) |
 cnd |
 Выбирает src1, если src0.a > 0.5, иначе src2 cnd dst, src0, src1, src2 ????dst-результат
(dst = iif(src0.a > 0.5, src1, src2)) |
 lrp |
 Линейная интерполяция между src1 и src2 с пропорцией src0 lrp dst, src0, src1, src2 (dest = src0 * src1 + (1-src0) * src2) |
 mad |
 Перемножает src0 и src1, и пребавляет src2 mad dst, src0, src1, src2 (dst = (src0 * src1) + src2) |
 mov |
 Копирует src в dst mov src, dst (dst = src) |
 mul |
 Перемножает src0 и src1 mul dst, src0, src1 (dst = src0 * src1) |
 nop |
 Не производить никаких операций |
 sub |
 Вычитает из src0 src1 sub dst, src0, src1 (dst = src0 - src1) |
 dp3 |
 Считает DotProduct3 src0 и src1 dp3 dst, src0, src1 (dest.w = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z) + (src0.w * src1.w)) |
 def |
 Объявляет константу cn def cn, val1, val2, val3, val4 ????Val1, val2, val3, val4 - значения константы(все из них должны присутствовать), тип - single Константа может быть использована как аргумент к инструкциям в виде цвета rgba или координаты xyzw |
 Текстурные инструкции

 tex |
 Записывает в регистр tn текстуру. tex tn |
 texbem |
 Применяет bump environment преобразование. texbem dest, src |
 texcoord |
 Интерпритирует координаты UVW1 как цвет RGBA texcoord dest |
 texkill |
 Отменяет прорисовку пикселя, если любой из компонентов координаты UVW равен или меньше 0. texkill src |
 texreg2ar |
 Переписывает информацию о координате текстуры(u, v) и записывает еЈ в alpha и red каналы texreg2ar dest, src |
 texreg2gb |
 Переписывает информацию о координате текстуры(u, v) и записывает еЈ в green и blue каналы texreg2gb dest, src |
 Регистры(Registres)
Регистры, доступные для использования. Любой из них может быть передан как аргумент к инструкциям приведЈнным выше.

 Имя |
 Описание
 | Max кол-во
|
 cn |
 Константа |
 8 |
 rn |
 Временный регистр, в r0 - должен быть записан результат пробразований |
 2 |
 tn |
 Текстура |
 4 |
 vn |
 Цвет vertex'а v0-diffuse v1-specular |
 2 |
Где n - от 0 до Max кол-ва.
 Модификаторы(Modifiers)
Типы модификаторов:
 Модификаторы арифметических инструкций.
Применяются для умножения, деления или установления значения результата выполнения инструкции от 0.0 до 1.0.
_x2 или _x4 умножает результат на 2 или 4.
_d2 делит результат на 2.
_sat утонавливает результат выполнения в промежутке от 0 до 1.
Пример:
add_x2 - умножит результат сложения двух регистров на 2.
mul_sat - результат будет в промежутке от 0 до 1.
 Модификаторы регистров.
_bias - вычитает из регистра 0.5. dest = src - 0.5. Например: mov r0, t0_bias
Invert - Выполняет следующую операци dest = 1 - src. Например: mul r0, r0, 1-r1
Negate - меняет знак регистра на противоположный. dest = -src. Например: mul r0, r0, -v1
Signed Scaling - вычитает из регистра 0.5 и умножает на 2. dest = 2 * (src - 0.5). Например: dp3_sat r0, t0_bx2, v0_bx2
Готовый пример Вы можете скачать здесь.
Добавлено: 29 апреля 2005
Отзывы читалелей
Janus
Замечательна! Я как раз мечтал об этом.
Большое спасибо - Авторам стати и сайта.
ARTCat
Статьи очень интересные. Для многих начинающих и тех кто уже програмирует на VB просто отличная помощь!!!!!!!!!!!! Молодцы создатели сайта и авторы статей! Так держать!
Георгий
Ух ты !!! Здорово! Огромное спасибо авторам статьи и сайта !!!
Добавить отзыв
Eсли
вы уже читали эту статью, не сочтите за труд, напишите пару строк о ваших
впечатлениях . Они будут опубликованы здесь для других читателей.
|