Графика 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; // Степень насыщенности красного