Графика DirectX в Delphi
Шрифт:
Нелинейных законов два: оба опираются на экспоненциальную зависимость, но в одном из них используется экспонента квадрата. Аргументом экспоненты в обоих случаях является произведение расстояния и весового фактора, называемого плотностью. Этот параметр должен быть вещественным и не превышать 1.
Проект каталога Ех05 поможет вам глубже постичь все вышесказанное. Тестовая композиция воспроизводится на панели, рядом с которой располагаются элементы, позволяющие менять текущие параметры тумана .Для возможности динамической смены параметров их значения хранятся в переменных:
var
FogDensity : Single = 1.0; //
FogStart : Single =0.4; // Расстояние, с которого туман действует
FogEnd : Single =1.0; // Граничное расстояние действия тумана
FogColor : DWORD = $00FFFFFF; // Цвет тумана, первоначально - белый
FOGTABLEMODE : DWORD = D3DFOG_LINEAR; // Закон тумана
with FD3DDevice do begin
// Включаем режим использования дымки
SetRenderState(D3DRS_FOGENABLE, DWORD (True));
// Используем пикселную схему расчета тумана
SetRenderState(D3DRS_FOGTABLEMODE, FOGTABLEMODE);
// Устанавливаем текущие параметры тумана
SetRenderState(D3DRS_FOGCOLOR, FogColor);
SetRenderState(D3DRS_FOGDENSITY, PDWORD (@FogDensity)л);
SetRenderState(D3DRS_FOGSTART, PDWORD (@FogStart)л);
SetRenderState(D3DRS_FOGEND, PDWORD (@FogEnd)");
end;
При изменении пользователем состояний интерфейсных элементов меняются значения соответствующих переменных:
procedure TfrmD3D.tbStartChange(Sender: TObject); // Ползунок "Fog Start''
begin
FogStart := tbStart.Position / 10;
end;
procedure TfrmD3D.tbEndChange{Sender: TObject); // Ползунок "Fog End"
begin
FogEnd := tbEnd.Position / 10;
end;
procedure TfrmDSD.tbDensityChange(Sender: TObject); // Ползунок "Density"
begin
FogDensity := tbDensity.Position / 10;
end;
// Ползунки, связанные с цветовыми весами тумана procedure TfrmD3D.tbRedChange(Sender: TObject);
begin
FogColor := tbBlue.Position + (tbGreen.Position shl 8) +
(tbRed.Position shl (4 * 4));
end;
// Закон тумана
procedure TfrraD3D.cmbxFOGTABLEMODEChange(Sender: TObject);
begin
case cmbxFOGTABLEMODE.Itemlndex of
0 : FOGTABLEMODE := D3DFOG_NONE;
1 : FOGTABLEMODE := D3DFOG EXP;
2 : FOGTABLEMODE := D3DFOG_EXP2;
3 : FOGTABLEMODE := D3DFOG_LINEAR;
end;
end;
Эффект дымки часто служит для усиления передачи глубины пространства, как в проекте каталога Ех06, где рисуется вращающийся додекаэдр .При каркасном режиме зритель часто теряется в пространстве, гадая, как линии располагаются в пространстве, и включение режима тумана значительно улучшит восприятие таких картинок.
Двусторонние поверхности
Я обращал ваше внимание на то, что Direct3D умеет окрашивать примитивы только с одной стороны. В этом небольшом разделе, на примере проекта каталога Ех07 мы разберем принципы построения двусторонних поверхностей. Работа примера очень
простая: на экране вращается квадрат, с одной стороны окрашенный в синий цвет, с другой - в красный. Цвета разные только для наглядности, чтобы мы могли различать стороны площадки. Используется два материала, но вы можете получать таким же способом примитивы, выглядящие одинаково независимо от точки обзора.Метод очень прост: примитивы фигуры описываются дважды, с одинаковыми координатами, но противоположным направлением нормалей. В моем примере первые четыре вершины описывают связанные треугольники, образующие квадрат. Нормаль к вершинам задается из расчета, что описывается передняя сторона квадрата. Затем буфер наполняется четверкой вершин, с противоположным направлением нормали. Считаем, что это соответствует задней стороне квадрата. В обоих случаях вершины перечисляются по часовой стрелке.
При воспроизведении выводим переднюю сторону квадрата, отсекая примитивы, вершины которых перечисляются в поле зрения против часовой стрелки. Затем выводим заднюю сторону квадрата, меняя правило отсечения на противоположное: with FD3DDevice do begin
SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
SetMaterial(MaterialRed);
DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
SetMaterial(MaterialBlue);
DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
end;
Теперь передняя сторона квадрата не будет отображаться, если он повернут к нам обратной стороной, и наоборот, задняя сторона воспроизводится только тогда, когда квадрат развернулся к нам обратной стороной.
Соприкасающиеся поверхности
Обращаю ваше внимание еще на одну проблему, с которой вы можете столкнуться. Наверняка в ваших построениях рано или поздно потребуется использовать соприкасающиеся поверхности, и здесь вы можете обнаружить, что на таких поверхностях появляется паразитный узор.
Посмотрим на данный эффект, запустив проект из каталога Ех08, где рисуются две частично перекрывающиеся разноцветные площадки. В местах их соприкосновения возникает картинка, которую мы не рисовали (рис. 10.6).
Связано появление таких узоров с использованием буфера глубины. При его заполнении одинаковыми значениями из-за погрешностей некоторые участки примитивов выводятся перепутанными. Проявляется эффект только после смены матрицы трансформаций, как в этом примере:
procedure TfrmD3D.DrawScene;
var
matRotateY, matTranslate : TD3DMatrix;
begin
// Сдвиг и поворот первого квадрата
SetTranslateMatrix (matTranslate, -0.5, -0.5, 0);
SetRotateYMatrix(matRotateY, Angle);
with FD3DDevice do begin
SetTransform(D3DTS WORLD, MatrixMul(matRotateY, matTranslate);;
SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
SetMaterial(MaterialRed);
DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // Сдвиг второго квадрата