Чтение онлайн

ЖАНРЫ

Графика DirectX в Delphi

Краснов Михаил

Шрифт:

for i := 1 to 10 do begin // 10 красных кругов

wrkAngle := wrkAngle + 0.04;

wrkRed := wrkRed + 25;

hRet := DrawRedCircle (wrkAngle, wrkRed);

if FAILED(hRet) then begin

Result := hRet;

Exit;

end;

end;

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

Работа

с переменным числом вершин

Мы уже хорошо освоились в построениях фигур с помощью Direct3D и в этом небольшом разделе попробуем развить наши навыки и узнать некоторые новые для нас вещи.

Как выяснилось из многочисленных предыдущих примеров, при использовании FVF-флага DSDFVF_XYZRHW в своих построениях мы опираемся на систему координат, ассоциированную с окном. Теперь нам предстоит постичь смысл еще одного флага: D3DFVF__XYZ. При его применении система координат экрана воспроизведения выглядит так: центру окна, независимо от его размеров, соответствует точка с координатами (0, 0), правому верхнему углу окна - (1, 1), левому нижнему углу - (-1, -1).

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

На примере проекта каталога Ех05 попробуем закрепить знания об этом флаге и попутно решим еще одну задачу: научимся работать с переменным числом вершин.

Самое простое решение задачи состоит, конечно, в том, чтобы задавать размер буфера вершин максимальным. Но такой прием приводит к неэффективному расходу памяти.

Во время работы программы на экране появляются узоры, образуемые отрезками, соединяющими равномерно расположенные точки на окружности. Число узлов меняется с течением времени случайно (рис. 8.4).

Текущее значение переменной numpoints хранит число узлов. В периодически вызываемой функции initve не используется массив вершин, а применяется единственная переменная - указатель на структуру TCustomVertex. В этой структуре, в отличие от предыдущих примеров, отсутствует поле color, а описание формата данных вершины сократилось до одной константы:

const

D3DFVF CUSTOMVERTEX = D3DFVF XYZ;

Поскольку размер буфера постоянно изменяется, при каждом обращении к этой функции повторяются все действия инициализации буфера вершин:

function TfrmD3D.InitVB : HRESULT;

const

Pi2 = 2 * Pi; // Для сокращения числа операций

var

Vertices : ^TCustomVertex; // Указатель на запись вершины

i, j, k : Byte;

hRet : HRESULT;

begin

numPoints := random (7) + 3; // Генерация количества узлов

k := 0; // Подсчет количества отрезков, образующих узор

for i := 1 to numPoints do

for j := i + 1 to numPoints do begin Inc(k);

end;

numbines := k; //

Используется в DrawPrimitive

// Создание буфера вершин нужного размера

hRet := FD3DDevice.CreateVertexBuffer(2 * k * SizeOf(TCustomVertex), 0,

D3DFVF__CUSTOMVERTEX, D3DPOOL_DEFAULT, FD3DVB) ;

if Failed(hRet) then begin

Result := hRet; Expend;

// Заполнение буфера

hRet := FD3DVB.Lock(0,2 * k * SizeOf(TCustomVertex), PByte(Vertices), 0);

if Failed(hRet) then begin

Result := hRet;

Exit;

end;

// Перебор точек узлов

for i := 1 to numPoints do

for j := i + 1 to numPoints do begin

// Начало отрезка, точка на окружности радиусом 0.5

Vertices.X := 0.5 * cos(Pi2 * i / numPoints);

Vertices.Y := 0.5 * sin(Pi2 * i / numPoints);

Vertices.Z := 0;

Inc(Vertices); // Сдвигаем указатель

// Конец отрезка

Vertices.X :=. 0.5 * cos(Pi2 * j / numPoints);

Vertices.Y := 0.5 * sin(Pi2 * j / numPoints);

Vertices.Z := 0; Inc(Vertices);

end;

hRet := FD3DVB.Unlock;

if Failed(hRet) then begin

Result := hRet;

Exit;

end;

// Заново устанавливаем поток

hRet := FDSDDevice.SetStreamSource(0, FD3DVB, SizeOf(TCUSTOMVERTEX));

if Failed (hRet) then begin

Result := hRet;

Exit;

end;

// Задаем вершинный шейдер

Result := FDSDDevice.SetVertexShader(D3DFVF_CUSTOMVERTEX);

end;

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

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

Теперь мы можем выяснить одну, очень важную для нас особенность использования флага D3DFVF_XYZ. Приведите код функции InitVB к следующему виду:

function TfrmDSD.InitVB : HRESULT;

var

Vertices : ^TCustomVertex;

hRet : HRESULT;

begin

hRet := FD3DDevice.CreateVertexBuffer(3 * SizeOf(TCustomVertex), 0,

D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT, FD3DVB);

if Failed(hRet) then begin

Result := hRet;

Exit;

end;

hRet := FD3DVB.Lock(0, 3 * SizeOf(TCustomVertex), PByte(Vertices), 0);

if Failed(hRet) then begin

Result := hRet;

Exit ;

end;

Vertices.X =0.0;

Vertices.Y = 0.0;

Vertices.Z = 0;

Inc(Vertices);

Vertices.X = 0.0;

Vertices.Y = 0.5;

Vertices.Z = 0;

Inc(Vertices) ;

Vertices.X =0.5;

Vertices.Y = 0.5;

Vertices.Z =0;

hRet := FD3DVB.Unlock;

if Failed(hRet) then begin

Result := hRet;

Exit;

end;

hRet := FD3DDevice.SetStreamSource(0, FD3DVB, SizeOf(TCUSTOMVERTEX));

if Failed (hRet) then begin

Поделиться с друзьями: