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


Построение стандартных объектов


Библиотека Direct3D располагает рядом встроенных функций для построения простых стандартных трехмерных примитивов (куб, цилиндр, сфера, тор):

  1. D3DXCreatePolygon // полигон
  2. D3DXCreateBox // параллелограмм
  3. D3DXCreateCylinder // цилиндр
  4. D3DXCreateSphere // сфера
  5. D3DXCreateTorus // тор
  6. D3DXCreateTeapot // чайник

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

Функция создания полигона (правильного многоугольника):

D3DXCreatePolygon( ссылка на устройство вывода, длина стороны полигона, количество сторон полигона, результат, указатель на смежные треугольники);

Ниже приведен пример создания и визуализации трехмерного объекта – полигона.

C++

// объявление переменной LPD3DXMESH polygon; // создание объекта полигон D3DXCreatePolygon( device, 0.5, 10, &polygon, NULL); // визуализация polygon->DrawSubset(0);

Pascal

// объявление переменной var polygon: ID3DXMesh; // создание объекта полигон D3DXCreatePolygon(device, 0.5, 10, polygon, nil); // визуализация polygon.DrawSubset(0);

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

Длина стороны = 0.5

Количество сторон = 10

Длина стороны = 2

Количество сторон = 3

Длина стороны = 0.1

Количество сторон = 36



Функция вывода параллелепипеда

D3DXCreateBox( ссылка на устройство вывода, ширина, высота, глубина, результат, указатель на смежные треугольники);

Ниже приведен пример создания и визуализации трехмерного объекта – полигона.


C++

// объявление переменной LPD3DXMESH box; // создание объекта D3DXCreateBox( device, 1.0f, 0.5f, 2.0f, &box, NULL); // визуализация box->DrawSubset(0);
Pascal

// объявление переменной var box: ID3DXMesh; // создание объекта D3DXCreateBox(device, 1, 0.5, 2, box, nil); // визуализация box.DrawSubset(0);
Примеры вывода параллелограмма с различными длинами сторон

ширина = 1

высота = 0.5

глубина = 2
ширина = 1

высота = 1

глубина = 1
ширина = 0.5

высота = 2

глубина = 1






Функция построения цилиндра

D3DXCreateCylinder( ссылка на устройство радиус первого основания радиус второго основания высота цилиндра количество разбиений "по радиусу" количество разбиений "по длине" результат указатель на смежные треугольники);



C++

LPD3DXMESH cylinder; D3DXCreateCylinder(device, 0.2f, 0.2f, 1, 16, 3, &cylinder, NULL);

cylinder->DrawSubset(0);
Pascal

var cylinder: ID3DXMesh; D3DXCreateCylinder(device, 0.2, 0.2, 1, 16, 3, cylinder, nil);

cylinder.DrawSubset(0);
Первое основание = 0.2

Второе основание = 0.2

Разбиений по радиусу = 16
Первое основание = 0.4

Второе основание = 0.2

Разбиений по радиусу = 16
Первое основание = 0.4

Второе основание = 0

Разбиений по радиусу = 6






Функция построения сферы:

D3DXCreateSphere( ссылка на устройство, радиус сферы, разбиений "по радиусу", // число апельсиновых долек разбиений "вдоль", // результат, указатель на смежные треугольники);
Разбиений по радиусу = 6, вдоль = 32Разбиений по радиусу = 32, вдоль = 6




C++

LPD3DXMESH sphere; D3DXCreateSphere(device, 1.0f, 16, 16, &sphere, NULL);

sphere->DrawSubset(0);
Pascal

var sphere: ID3DXMesh; D3DXCreateSphere(device, 1, 16, 16, sphere, nil);

sphere.DrawSubset(0);
Функция построения тора:

D3DXCreateTorus( ссылка на устройство, внутренний радиус тора, внешний радиус тора, количество разбиений в поперечном сечении, количество разбиений по кругу, результат, указатель на смежные треугольники);
Разбиений в сечение = 6

Разбиений по кругу = 32
Разбиений в сечение = 32

Разбиений по кругу = 6




<


table class="xml_table" cellpadding="2" cellspacing="1">C++

LPD3DXMESH torus; D3DXCreateTorus(device, 0.2f, 0.8f, 32, 6, &torus, NULL); torus->DrawSubset(0); Pascal

var torus: ID3DXMesh; D3DXCreateTorus(device, 0.2, 0.8, 32, 6, torus, nil);

torus.DrawSubset(0); Функция построения чайника:

D3DXCreateTeapot( ссылка на устройство, результат, указатель на смежные треугольники);

Это единственный примитив, для которого отсутствует возможность задать уровень детализации.



C++

LPD3DXMESH teapot; D3DXCreateTeapot(device, &teapot, NULL); teapot->DrawSubset(0);
Pascal

var teapot: ID3DXMesh; D3DXCreateTeapot(device, teapot, nil);

teapot.DrawSubset(0);
Ниже приведены примеры освещения трехмерного объекта точечным источником света с различными характеристиками.

light.Ambient = D3DXCOLOR(0.3f, 0,0,0);



light.Diffuse = D3DXCOLOR(0.5f, 0.0, 0,0); light.Ambient = D3DXCOLOR(0.2f, 0,0,0);


light.Diffuse = D3DXCOLOR(0.5, 0.0, 0,0); light.Ambient = D3DXCOLOR(0.2, 0,0,0); light.Specular = D3DXCOLOR(0.3,0,0.0,0);

Следует заметить, что зеркальное освещение требует больших вычислений, чем другие типы освещения, поэтому библиотека Direct3DM предоставляет возможность отключать его (по умолчанию оно выключено). Для включения зеркального освещения необходимо установить константу состояния D3DRS_SPECULARENABLE в значение "истина".

C++device->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
Pascaldevice.SetRenderState(D3DRS_SPECULARENABLE, 1);
Как мы уже говорили, библиотека Direct3D позволяет одновременно использовать (обсчитывать) в сцене до восьми источников света. Программно использование нескольких источников света в сцене накладывает на программиста дополнительные "обязанности" по созданию и заполнению полей структуры для каждого источника. Ниже приведен пример использования трех разноцветных точечных источников света в сцене, которые расположены на координатных осях системы координат.

C++

D3DMATERIAL9 material; D3DLIGHT9 light0, light1, light2;

ZeroMemory( &material, sizeof(D3DMATERIAL9) ); material.Diffuse=D3DXCOLOR(1.0f, 1.0f, 1.0f, 0.0f);

ZeroMemory( &light0, sizeof(D3DLIGHT9) ); light0.Type = D3DLIGHT_POINT; light0.Diffuse = D3DXCOLOR(0.5f, 0.0f, 0.0f, 0.0f); light0.Position = D3DXVECTOR3(4.0f, 0.0f, 0.0f); … ZeroMemory( &light1, sizeof(D3DLIGHT9) ); light1.Type = D3DLIGHT_POINT; light1.Diffuse = D3DXCOLOR(0.0f, 0.5f, 0.0f, 0.0f); light1.Position = D3DXVECTOR3(0.0f, 0.0f, -4.0f); … ZeroMemory( &light2, sizeof(D3DLIGHT9) ); light2.Type = D3DLIGHT_POINT; light2.Diffuse = D3DXCOLOR(0.0f, 0.0f, 0.5f, 0.0f); light2.Position = D3DXVECTOR3(-4.0f, 0.0f, 0.0f);

device->SetRenderState( D3DRS_LIGHTING, TRUE ); ... // процедура рендеринга device->SetLight( 0, &light0 ); device->LightEnable( 0, TRUE ); device->SetLight( 1, &light1 ); device->LightEnable( 1, TRUE ); device->SetLight( 2, &light2 ); device->LightEnable( 2, TRUE );
Pascal

var material: TD3DMaterial9; light0, light1, light2: TD3DLight9;

ZeroMemory(@material,SizeOf(TD3DMaterial9)); material.Diffuse:=D3DXColor(1,1,1,0);

light0._Type:=D3DLIGHT_POINT; light0.Diffuse:=D3DXColor(0.5, 0.0, 0, 0); light0.Position:=D3DXVector3(4,0,0); … light1._Type:=D3DLIGHT_POINT; light1.Diffuse:=D3DXColor(0.0, 0.5, 0, 0); light1.Position:=D3DXVector3(0,0,-4); … light2._Type:=D3DLIGHT_POINT; light2.Diffuse:=D3DXColor(0.0, 0.0, 0.5, 0); light2.Position:=D3DXVector3(-4,0,0); … device.SetRenderState(D3DRS_LIGHTING, 1);

// процедура рендеринга device.SetLight(0,light0); device.LightEnable(0,true); device.SetLight(1,light1); device.LightEnable(1,true); device.SetLight(2,light2); device.LightEnable(2,true);
<




Сложные ( содержащие десятки тысяч вершин) объекты, как правило, создаются в профессиональных трехмерных редакторах (3D Studio, Maya, LightWave, и т.п.). Библиотека Direct3D содержит средства для загрузки и визуализации моделей, содержащихся в x-файлах. Х-файл – файл, содержащий в себе данные о трехмерном объекте (координаты вершин, материалы, нормали, текстуры и анимацию). Вначале необходимо объявить нужные переменные.

C++LPD3DXMESH mesh;
Pascalvar mesh: ID3DXMesh;
Для загрузки трехмерного объекта (модели) из Х-файла предназначена функция

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

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

C++

D3DXLoadMeshFromX("ship.x", D3DXMESH_MANAGED, device, NULL, NULL, NULL, NULL, &mesh);
Pascal

D3DXLoadMeshFromX('ship.x', D3DXMESH_MANAGED, device, nil, nil, nil, nil, mesh);
Для визуализации трехмерной модели из Х-файла необходимо вызвать метод DrawSubset интерфейса ID3DXMesh, где в качестве параметра передается номер выводимой группы (подмножества) модели. Если модель не разбита на группы, то параметр метода равен нулю.

C++mesh->DrawSubset(0);
Pascalmesh.DrawSubset(0);
Для того чтобы трехмерная модель выглядела более реалистично, можно добавить в сцену источники света и определить материалы.




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