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

Вывод трехмерных объектов


В первую очередь при визуализации трехмерных объектов, необходимо изменить формат вершины и набор FVF флагов.

C++

struct VERTEX3D { FLOAT x, y, z; … }; VERTEX3D data[];

#define MY_FVF (D3DFVF_XYZ | …);

Pascal

type Vertex3D = packed record x, y, z: Single; … end;

const MY_FVF = D3DFVF_XYZ or …;

var data: array of Vertex3D;

Единственное отличие от двумерного случая будет заключаться в наличии операций с матрицами для преобразования объектов. Функции для визуализации трехмерных объектов будут такими же, какие мы использовали в двумерном случае: DrawPrimitive, DrawPrimitiveUP, DrawIndexedPrimitive, DrawIndexedPrimitiveUP. В качестве примера разберем построение, вращающего вокруг одной из координатных осей, цветного треугольника. Запишем шаги, которые мы должны проделать.

  1. Определение формата вершин треугольника и набор FVF флагов;
  2. Заполнение массива вершин данными;
  3. Установка видовой и проекционной матриц;
  4. Установка мировой матрицы (поворот вокруг оси) и вывод примитива.

Приведем программные строки для каждого шага алгоритма.

C++

struct VERTEX3D { FLOAT x, y, z; DWORD color; }; #define MY_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE); ... VERTEX3D points[3] = { { -1.0f,-1.0f, 0.0f, 0x00ff0000, }, { 0.0f, 1.0f, 0.0f, 0x0000ff00, }, { 1.0f,-1.0f, 0.0f, 0x000000ff, } } ... D3DXMATRIX matWorld, matView, matProj;

D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3 ( 0.0f, 0.0f,-5.0f ), &D3DXVECTOR3 ( 0.0f, 0.0f, 0.0f ), &D3DXVECTOR3 ( 0.0f, 1.0f, 0.0f ) ); device->SetTransform( D3DTS_VIEW, &matView );

D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f ); device->SetTransform( D3DTS_PROJECTION, &matProj ); ... D3DXMatrixRotationY( &matWorld, angle ); device->SetTransform( D3DTS_WORLD, &matWorld );

device->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );

Pascal

type Vertex3D = packed record x, y, z: Single; color: DWORD; end;

const MY_FVF = D3DFVF_XYZ or D3DFVF_DIFFUSE;

var points: array [0..2] of Vertex3D = ( (x: -1; y: -1; z: 0; color: $000000ff), (x: 0; y: 1; z: 0; color: $0000ff00), (x: 1; y: -1; z: 0; color: $00ff0000) );

matWorld, matView, matProj: TD3DMatrix; ...

D3DXMatrixLookAtLH(matView, D3DXVector3(0,0,-5), D3DXVector3(0,0,0), D3DXVector3(0,1,0)); device.SetTransform(D3DTS_VIEW, matView);

D3DXMatrixPerspectiveFovLH(matProj, PI/4, 1, 1, 100); device.SetTransform(D3DTS_PROJECTION, matProj); ... D3DXMatrixRotationY(matWorld, angle); device.SetTransform(D3DTS_WORLD, matWorld); device.DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

<
Ниже приведен пример нескольких кадров из анимации.


Библиотека Direct3D располагает механизмом отсечения граней. Идея заключается в том, что можно указать порядок обхода вершин треугольника (по часовой или против часовой стрелки) и отключить вывод тех граней, которые перечислены, например, по часовой стрелке. По умолчанию механизм отсечения граней отключен, т.е. воспроизводятся обе стороны примитива. Программно отключение "задних" сторон примитива реализуется через вывоз метода SetRenderState(D3DRS_CULLMODE, <значение>) интерфейса IDirect3DDevice9. В качестве второго параметра может выступать одна из трех констант: D3DCULL_NONE – механизм отбраковки граней выключен;
D3DCULL_CW – отбраковываются грани, вершины которых перечислены по часовой стрелке;
D3DCULL_CCW – отбраковываются грани, вершины которых перечислены против часовой стрелки.
Так, на представленном ниже рисунке грань (треугольник) задается перечислением своих вершин: v0, v1, v2 – по часовой стрелке; v0, v2, v1 – против часовой стрелки.

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