Опубликован: 08.07.2007 | Доступ: свободный | Студентов: 1431 / 183 | Оценка: 4.43 / 4.02 | Длительность: 13:47:00
Специальности: Программист
Лекция 2:

Двумерная графика с использованием Direct3D

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >

Вывод простейших примитивов

Построение любой сцены в Direct3D, будь это обычная плоская кривая, например, график функции одной переменной, или сложная трехмерная композиция, происходит с помощью простейших геометрических примитивов, таких как точка, отрезок прямой и треугольник. Элементарным строительным материалом для перечисленных примитивов является вершина. Именно набором вершин задается тот или иной примитив. Чтобы использовать вершины при построении сцены необходимо определить их тип. Для хранения вершин отведем область памяти, представляющую собой обычный массив определенного типа. Вначале необходимо описать, что из себя будет представлять вершина – задать определенный формат. Программно этот шаг реализуется через структуры следующим образом:

C++
struct MYVERTEX1
{
    FLOAT x, y, z, rhw;
    DWORD color;
};
MYVERTEX1 data1[100];

struct MYVERTEX2
{
    FLOAT x, y, z;
    FLOAT n1, n2, n3;
};
MYVERTEX2 data2[100];
Pascal
MyVertex1 = packed record
    x, y, z, rhw: Single;
    color: DWORD;
end;

MyVertex2 = packed record
    x, y, z: Single;
    n1, n2, n3: Single;
end;

var 
      data1: array [0..99] of MyVertex1;
      data2: array [0..99] of MyVertex2;

Тем самым данные о вершинах будут храниться в массиве, и иметь строго определенный формат (тип). В процессе визуализации сцены необходимо указать графической библиотеке, что собой представляет одна вершина примитива. Это реализуется с помощью механизма флагов, называемого FVF ( Flexible Vertex Format – гибкий формат вершин). Существует порядка двух десятков флагов FVF для определения формата вершины. Самые распространенные и наиболее используемые флаги FVF для определения формата вершины представлены в следующей таблице:

D3DFVF_DIFFUSE используется цветовая компонента вершины
D3DFVF_NORMAL вершина содержит нормали
D3DFVF_TEX1 задает текстурные координаты вершины
D3DFVF_PSIZE определяет размер частицы
D3DFVF_XYZ вершина содержит три координаты
D3DFVF_XYZRHW преобразованный формат вершин

Комбинация конкретных флагов дает возможность сообщить системе, с каким форматом (типом) вершин она имеет дело в данный момент времени. Так, например,

(D3DFVF_XYZ OR D3DFVF_NORMAL)вершина содержит нормали и координаты, (D3DFVF_XYZRHW OR D3DFVF_DIFFUSE) - цветная преобразованная вершина, где OR – операция логического "или". Установка формата вершин осуществляется с помощью вызова метода SetFVF интерфейса IDirect3DDevice9. Программно это реализуется так:

C++
#define MY_FVF (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
…
device->SetFVF(MY_FVF);
Pascal
const MY_FVF = D3DFVF_XYZRHW or D3DFVF_DIFFUSE;
…
device.SetFVF(MY_FVF);

Следует особо остановиться на флаге D3DFVF_XYZRHW. Этот флаг позволяет описывать вершины, определенные на плоскости. Он служит для графической системы индикатором того, что построение сцены происходит на плоскости в координатах окна (формы) вывода. При этом формат вершины должен задаваться четверкой чисел x,y,z,w, две последних из которых, как правило, не используются, однако должны присутствовать при описании вершины.

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

  1. Описать структуру, в которой будут храниться координаты точек;
  2. Объявить массив нужной размерности (в нашем случае на 100 элементов) и заполнить его данными (в нашем случае случайными координатами).
  3. Вызвать метод для вывода этого массива на экран.

Первые два шага нам реализовать уже не составляет особого труда. Третий же шаг может быть реализован с помощью вызова метода DrawPrimitiveUP интерфейса IDirect3DDevice9. Прототип данного метода выглядит так:

DrawPrimitiveUP(
	  Тип выводимого примитива,
	  Количество примитивов,
	  Массив данных,
	  Размер "шага в байтах" от одной вершины до другой
)

Первый параметр указывает на тип выводимого примитива и задается одной из следующих констант: D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP, D3DPT_TRIANGLEFAN. Второй аргумент задает количество выводимых примитивов. Третий параметр является указателем на область в памяти, где располагаются данные о вершинах (в нашем случае это заполненный массив). И последний параметр задает, сколько байтов отводится для хранения одной вершины.

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

C++
struct MYVERTEX
{
    FLOAT x, y, z, rhw;
}data[100];

#define MY_FVF (D3DFVF_XYZRHW);

// заполнение массива data "случайными" точками …

// процедура вывода сцены
device->SetFVF(MY_FVF);
device->DrawPrimitiveUP( D3DPT_POINTLIST, 100, data, 
 sizeof(MYVERTEX) );
Pascal
type
    MyVertex = packed record
        x, y, z, rhw: Single;
    end;

const
      MY_FVF = D3DFVF_XYZRHW;

var 
      data: array [0..99] of MyVertex;

// заполнение массива data "случайными" точками …

// процедура вывода сцены
device.SetFVF(MY_FVF);
device.DrawPrimitiveUP( D3DPT_POINTLIST, 100, data, 
 SizeOf(MyVertex) );

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

C++
VOID Render()
{
device->BeginScene();
device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0),
 1.0f, 0);
device->SetFVF(…);
device->DrawPrimitiveUP(…);
device->EndScene();
device->Present( NULL, NULL, NULL, NULL );
}
Pascal
procedure Render;
begin
  device.BeginScene;
  device.Clear(0,nil,D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0,0);
  device.SetFVF(…);
  device.DrawPrimitiveUP(…);
  device.EndScene;
  device.Present(nil, nil, 0, nil);
end;
< Лекция 1 || Лекция 2: 123456 || Лекция 3 >