Программирование графических процессоров с использованием Direct3D и HLSL

       

Спрайты


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

Работу со спрайтами можно производить через вызовы методов интерфейса ID3DXSprite.

C++LPD3DXSPRITE sprite = NULL;
Pascalvar sprite: ID3DXSprite;

Создание самого объекта производится с помощью вызова функции D3DXCreateSprite, которая имеет два параметра: первый – указатель на устройство вывода, второй – переменная, в которую будет помещен результат.

C++D3DXCreateSprite(device, &sprite);
PascalD3DXCreateSprite(device, sprite);

Для отображения спрайта, как правило, прибегают к такому коду:

sprite->Begin(...) sprite->Draw(...) sprite->End()

Сам вывод спрайта сопряжен с взаимодействием с текстурой. Само изображение спрайта должно храниться в объекте LPDIRECT3DTEXTURE9 (загрузка изображения осуществляется через функцию D3DXCreateTextureFromFile), а вывод его производится через вызов метода Draw интерфейса ID3DXSprite. Данный метод содержит 5 параметров: первый – указатель на текстуру, в которой хранится изображение спрайта, второй определяет прямоугольник вырезки на текстуре (если значение равно NULL, то выводится вся текстура), третий определяет точку, вокруг которой может быть повернут спрайт (если значение NULL, то поворот будет производиться вокруг левого верхнего угла), четвертый параметр задает смещение спрайта относительно верхнего левого угла в экранных координатах, и пятый параметр определяет значение цвета, на который будет умножаться каждый пиксель спрайта (значение 0xFFFFFFFF позволяет оставить значение текселя без изменений).


Простейший пример вывода спрайта может выглядеть следующим образом:

C++

// создание и загрузка спрайта D3DXCreateTextureFromFile(device, "sprite.dds", &tex); D3DXCreateSprite(device, &sprite); … // вывод спрайта на экран sprite->Begin(D3DXSPRITE_ALPHABLEND); sprite->Draw(tex, NULL, NULL, NULL, D3DCOLOR_XRGB(255,255,255)); sprite->End();
Pascal

// создание и загрузка спрайта D3DXCreateTextureFromFile(device, 'sprite.dds', tex); D3DXCreateSprite(device, sprite); … // вывод спрайта на экран sprite._Begin(D3DXSPRITE_ALPHABLEND); sprite.Draw(tex, nil, nil, nil, D3DCOLOR_XRGB(255,255,255)); sprite._End;
Константа D3DXSPRITE_ALPHABLEND в качестве параметра метода Draw указывает на то, что выводится спрайт с прозрачным фоном.

Для масштабирования и вращения спрайтов необходимо использовать матрицы. Интерфейс ID3DXSprite предоставляет метод SetTransform(), где в качестве параметра передается матрица преобразования. Чтобы определить матрицу преобразования можно воспользоваться функцией библиотеки Direct3D – D3DXMatrixAffineTransformation2D(). Данная функция имеет пять параметров: первый определяет матрицу, в которую будет помещен результат, второй параметр определяет коэффициент масштабирования, третий задает точку вращения, четвертый – угол поворота в радианах, пятый параметр определяет вектор смещения спрайта. Следует отметить, что вначале производится операция масштабирования, затем поворот и последний шаг смещение спрайта. Ниже приведен пример вывода спрайт, который увеличен в размерах в два раза по каждой оси, повернут вокруг своего центра на угол 30 градусов и смещен на вектор (150, 100). Пусть размеры спрайта будут 256х256 пикселей.

C++

// объявление переменных D3DXVECTOR2 rot = D3DXVECTOR2(128.0f, 128.0f); D3DXVECTOR2 trans = D3DXVECTOR2(150.0f, 100.0f); D3DXMATRIX mat;

// функция вывода спрата D3DXMatrixAffineTransformation2D(&mat, 2.0f, &rot, 30.0f*pi/180.0f, &trans);

Sprite->Begin(D3DXSPRITE_ALPHABLEND); sprite->SetTransform(&mat); sprite->Draw(tex, NULL, NULL, NULL, D3DCOLOR_XRGB(255,255,255)); sprite->End();
Pascal

// объявление переменных var rot, trans,scale: TD3DXVector2; mat: TD3DXMatrix;

// функция вывода спрата rot:=D3DXVector2(128,128); trans:=D3DXVector2(150,100); D3DXMatrixAffineTransformation2D(mat, 2, @rot, 30*pi/180, @trans);

sprite._Begin(D3DXSPRITE_ALPHABLEND); sprite.SetTransform(mat); sprite.Draw(tex, nil, nil, nil, D3DCOLOR_XRGB(255,255,255)); sprite._End;
<


Ниже показаны примеры вывода спрайта с различными углами поворота.



Для создания анимации на основе спрайтов довольно часто прибегают к следующему подходу. Используют одну текстуру, на которой представлен объект в различных положениях анимации (кадрах). Мы можем использовать второй параметр метода Draw, который позволяет определить прямоугольную область на текстуре для вывода нужного кадра анимации. Ниже приведен пример подобной текстуры с 30 кадрами анимации.



В данном примере каждый кадр имеет размеры 64х64 пикселей. Для того чтобы отобразить кадр с номером i, i=1,…,30, необходимо на исходной текстуре вырезать прямоугольник размерами 64х64 пикселей с координатами левого верхнего угла X = ((i-1) mod 5)*64, Y = ((i-1) div 5)*64, где mod – операция "остаток от отделения", а div – операция "деление без остатка". Так, например, чтобы вывести кадр номер 14, нужно вырезать прямоугольник размером 64х64 с координатами левого верхнего угла (192, 128). Программно вывод нужного кадра (frame) можно реализовать следующим образом:

C++

RECT r; int x0,y0; … x0 = ((frame-1) % 5)*64; y0 = ((frame-1) / 5)*64; r.left = x0; r.top = y0; r.right = x0+63; r.bottom = y0+63; sprite->Begin(D3DXSPRITE_ALPHABLEND); sprite->Draw(tex, &r, NULL, NULL, D3DCOLOR_XRGB(255,255,255)); sprite->End();
Pascal

var r: TRect; x0,y0: Integer; … x0:=((frame-1) mod 5)*64; y0:=((frame-1) div 5)*64; r:=Rect(x0,y0,x0+63,y0+63); sprite._Begin(D3DXSPRITE_ALPHABLEND); sprite.Draw(tex, @r, nil, nil, D3DCOLOR_XRGB(255,255,255)); sprite._End;
Таким образом, можно сделать вывод, что функции для работы со спрайтами в библиотеке Direct3D позволяют использовать их в различных областях двумерной графики.


Содержание раздела