Графика DirectX в Delphi
Шрифт:
FD3DDevice.DrawPrimiti.ve(D3DPTJTRIANGLELIST, 0, 1); // Квадрат вращается по оси Y в 2 раза быстрее треугольника SetRotateYMatrix(matRotate, 2 * Angle); // Квадрат сдвигается на единицу вправо
SetTranslateMatrix(matTranslate, 1.0, 0.0, 0.0); // Матрица трансформаций для квадрата
FD3DDevice.SetTransform(D3DTS_WORLD,
MatrixMul(matTranslate, matRotate)); // Вывод квадрата
FD3DDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 3, 2); // Задаем видовую матрицу
SetViewMatrix(matView, D3DVector(0, 0, -5),
D3DVector(0, 0, 0), D3DVector(0, 1, 0)); //
FD3DDevice.SetTransform(D3DTS_VIEW, matView); // Задаем матрицу проекций
SetProjectionMatrix(matProj, I, 1, 1, 10); // Устанавливаем матрицу проекций
FD3DDevice.SetTransform(D3DTS_PROJECTION, matProj);
end;
Тип TD3DMatrix, массив 4x4 вещественных чисел, определен в модуле DirectxGraphics, а все функции операций с матрицами - в модуле DXGUtils. Эти функции возвращают величину типа HRESULT, значение которой мы, для простоты, анализировать не будем.
Функция D3DVector этого же модуля возвращает сформированный по трем аргументам вектор, тройку вещественных чисел, величину типа TD3DVector.
Функция SetRotateXMatrix первым аргументом получает переменную, в которую помещается результат, матрицу поворота вокруг оси X. Второй аргумент - угол, в радианах, на который осуществляется поворот. Функция SetTranslateMatrix первым аргументом получает переменную, в которую помещается заполненная матрица сдвига. Одновременно можно сдвинуть по нескольким осям.
Метод setTransform объекта устройства позволяет установить матрицу трансформаций. Первый аргумент - константа, определяющая, для какой матрицы устанавливается трансформация. Второй аргумент - собственно матрица трансформаций. Здесь мы передаем результирующую матрицу, полученную умножением матрицы поворота и матрицы сдвига, но не обязательно, чтобы в трансформации участвовало несколько матриц. Функция MatrixMul позволяет умножить две матрицы, передаваемые в качестве параметров.
Напоминаю, что порядок перечисления этих матриц очень важен. В данном случае разноцветный треугольник поворачивается вокруг оси X, затем сдвигается на единицу влево, по этой же оси.
Квадрат в этом примере вначале сдвигается вправо, затем поворачивается вокруг оси Y (собственной оси, а не мировой). Измените порядок перемножения матриц, чтобы убедиться, что результат будет отличаться от предыдущего.
Функция setviewMatrix подготавливает видовую матрицу. Параметры функции следующие: матрица, в которую помещается результат, вектор, определяющий точку, где располагается голова наблюдателя, опорная точка, определяющая середину видимой области, и вектор, задающий направление взгляда.
Функция setProjectionMatrix предназначена для удобного определения матрицы проекции. Второй аргумент функции задает угол обзора камеры по оси Y, третий аргумент - отношение, определяющее угол обзора по оси X, последние два аргумента - расстояния от глаза наблюдателя до ближней и дальней плоскостей отсечения.
Подозреваю, что последние две функции вызовут много вопросов, поэтому чуть позже мы подробно разберем их смысл.
Реалистичные изображения
Для получения реалистичных изображений необходимо выполнить три условия:
* при описании примитивов задать нормали; определить свойство материала; включить источник света.
Нормали помогают системе рассчитать освещенность примитива при различном его положении относительно источника света. В самом простом использовании нормаль представляет собой вектор, перпендикулярный воспроизводимому треугольнику. Этот вектор задается для каждой вершины, образующей примитив, и из требований оптимизации должен быть нормализован, т. е. иметь единичную длину.
Формат вершин теперь помимо пространственных координат обязан включать вектор нормали (тройку вещественных чисел), а FVF-флаг должен дополниться константой D3DFVF_NORMAL. ЭТО первое новшество в модуле нашего следующего примера, проекта каталога Ех02, где рисуется красивый желтый кубик (рис. 9.3).
Итак, запись описания вершины дополнилась тремя полями:
type
TCUSTOMVERTEX = packed record
X, Y, Z : Single;
nX, nY, nZ : Single; // Вектор нормали end;
const
D3DEVF_CUSTOMVERTEX = D3DFVF_XYZ or D3DFVF_NORMAL;
Буфер содержит 36 вершин, предназначенных для построения куба. Они образуют 12 независимых треугольников, по 2 соприкасающихся треугольника на каждую сторону куба. Все треугольники описываются по часовой стрелке, чтобы при воспроизведении мы могли, для экономии времени, отключить воспроизведение примитивов, перечисляемых в поле зрения против часовой стрелки. То есть стороны куба, повернутые к нам задней стороной, воспроизводить не будем, это обычный прием, применяемый к замкнутым трехмерным фигурам. Нормали для всех вершин, относящихся к одной стороне, задаются одинаковыми, исходя из того, какая сторона куба описывается. Так выглядит описание первого треугольника:
Vertices.X := -0.5;
Vertices.Y := -0.5;
Vertices.Z := -0.5;
Vertices.nX := -1.0;
Inc(Vertices);
При инициализации графической системы вызывается процедура, задающая свойства материала и включающая источник света:
procedure TfrmD3D.SetupLights;
var
Material : TD3DMaterial8;
Light : TD3DLight8;
begin
// Инициализация материала, желтый цвет
Material := InitMaterial(1, 1, 0, 0) ;
// Устанавливаем материал в объекте устройства