Графика DirectX в Delphi
Шрифт:
* формула, задающая закон эффекта (линейный или экспоненциальный); плотность дымки, указываемая для нелинейных законов; интервал, на протяжении которого эффект действует, используется для линейного закона; цвет тумана.
При линейном законе плотность дымки равномерно увеличивается по мере удаления от глаза наблюдателя. Дымка действует в пределах интервала от передней до задней плоскостей отсечения. Этот интервал можно сузить, задавая значение параметров D3DRS__FOGSТАRТ и D3DRS_FOGEND. Есть две схемы расчета тумана: пикселная и вершинная. Если задана первая схема, значения
Нелинейных законов два: оба опираются на экспоненциальную зависимость, но в одном из них используется экспонента квадрата. Аргументом экспоненты в обоих случаях является произведение расстояния и весового фактора, называемого плотностью. Этот параметр должен быть вещественным и не превышать 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;
//
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;
Теперь передняя сторона квадрата не будет отображаться, если он повернут к нам обратной стороной, и наоборот, задняя сторона воспроизводится только тогда, когда квадрат развернулся к нам обратной стороной.
Соприкасающиеся поверхности
Обращаю ваше внимание еще на одну проблему, с которой вы можете столкнуться. Наверняка в ваших построениях рано или поздно потребуется использовать соприкасающиеся поверхности, и здесь вы можете обнаружить, что на таких поверхностях появляется паразитный узор.