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

       

Альфа-составляющая текстуры



Формат текстуры D3DFMT_A8R8G8B8 позволяет для каждого пиксела образа заавать индивидуальное значение альфа-составляющей, чем можно воспольоваться для получения массы интересных эффектов. Так, проект каталога Ex12 решает задачу, сходную задаче предыдущего примера: курсор при своем вижении по поверхности окна оставляет след постепенно проступающего браза (рис. 8.9).

Рис. 8.9. Постепенно проступающий образ: пример использования альфа-составля ющей текстуры

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

PDWORD (DWORD(d3dlr.pBits) + У * dwDstPitch + X * 4)^ :=
D3DCOLOR_ARGB(0, R, G, В);

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

with FDSDDevice do begin
SetTexture(0, FD3Texture); // Устанавливаем текстуру
// Операции с цветом пикселов текстуры
SetTextureStageStatefO, D3DTSS__COLOROP, D3DTAJTEXTURE);
// Операции с альфа-компонентом пикселов текстуры
SetTextureStageStatefO, D3DTSS_ALPHAOP, D3DTA_TEXTURE);
// Разрешаем работу с альфа-составляющей
SetRenderState(D3DRS_ALPHABLENDENABLE, DWORD (True));
// Параметры альфа-смешения
SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
end;
// Квадрат, покрытый текстурой
hRet := FD3DDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
if FAILED(hRet) then begin
Result := hRet;
Exit;
end;
// Выключаем текстуру и альфа-смешение
with FDSDDevice do begin
SetTexture(0, nil) ;
SetRenderState(D3DRS_ALPHABLENDENABLE, DWORD (False));
end;

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


procedure TfrmD3D.FormMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
d3dlr : TD3DLOCKED_RECT;
dwDstPitch : DWORD;
i : Integer; wrkX, wrkY : DWORD;
begin
if Down then begin // Нажата ли кнопка мыши
FD3Texture.LockRect(0, d3dlr, nil, 0);
dwDstPitch := d3dlr.Pitch;
for i := 1 to 50 do begin //50 точек в районе курсора
repeat // Генерируем точку в пределах окна
wrkX := DWORD (X + random (7) - 3);
wrkY := DWORD (ClientHeight - Y + random (7) - 3);
until (wrkX < DWORD (ClientWidth)) and (wrkY < DWORD (ClientHeight))
and (wrkX > 0) and (wrkY > 0);
PDWORD (DWORD(d3dlr.pBits) + wrkY * dwDstPitch + wrkX * 4)^ :=
// Альфа-составляющую для точек задаем равной 255
PDWORD (DWORD(d3dlr.pBics) + wrkY * dwDstPitch + wrkX * 4)" +
SFF000000;
end;
FD3Texture.UnlockRect(0);
end;
end;

Несколько небольших замечаний:

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


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