DirectX Графика в проектах Delphi

         

Точки



Примитив точка, соответствующий использованию константы D3DPT_POINTLIST в качестве первого аргумента метода DrawPrimitive, приводит к тому, что для каждой порции данных, считываемых из потока, на экране вывода ставится точка.
Изучим основательнее этот примитив на примере проекта каталога Ех07, где экран усеивается множеством точек (рис. 7.2).

Рис. 7.2. Пример использования множества вершин

Теперь нам требуется массив, хранящий данные о вершинах:

const
MAXPOINTS = 1000; // Количество точек
var
VPoints : Array [0..MAXPOINTS - 1] of TCOSTOMVERTEX; // Массив точек

Координаты точек берутся случайно, в пределах, обусловленных размерами клиентской области окна приложения:

Randomize; // Инициализируем генератор случайных чисел
for i := 0 to MAXPOINTS - 1 do // Цикл по точкам
with VPoints [i] do begin
X := random (300);
Y := random (300);
Z := 0.0;
RHW := 0.0;
end;

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

hRet := FD3DDevice.BeginScene; // Информируем устройство о готовности
if FAILED(hRet) then begin // к воспроизведению
Result := hRet;
Exit; end;
// Последний аргумент - количество используемых точек
hRet := FD3DDevice.DrawPrimitive(D3DPT_POINTLIST, 0, MAXPOINTS);
if FAILED(hRet) then begin
Result := hRet;
Exit;
end;
// Это действие теперь всегда будет завершать код воспроизведения
hRet := FD3DDevice.EndScene;
if FAILED(hRet) then begin
Result := hRet;
Exit;
end;

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

hRet := FD3DDevice.DrawPrimitive(D3DPT_POINTLIST, 0, random(MAXPOINTS));

Количество примитивов, считываемых из потока, стало теперь случайным. Посмотрите работу профаммы: одни точки мерцают, другие - нет. Данные, располагающиеся в конце потока, будут реже использоваться при воспроизведении, чем находящиеся ближе к его началу.
Чтобы мерцание получилось равномерным, надо выбирать случайную одну точку для воспроизведения. Например, чтобы в кадре сияло одновременно не более 200 точек, код можно скорректировать таким образом:


for i := 0 to 200 do begin
hRet := FD3DDevice.DrawPrimitive(D3DPT_POINTLIST,
random (MAXPOINTS), 1);
if FAILED(hRet) then begin
Result := hRet;
Exit;
end;
end;

Но все точки располагаются пока неподвижно, попробуем передвигать примитивы.
В проекте каталога Ех08 координаты точек генерируются при каждом обновлении кадра. Перед очередным вызовом метода DrawPrimitive происходит обращение к пользовательской функции, заполняющей буфер вершин новыми значениями. Обратите внимание, что код не загромождается действиями, выполненными при инициализации массива точек:

function TfrmDSD.GenPoints : HRESULT;
var
pVertices : PByte;
hRet : HRESULT; i : Integer;
begin
for i := 0 to MAXPOINTS - 1 do with VPoints [i] do begin
X := random (300);
Y := random (300); // Значения остальных полей не меняем
end;
hRet := FD3DVB.Lock(0, SizeOf(VPoints), pVertices, 0);
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
Move (VPoints, pVertices", SizeOf(VPoints));
Result := FD3DVB.Unlock;
end;

Нет необходимости снова выполнять действия по созданию буфера вершин и инициализации шейдера, лишь заполняем буфер вершин новыми значениями.
Это был пример на хаотическое перемещение точек, а в проекте каталога Ех09 по аналогичной схеме рисуется вращающаяся спираль (рис. 7.3).



Рис. 7.3. Вращающаяся спираль строится из отдельных точек

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

var
Angle : Single = 0.0;
function TfrmD3D.GenPoints : HRESULT;
var
pVertices : PByte;
hRet : HRESULT; i : Integer;
const
Step = 2 * Pi / MAXPOINTS;
begin
for i := 0 to MAXPOINTS - 1 do with VPoints [i] do begin
X := 150 + cos (Angle + Step * 5 * i) * i / 20;
Y := 150 + sin (Angle + Step * 5 * i) * i / 20;
end;
Angle := Angle + 0.1;
if Angle > 2 * Pi then Angle := Angle - 2 * Pi;
hRet := FD3DVB.Lock(0, SizeOf(VPoints), pVertices, 0);
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
Move (VPoints, pVertices^, SizeOf(VPoints));
Result := FD3DVB.Unlock;
end;




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