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

ЖАНРЫ

Графика DirectX в Delphi

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

Шрифт:

Max_Ring_Radius = 100.0; // Максимальный радиус пятна var

VCircle : Array [0..Level + 1] of TCUSTOMVERTEX; // Вершины круга

First_Drip, New_Drip : Integer; // Счетчики пятен

Drips : Array [0..Max_Drips - 1] of TDrip; // Массив пятен

При каждом нажатии кнопки мыши создается новое пятно. Координатами его центра выступают текущие координаты курсора:

procedure Create_Drip(const inX, inY : Integer; const R, G, В : Byte);

begin

// Создание нового пятна

Drips [New_Drip] := TDrip.Create;

with Drips[New_Drip] do begin

Ring_Color.R := R;

Ring_Color.G := G;

Ring_Color.B := B;

Ring_Radius := 0;

PosX := inX;

PosY := inY;

end;

//

Увеличение счетчиков

New_Drip := (New_Drip + 1) mod Max_Drips;

// Достигнут предел по количеству пятен на экране

if New_Drip = First_Drip

then First_Drip := (First_Drip + 1) mod Max_Drips;

end;

procedure TfrmD3D.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Create_Drip(X,Y,random(lSO)+105,random(150)+105, random(150)+105);

end;

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

Для рисования каждого пятна вызывается функция Drawcircle, круг рисуется группой связанных треугольников:

function TfrmD3D.DrawCircle (const inX, inY, inRadius : Integer;

const Ring_Color : TRGB) : HRESULT;

const

Step = 2 * Pi / Level;

var

pVertices : PByte;

hRet : HRESULT; i : Integer;

begin

// Первая точка - центр круга

with VCircle [0] do begin

X := inX;

Y := inY;

// Точка центра совершенно непрозрачна

Color := D3DCOLOR_ARGB(255, Ring_Color.R, Ring_Color.G, Ring_Color.B);

end;

// Точки края круга абсолютно прозрачны

for i := 1 to Level + 1 do

with VCircle [i] do begin

X := VCircle [0].X + cos (i * Step) * inRadius;

Y := VCircle [0].Y + sin (i * Step) * inRadius;

Color := D3DCOLOR_ARGB(0, Ring_Color.R, Ring_Color.G, Ring_Color.B);

end;

hRet := FD3DVB.Lock(0, SizeOf(VCircle), pVertices, 0) ;

if Failed (hRet) then begin

Result := hRet;

Exit;

end;

Move (VCircle, pVerticesA, SizeOf(VCircle));

hRet := FD3DVB.Unlock;

if Failed (hRet) then begin

Result := hRet;

Exit ;

end;

Result := FD3DDevice.DrawPrimitive(D3DPTJTRIANGLEFAN, 0, Level);

end;

При перерисовке кадра отображается круг для каждого существующего пятна:

i := First_Drip;

// Цикл по всем присутствующим на экране пятнам

while i <> New_Drip do begin

//

Каждое пятно увеличивается в размерах

Drips [ i ]. Ring_Radius := Drips [i] .Ring_Radius + 1;

DrawCircle (Drips [i] . PosX,

Drips [i] .PosY,

Drips [i] .Ring_Radius,

Drips [i] .Ring_Color) ;

// Пятно достигло максимального размера, поэтому исчезает с экрана

if Drips [i] .Ring_Radius > Max_Ring_Radius

then First_Drip := (First_Drip + 1) mod Max_Drips;

i := (i+1) mod Max_Drips;

end;

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

Размытие при движении

Манипулированием альфа-смешением можно легко получить эффект размытия при движении, когда быстро движущиеся объекты оставляют за собой след. Обычно такой эффект называется motion blur. Для получения эффекта в местах предыдущего положения объекта рисуют его полупрозрачную копию. Более простой способ создания эффекта - манипулирование цветовой интенсивностью.

Оба способа используются в проекте каталога Ех04, где на экране быстро вращаются два круга: желтый оставляет полупрозрачный след, а за красным тянется постепенно угасающий след (рис. 8.3).

Рисование каждого круга сводится к выводу ряда близко расположенных примитивов:

wrkGreen := 5;

for i := 1 to 10 do begin // 10 зеленых треугольников фона

wrkGreen := wrkGreen + 25;

hRet := DrawTriangle (ScreenWidth - (i + 1) * (ScreenWidth div 11),

ScreenWidth div 6, wrkGreen);

if FAILED(hRet) then begin

Result := hRet;

Exit;

end;

end;

wrkAngle := Angle;

wrkAlpha := 5; // Круги рисуются, начиная с самого прозрачного

with FDSDDevice do begin

SetRenderState(D3DRS__ALPHABLENDENABLE, DWORD(True));

SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);

SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

end;

for i := 1 to 10 do begin // 10 желтых кругов различной

wrkAngle := wrkAngle +0.04; // прозрачности

wrkAlpha := wrkAlpha + 25;

hRet := DrawYellowCircle (wrkAngle, wrkAlpha);

if FAILED(hRet) then begin

Result := hRet;

Exit;

end;

end;

FDSDDevice.SetRenderState(D3DRS_ALPHABLENDENABLE, DWORD(False));

wrkAngle := Angle + Pi;

wrkRed := 5; // Степень насыщенности красного

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