Вершинные шейдеры являются вашими спасителями при работе с комбинированием морфированных анимаций. Ранее в этой главе, вы видели, что необходимо делать при комбинировании мешей - блокировать каждый буфер вершин, вычислять разности и наконец комбинировать значения, выполняя кадр за кадром этот медленный процесс.

Говоря об основных причинах медленной обработки, особенно если буферы вершин находятся в видео памяти. Использование вершинных шейдеров гарантирует увеличение скорости обработки комбинированных морфированных анимаций, потому что вы можете хранить все данные меша в быстрой видео памяти и позволить вершинному шейдеру обрабатывать все.

Комбинированный вершинный шейдер будет работать аналогично тому, как вы непосредственно комбинировали координаты вершин ранее в этой главе. Для каждого комбинируемого меша вам необходимо получить доступ к его буферу вершин. Используя вершинные шейдеры, необходимо будет ассоциировать каждый буфер вершин с потоком вершин. Вместо того чтобы для получения данных вершин блокировать буфер вершин, вы используете данные потока вершин (как ассоциировано в объявлении вершин) для получения координат и нормалей.

Единственно проблемой является то, что вершинные шейдеры не могут использовать так много потоков. В дополнение, каждый вершинный шейдер имеет доступ к ограниченному количеству вершинных регистров (таких как координаты, нормали и текстурные координаты). DirectX 8 и 9 ограничивает число вершинных регистров 16, так что приходится считать каждый кусочек информации.

Если структура вершин должна содержать по крайне мере координаты вершины, нормаль и текстуру (всего три регистра на один поток), то вы можете использовать только пять мешей, один из которых базовый. В вершинном шейдере вы можете установить до четырех комбинированных мешей. Первым шагом к созданию вершинного шейдера комбинированного морфирования является определение структур и объявлений вершин. Помните, что необходимо сохранять минимальное количество данных (максимум три используемых регистра), так что структура вершины может выглядеть так:

typedef struct {

D3DXVECTOR3 vecPos; //Координаты вершины

D3DXVECTOR3 vecNormal; //Нормаль вершины

float u,v; //Текстурные координаты } sBlendVertex;

Комментарии внутри структуры sBlendVertex говорят сами за себя, так что я пропущу объяснения и перейду к объявлению вершин.

// Объявления и интерфейсы вершинного шейдера D3DVERTEXELEMENT9 g_MorphBlendMeshDecl [] == {

// Первый поток используется для базового меша

// задать положение, нормаль и текстурные координаты

{0,0,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT, \

D3DDECLUSAGE_POSITION,0 }, {0,12,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,

D3DDECLUSAGE_NORMAL,0 }, {0,24,D3DDECLTYPE_FLOAT2,D3DDECLMETHOD_DEFAULT,

D3DDECLUSAGE_TEXCOORD,0 },

// Второй поток используется для первого меша {1,0,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,1 } ,

(1,12,Р3РС'ЕСЕТУРЕ_ЕЕОАТ3,Р3РС'ЕСЕМЕТН0Р_РЕЕАиЕТ,

Р3РРЕСЕША0Е_ЮКМАЕ,1 }, (1,24,Р3РС'ЕСЕТУРЕ_ЕЕОАТ2,Р3РС'ЕСЕМЕТН0Р_РЕЕАиЕТ,

Р3РРЕСЕи8АОЕ_ТЕХСООРТ,1 },

// Третий поток используется для второго меша (2,0, Б3ББЕСЬТУРЕ_ЕЪОАТ3,Б3ББЕСЬМЕТНОР_БЕЕАиЬТ,

Р3РОЕСЕи8АОЕ_РО81Т1ОЫ,2 }, (2,12,Р3РРЕСЕТУРЕ_ЕЕОАТ3,Р3РС'ЕСЕМЕТНХЮ_РЕЕАиЕТ,

Р3РОЕСЕи8АОЕ_КЮКМАЕ,2 }, (2,24,Р3РРЕСЕТУРЕ_ЕЕОАТ2,Р3РРЕСЕМЕТНОР_РЕЕАиЕТ,

Р3РОЕСЕШАОЕ_ТЕХСООКР,2 } ,

// Четвертый поток используется для третьего меша ' (3,0,Р3РРЕСЕТУРЕ_ЕЕОАТ3,Р3РРЕСЕМЕТНОР_РЕЕАиЕТ,

Р3РОЕСЕи8АОЕ_РО81Т1ОЫ,3 }, (3,12,Р3РРЕСЕТУРЕ_ЕЕОАТ3,Р3РРЕСЕМЕТНОи_РЕЕАиЕТ,

Р3РОЕСЕи8АОЕ_ЮКМАЕ,3 }, (3,24,Р3РРЕСЕТУРЕ_ЕЕОАТ2,Р3РРЕСЕМЕТНОР_РЕЕАиЕТ,

Р3РОЕСЕи8АОЕ_ТЕХСООКР,3 },

// Пятый поток используется для четвертого меша (4,0, Б3ББЕСЬТУРЕ_ЕЪОАТ3,Б3ББЕСЬМЕТНОР_БЕЕАиЬТ,

Р3РОЕСЕШАОЕ_РО31Т1ОЫ,4 }, (4,12,Р3РРЕСЕТУРЕ_ЕЕОАТ3,Р3РРЕСЕМЕТНОР_РЕЕАиЕТ,

Р3РОЕСЕи8АОЕ_ЮКМАЕ,4 }, (4,24,Р3РРЕСЕТУРЕ_ЕЕОАТ2,Р3РРЕСЕМЕТНОР_РЕЕАиЕТ,

Р3РОЕСЕи8АОЕ_ТЕХСООКР,4 },

Р3РОЕСЕ_ЕШ()

В §_В1епёМофгЮес1 вы можете видеть объявление пяти потоков, содержащих трехмерное положение, нормаль и двухмерные текстурные координаты. Первый поток имеет индекс использования 0, второй поток имеет индекс использования 1 и т. д. Это означает, что у вершинного шейдера будет доступ к пяти используемым типам для каждой компоненты вершины (положения, нормали и текстурных координат). В таблице 10.1 показаны типы данных, хранимые в каждом вершинном регистре.

После того как вы создали структуру вершин и их объявление, вы можете переходить к созданию самого вершинного шейдера. Шейдер будет дублировать то, что вы делали ранее в этой главе. Для каждой комбинируемой вершины вы вычисляете разность координат целевого морфируемого и базового меша.

Замечание. Вы можете найти вершинный шейдер комбинированного морфирования (МогрпВ1епа.у$п) на компакт диске. Посмотрите конец этой главы для получения дополнительной информации о демонстрационной программе комбинированного морфирования.

Таблица 10.4. Назначение вершинных регистров комбинированной

морфируемой анимации

Вершинный регистр

Назначение

v0

Трехмерные координаты первого (базового) меша

VI

Нормаль первого (базового) меша

у2

Текстурные координаты первого (базового) меша

\\3

Трехмерные координаты второго меша

\4

Нормаль второго меша

\\5

Текстурные координаты второго меша

\\6

Трехмерные координаты третьего меша

\7

Нормаль третьего меша

\\8

Текстурные координаты третьего меша

\\9

Трехмерные координаты четвертого меша

Нормаль четвертого меша

VII

Текстурные координаты четветого меша

Трехмерные координаты пятого меша

Нормаль пятого меша

^14

Текстурные координаты пятого меша

Эта разность масштабируется на заданное процентное соотношение (с помощью константы вершинного шейдера, находящейся в диапазоне от 0 до 1), и результат, полученный от каждого комбинируемого меша, добавляется к результирующему набору координат положения, нормали и текстурных координат выходной вершины. Просто, не правда ли?

Посмотрите на код вершин, чтобы увидеть что происходит.

,^0 =Положєуиє (xyz) базового меша

,^1 =Нормаль (xyz) базового меша

,^2 =Текстурные координаты (ху) базового меша

,^3 комбинированное положение (xyz) первого меша

,^4 комбинированная нормаль (xyz) первого меша

,^5 =Комбинированные текстурные координаты (ху) первого меша

,^6 комбинированное положение (xyz) второго меша ,^7 комбинированная нормаль (xyz) второго меша

;у8 комбинированные текстурные координаты (ху) второго меша

;у9 комбинированное положение (xyz) третьего меша

;у10 =Комбинированная нормаль (xyz) третьего меша

;у11 =Комбинированные текстурные координаты (ху) третьего меша

;у12 комбинированное положение (xyz) четвертого меша

;у1З =Комбинированная нормаль (xyz) четвертого меша

;у14 =Комбинированные текстурные координаты (ху) четвертого меша

;с0-с3 =матрица мир+вид+проекция

; с4 комбинированные значения 0-1 (mesh1,mesh2,mesh3,mesh4) ; с5 =направление света ув. 1.0

Сначала, вы увидите комментарии, помогающие определить назначение используемых регистров вершин и констант. Перед вызовом вершинного шейдера необходимо установить шесть констант вершин.

• От с0 до с3 должны содержать транспонированную матрицу преобразования мир*вид*проекция.

• с4 содержит значения комбинирования для каждого меша (с4.х для меша 1, с4.у для меша 2, с4.2 для меша 3 и с4.л¥ для меша 4).

• с5 содержит вектор направления света.

Я вернусь к этим константам немного позже; а пока я продолжу код вершинного шейдера. После комментариев я добавил необходимую версию вершинного шейдера. Как вы можете видеть, вершинный шейдер комбинированного морфирования требует вершинного шейдера версии 1.0, который должен поддерживаться большинством карт, к тому времени, как вы будете читать эту книгу.

После комментариев и необходимой версии идет объявление ассоциации элементов вершин. Эти объявления используются для привязывания компонент вершин, определенных в массиве В3ВУЕКТЕХЕЬЕМЕ1ЧТ9, к регистрам вершин шейдера. Эти ассоциации идентичны показанным в таблице 10.1, так что это должно быть понятно.

;объявить привязывание бс1_ровісіоп у0 ;базовый меш бс1_погта1 у1 бс1_сехсоогб у2

бс1_ровісіоп1 уЗ ;первый меш бс1_погта11 у4 бс1_сехсоогб1 у5

бс1_ровісіоп2 у6 ;второй меш бс1_погта12 у7 бс1_сехсоогб2 у8

dcl_position3 v9 ;третий меш dcl_normal3 v10 dcl_texcoord3 v11

dcl_position4 v12 ;четвертый меш dcl_normal4 v13 dcl_texcoord4 v14

После ассоциирования регистров вершин вы можете получить доступ к данным вершин, используя регистры от v0 до v14. Регистр v0 содержит координаты вершины базового меша; регистр v6 содержит координаты вершины второго меша и т. д.

В начале фактического кода вершинного шейдера координаты вершины базового меша и его нормаль помещаются в два временных регистра (г0 и г1).

; Поместить базовые координаты и нормаль в регистры r0 и r1 mov r0,v0 ;координаты (r0) mov r1,v1 ;нормаль (r1)

Шейдер использует эти два регистра только в качестве ссылок, так что они не будут переписаны при вызове последующих функий (по крайне мере до завершения работы шейдера, как вы скоро увидите). Следующий кусочек кода вычисляет разность координат базового меша и меша, заданного в качестве первого комбинируемого, который использует регистры вершин начиная с v3 до v5. Разность масштабируется (умножается) на значение константы с4.х (значение от 0 до 1) и прибавляется к начальным координатам из г0, хранимым в регистре г4. На протяжении оставшейся работы вершинного шейдера г4 будет содержать результирующие координаты вершины комбинированного меша. Точно такой же процесс повторяется для нормалей, а результат хранится в г5. Посмотрите:

;Получить разности первого комбинируемого меша и добавить их ;к результату

sub r2,v3,r0 ;Получить разность координат mad r4,r2,c4.x,r0 ;Поместить результат вr4 sub r3,v4,r1 ;Получить разность нормалей mad r5,r3,c4.x,r1 ; Поместить результат вr4

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

;Получить разности второго комбинированного меша и добавить их к ; результату

sub r2,v6,r0 ;Получить разность координат

mad г4,г2,с4.у,г4 /Добавить полученные координаты к r4 sub r3,v7,r1 /Получить разность нормалей

mad r5,r3,c4.y,r5 /Добавить полученную нормаль к r5 /Получить разности третьего комбинированного меша и добавить их к /результату

sub r2,v9,r0 / Получить разность координат

mad r4,r2,c4.z,r4 / Добавить полученные координаты к r4

sub r3,v10,r1 / Получить разность нормалей

mad r5,r3,c4.z,r5 / Добавить полученную нормаль к r5

/Получить разности четвертого комбинированного меша и добавить их к /результату

sub r2,v12,r0 / Получить разность координат

mad r4,r2,c4.w,r4 / Добавить полученные координаты к r4

sub r3,v13,r1 / Получить разность нормалей

mad r5,r3,c4.w,r5 / Добавить полученную нормаль к r5

После того как вы получили результирующую комбинированную вершину (в г4), вершинный шейдер должен преобразовать ее положение на матрицу объединенного преобразования мира, вида и проекции (хранимой в константах от с0 до с3). Что же касается нормали (сохраненной в г5), вы можете векторно умножить ее на обратное направление света (хранимое в с5) для получения рассеянной компоненты цвета, используемого для затемнения многоугольников.

/ Спроецировать положение, используя преобразование мир*вид*проекция m4x4 oPos,r4,c0

/Векторно умножить нормаль на обратное направление света dp3 oD0,r5,-c5

Наконец, текстурные координаты могут быть взяты из регистра вершин базового меша v2 и помещены в выходной регистр текстуры t0.

/Сохранить текстурные координаты mov oT0.xy,v2

На этом заканчивается программирование вершинного шейдера. Все, что остается сделать, - это поместить шейдер в проект и выяснить, как заставить его работать.

Комбинирование разностей || Оглавление || Использование вершинного шейдера морфируемого комбинирования