Новости
Карта сайта
Авторы
Поиск
Рассылки
Статьи и информация
VB хитрости
Популярные ошибки
Книги
Конференция
Программы
Контролы
Примеры
Разное
Ссылки

Статьи

О Vertex Shader'ах (VS) для Visual Basic 6

Количество просмотров: 6729 Автор: Катичев Роман

VS - это программы, выполняемые видео-адаптером при прорисовке каждой вершиы в примитиве. Т.е., например, в треугольнике она выполнится 3 раза. С помощью этих программ можно манипулировать положением, цветом вершины, а так же координатами наложенных на примитив текстур. Появилась эта возможнасть, как и pixel shader в DirectX 8. VS состоят из инструкций и регистров о которых смотрите ближе к концу :)

Как создать Vertex Shader


Во-первых, при создании D3DDevice необходимо указывать D3DCREATE_SOFTWARE_VERTEXPROCESSING или D3DCREATE_MIXED_VERTEXPROCESSING в BehaviorFlags, т.к. в DX8 VS могут обрабатываться только програмно.
Во-вторых, перед прорисовкой примитива с использованием Vertex shader, нужно выполнять следующее:
D3DDevice.SetRenderState D3DRS_SOFTWAREVERTEXPROCESSING, True
Ну, и после прорисовки поменять True на False, если в цикле будут рисоваться примитивы без использования VS.
VS можно составлять прямо в программе, если он неочень длинный, или в любом текстовом фаиле. Любой VS начинается с главной инструкции, в которой определяется его версия.
vs.1.1
 
Затем идут инструкции, о которых см. далее.
Как и pixel shader, VS компилируется с помощью D3DX8 и записывается в массив Long.
Dim buffer As D3DXBuffer, ErrLog As String, bConsts As D3DXBuffer
Set buffer = D3DX.AssembleShaderFromFile(App.Path & "\vs.txt", 0, ErrLog, bConsts)
Dim f() As Long
ReDim f(buffer.GetBufferSize / 4 - 1)
DXCopyMemory f(0), ByVal buffer.GetBufferPointer, buffer.GetBufferSize

Следующим шагом необходимо сделать следующее:
Dim decl As D3DXDECLARATOR
D3DX.DeclaratorFromFVF FVF, decl 

Смысл этой операции в том, чтобы заполнить структуру D3DXDECLARATOR тем типом вершин, с которым Вы будете работать(FVF), т.е. тем форматом, каким записаны вершины в VertexBuffer.
Ну и осталось все эти данные передать D3DDevice.
D3DDevice.CreateVertexShader decl.Value(0), f(0), dwVertexShader, D3DUSAGE_SOFTWAREPROCESSING 

dwVertexShader - это и будет то значение, с помощью которого вызывается VS при прорисовке.
D3DDevice.SetVertexShader dwVertexShader

После этого любая вершина будет рисоваться с учЈтом VS.
 

Инструкции


Полный список инструкций Vertex Shader 1.1 :
add - Складывает 2 вектора
def - Объявляет константу
dp3 - 3-x компонентный DotProduct двух векторов
dp4 - 4-x компонентный DotProduct двух векторов
dst - Считает дистанцию между двумя векторами
exp - 2x с полной точностью
expp - 2x с частичной точностью
frc - Возвращает дробную часть каждого входного компонента
lit - Частичная поддержка освящения
log - log2(x) с полной точностью
logp - log2(x) с частичной точностью
m3x2 - 3х2 матричное умножение
m3x3 - 3х3 матричное умножение
m3x4 - 3х4 матричное умножение
m4x3 - 4х3 матричное умножение
m4x4 - 4х4 матричное умножение
mad - Перемножает 2 вектора и прибавляет 3й
max - Считает максимум двух векторов
min - Считает минимум двух векторов
mov - Копирует один вектор в другой
mul - Перемножает вектора
nop - Ничего не делает
rcp - Обратная величина(1/X)
rsq - 1/sqr(x)
sge - Сравнивает 2 векторв друг с другом.
slt - Сравнивает 2 вектора. slt-противоположная sge инструкция
sub - Вычитание
 

Описание инструкций


add
 
Складывает два исходных вектора
add dest, src0, src1

 
Эквивалентно:
dest.x = src0.x + src1.x
dest.y = src0.y + src1.y
dest.z = src0.z + src1.z
dest.w = src0.w + src1.w

 
def
 
Объявляет константу
def dst, value

 
Записывает 4D вектор value в регистр dest. Например:
dst c0, 1.0, 1.0, 0.5, 0.11

 
dp3
 
3х компонентный DotProduct двух векторов
dp3 dest, src0, src1

 
Эквивалентно:
dest.w = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)
dest.x = dest.y = dest.z = dest.w

 
dp4
 
4х компонентный DotProduct двух векторов
dp4 dest, src0, src1

Эквивалентно:
dest.w = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z) + (src0.w * src1.w)
'dest.x = dest.y = dest.z = не_используется

 
dst
 
Дистанция между двумя векторами
dst dest, src0, src1

Эквивалентно:
dest.x = 1
dest.y = src0.y * src1.y
dest.z = src0.z
dest.w = src1.w

 

exp
 
2x с полной точностью(21 бит)
exp dest, src

Эквивалентно:
dest.x = dest.y = dest.z = dest.w = 2 ^ src.w

 
expp
 
2x с неполной точностью(10 бит)
expp dest, src

 
Эквивалентно:
dim w, v
w = src.w
v = src.w - int(src.w)
dest.x = 2 ^ v
dest.y = w - v

dim tmp, tmpd
tmp = 2 ^ w
tmpd = tmp and &hffffff00
dest.z = tmpd
dest.w = 1

 
frc
 
Возвращает дробную часть каждого входного компонента
frc dest, src

 
Эквивалентно:
dest.x = src.x - int(src.x)
dest.y = src.y - int(src.y)
dest.z = src.z - int(src.z)
dest.w = src.w - int(src.w)

 
lit
 
Подсчитывает освещенность путЈм подсчЈта коэффициента из двух точек и экспоненты
lit dest, src

Эквивалентно:
dest.x = 1
dest.y = 0
dest.z = 0
dest.w = 1
dim power: power = src.w
const MAXPOWER = 127.9961
if power < -MAXPOWER then
    power = -MAXPOWER
elseif power > MAXPOWER then
    power = -MAXPOWER
end if
if src.x > 0 then
    dest.y = src.x
    if src.y > 0 then
        dest.z = src.y ^ power
end if
end if

 

log
 
log2(x) с полной точностью(21 бит)
log dst, src

 
Эквивалентно:
dim v: v = abs(src)
if v <> 0 then
    dest.x = dest.y = dest.z = dest.w = log(v)/log(2) 
else
    dest.x = dest.y = dest.z = dest.w = -FLT_MAX;
end if

 
logp
 
Эквивалентно log, но с 10-битной точностью.
 
m3x2
 
3х2 матричное умножение.
m3x2 dest, src0, src1

Эквивалентно на VB:
dest.x = (src0.x * src1.x) + (src0.x * src1.y) + (src0.x * src1.z)
dest.y = (src0.y * src1.x) + (src0.y * src1.y) + (src0.y * src1.z) 

Или на языке инструкций:
dp3 r0.x, r1, c0
dp3 r0.y, r1, c1

Во всех матричных инструкциях src1 - должен быть равен первой константе d3dmatrix, переданной программой. Например, регистры с0, c1, c2, c3 будут равны значениям матрицы, переданной методом D3DDevice.SetVertexShaderConstant 0, mat, 4
 
m3x3
 
3х3 матричное умножение.
m3x3 dest, src0, src1

 
Эквивалентно на VB:
dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)
dest.y = (src0.x * src2.x) + (src0.y * src2.y) + (src0.z * src2.z)
dest.z = (src0.x * src3.x) + (src0.y * src3.y) + (src0.z * src3.z)

 

Или на языке инструкций:
dp3 r0.x, r1, c0
dp3 r0.y, r1, c1
dp3 r0.z, r1, c2

 

m3x4
 
3х4 матричное умножение.
m3x4 dest, src0, src1

Эквивалентно на VB:
dest.x = (src0.x * src1.x) + (src0.x * src1.y) + (src0.x * src1.z)
dest.y = (src0.y * src1.x) + (src0.y * src1.y) + (src0.y * src1.z)
dest.z = (src0.z * src1.x) + (src0.z * src1.y) + (src0.z * src1.z)
dest.w = (src0.w * src1.x) + (src0.w * src1.y) + (src0.w * src1.z)

 
Или на языке инструкций:
dp3 r0.x, r1, c0
dp3 r0.y, r1, c1
dp3 r0.z, r1, c2
dp3 r0.w, r1, c3

 
m4x3
 
4х3 матричное умножение.
m4x3 dest, src0, src1

 
Эквивалентно на VB:
dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z) + (src0.w * src1.w)
dest.y = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z) + (src0.w * src1.w)
dest.z = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z) + (src0.w * src1.w)

 
Или на языке инструкций:
dp4 r0.x, r1, c0
dp4 r0.y, r1, c1
dp4 r0.z, r1, c2

 

m4x4
 
4х4 матричное умножение.
m4x4 dest, src0, src1

 
Эквивалентно на VB:
dest.x = (src0.x * src1.x) + (src0.x * src1.y) + (src0.x * src1.z) + (src0.x * src1.w)
dest.y = (src0.y * src1.x) + (src0.y * src1.y) + (src0.y * src1.z) + (src0.y * src1.w)
dest.z = (src0.z * src1.x) + (src0.z * src1.y) + (src0.z * src1.z) + (src0.z * src1.w)
dest.w = (src0.w * src1.x) + (src0.w * src1.y) + (src0.z * src1.z) + (src0.w * src1.w)

 
Или на языке инструкций:
dp4 r0.x, r1, c0
dp4 r0.y, r1, c1
dp4 r0.z, r1, c2
dp4 r0.w, r1, c3

 

mad
 
Перемножает и складывает регистры
mad dest, src0, src1, src2

 
Эквивалентно:
dest.x = src0.x * src1.x + src2.x
dest.y = src0.y * src1.y + src2.y
dest.z = src0.z * src1.z + src2.z
dest.w = src0.w * src1.w + src2.w

 
max
 
Выбирает максимум из двух регистров
max dest, src0, src1

 
Эквивалентно:
dest.x=iif(src0.x >= src1.x, src0.x , src1.x)
dest.y=iif(src0.y >= src1.y, src0.y , src1.y)
dest.z=iif(src0.z >= src1.z, src0.z , src1.z)
dest.w=iif(src0.w >= src1.w, src0.w , src1.w)

 
min
 
Выбирает минимум из двух регистров
min dest, src0, src1

 
Эквивалентно:
dest.x=iif(src0.x < src1.x, src0.x , src1.x)
dest.y=iif(src0.y < src1.y, src0.y , src1.y)
dest.z=iif(src0.z < src1.z, src0.z , src1.z)
dest.w=iif(src0.w < src1.w, src0.w , src1.w)

 
mov
 
Переписывает один регистр в другой
mov dest, src

 
Эквивалентно:
dest.x=src.x
dest.y=src.y
dest.z=src.z
dest.w=src.w

 
mul
 
Перемножает регистры
mul dest, src0, src1

 
Эквивалентно:
dest.x = src0.x * src1.x
dest.y = src0.y * src1.y
dest.z = src0.z * src1.z
dest.w = src0.w * src1.w

 
rcp
 
1/X
rcp dest, src

 
Эквивалентно:
 
dim f: f = src0
if f = 0 then
    f = FLT_MAX
else
    if f <> 1.0 then
    f = 1/f
    end if
end if
dest = f

 
rsq
 
1/sqr(x)
rsq dest, src

 
Эквивалентно:
 
dim f: f = abs(src0)
if f = 0 then
    f = FLT_MAX
else
    if f <> 1 then f = 1/sqr(f)
end if
dest.z = dest.y = dest.z = dest.w = f

 

sge
 
Сравнение "больше или равно"
sge dest, src0, src1

 
Эквивалентно:
dest.x = iif(src0.x >= src1.x, 1, 0)
dest.y = iif(src0.y >= src1.y, 1, 0)
dest.z = iif(src0.z >= src1.z, 1, 0)
dest.w = iif(src0.w >= src1.w, 1, 0)

 

slt
 
Сравнение "меньше"
slt dest, src0, src1

 
Эквивалентно:
dest.x = iif(src0.x >= src1.x, 1, 0)
dest.y = iif(src0.y < src1.y, 1, 0)
dest.z = iif(src0.z < src1.z, 1, 0)
dest.w = iif(src0.w < src1.w, 1, 0)

 

sub
 
Вычитание векторов
sub dest, scr0, src1

 
Эквивалентно:
dest = src0 - src1

 

Регистры


Входные регистры
Регистр Тип данных Кол-во Назначение
c# 4D вектор, single 96 Константа
r# 4D вектор, single 12 временный регистр
v# 4D вектор 16 данные из VertexBuffer

 
Выходные регистры
Регистр Тип Кол-во Назначение
oD# 4D vector 2 oD0 \ oD1 - Diffuse \ Specular цвет вершины
oFog скалярная величина 1 Коэффициент тумана. Только oFog.x используется
oPos 4D vector 1 Положение вершины после всех преобразований. Все компоненты (x, y, z, w) должны быть записаны.
oPts скалярная 1 Размер точки, если используется в качестве PointSprites
oT# 4D vector 8 Координаты наложенных текстур

 

Модификаторы


1. _sat - модификатор инструкции. Записывает результат в промежутке от 0 до 1. Например: add_sat dest, src0, src1Не может быть использован для матричных инструкций(m3x2, ...)
2. " - " - модификатор регистра. Меняет знак регистра на противоположный. Например: add dest, src0, -src1
 
Для тех, кто всЈ понял небольшой примерчик ;)
 

Небольшое примечание


Когда начнЈте творить, увидите, что при прорисовке, вне зависимости от положения камеры, у Ваших вершин не будет сохраняться пространственное положение... Т.е. все будет рисоваться на перпендикулярной зрителю плоскости... Как с этим бороться? Вот так:
Получите матрицу вида и проекции и перемножте их(а если меняется и матрица мира(например вращается), то и ее так-же залейте в mat):
Dim matProj As D3DMATRIX
D3DDevice.GetTransform D3DTS_PROJECTION, matProj
D3DDevice.SetTransform D3DTS_VIEW, matView
 
Dim mat As D3DMATRIX
D3DXMatrixIdentity mat
D3DXMatrixMultiply mat, matView, matProj
D3DXMatrixTranspose mat, mat
 

Затем передайте получившуюся матрицу shader'у:
D3DDevice.SetVertexShaderConstant 0, mat, 4
 
А в самом VS в конце добавьте следующее:
m4x4 oPos, r0, c0
 
где r0 - будет записан результат ваших преобразований.
 
Если есть вопросы, пишите, постараюсь ответить.

Добавлено: 30 июня 2005

Отзывы читалелей

Hexfire

Молодец, отличная статья!
Давно не работал с 3D, пора бы вспомнить...
 
ЕщЈ раз респект.

Phil

Какая-то страшная вещь... Насколько я знаю, полигоны прорисовываются по нес-ко тыс. в секунду. ЭТО Ж КАК ТОРМОЗИТ ЭТО ДЕЛО ЕСЛИ ДЛЯ КАЖДОЙ ВЕРШИНЫ ПО ПРОГАММЕ? Если не прав, токо скажите...



Добавить отзыв

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

Ваше имя:
Ваш E-mail:
Ваш комментарий:
 


К статьям

Rambler's Top100
Хостинг от Parking.ru