Кубик в нашем примере вращается вокруг двух осей одновременно:
SetRotateXMatrix(matRotateX, Angle);
SetRotateYMatrix(matRotateY, Angle);
FD3DDevice.SetTransform(D3DTS_WORLD, MatrixMul(matRotateX, matRotateY));
FD3DDevice.DrawPrimitive(D3DPT__TRIANGLELIST, 0, 12);
На рисунке куб получился крупнее, чем при работе приложения. Для того, чтобы увеличить изображение, можно просто "приблизить" глаз наблюдателя:
SetViewMatrixfmatView, D3DVector(0, 0, -2),
D3DVector(0, 0, 0), D3DVector(0, I, 0));
Есть и другой способ: действительно увеличить объект. Для этого в матрицу трансформаций надо добавить матрицу масштабирования, по главной диагонали которой стоят числа, отличные от единицы и равные масштабным множителям по трем осям отдельно. Попробуйте сейчас увеличить кубик в два раза:
procedure TfrmD3D.DrawScene;
var
matView, matProj : TD3DMatrix;
matRotateX, matRotateY : TD3DMatrix;
niatScale : TD3DMatrix; // Добавилась матрица масштабирования
begin
SetRotateXMatrix(matRotateX, Angle);
SetRotateYMatrix(matRotateY, Angle);
SetScaleMatrix(matScale, 2.0, 2.0, 2.0); // Увеличиваем в 2 раза
// Добавляем матрицу масштабирования
FD3DDevice.SetTransform(D3DTS_WORLD, MatrixMul(matScale,
MatrixMul(matRotateX, matRotateY)));
Обязательно это сделайте, чтобы увидеть, что куб действительно увеличился. Однако освещение его тоже изменилось. Связано это с тем, что векторы нормалей к вершинам вслед за масштабированием стали увеличенными, и требуется их нормализация. В таких случаях необходимо включить режим автоматической нормализации этих векторов:
SetRenderState(D3DRS NORMALIZENORMALS, DWORD (True));
Буфер глубины
Продолжим рассмотрение нашего примера с вращающимся кубом. В нем еще остались некоторые новые для нас вещи. Рисуемые примитивы накладываются друг на друга в том порядке, в котором они воспроизводятся: нарисованные позже лежат поверх созданных ранее. Это хорошо для двумерных построений, но при переходе в ЗD-пространство нам приходится беспокоиться о том, чтобы положения объектов передавались правильно: более удаленные от глаза наблюдателя объекты могут заслонять воспроизведенные позже, но располагающиеся ближе к камере. Графическая система предлагает решение в виде использования буфера глубины - вспомогательного экрана, предназначенного только для сортировки объектов, располагающихся в пространстве. При подключении этого буфера воспроизведение осуществляется дважды: первый раз в буфер записывается информация о значении расстояния от камеры до точки, второй раз в буфер кадра помещаются данные только о точках, действительно видимых и не заслоняемых другими точками.
Другое название буфера глубины - Z-буфер.
При инициализации Direct3D надо указать, что будет использоваться буфер глубины, и задать его формат. Обычно используется 16-битный формат:
with d3dpp do begin
Windowed := True;
SwapEffect := D3DSWAPEFFECT_DISCARD;
BackBufferFormat := dSddm.Format;
// Будет использоваться буфер глубины
EnableAutoDepthStencil := True;
AutoDepthStencilFormat := D3DFMT_D16; // 16-битный формат
end;
Размеры буфера глубины будут автоматически определяться системой при каждом изменении размеров окна.
При очередной перерисовке кадра теперь должен очищаться не только буфер кадра, но и подключенный буфер глубины. Предпоследний параметр метода clear объекта устройства - значение, которым заполняется буфер глубины. Этим значением должна быть единица, фон экрана бесконечно удален в пространстве:
FD3DDevice.Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,
$00FFFFFF, 1.0, 0) ;
Для разрешения работы с буфером глубины надо также задать положительный флаг для соответствующего режима:
SetRenderState(D3DRS_ZENABLE, D3DZBJTRUE);
Флагом для этого состояния может быть и обычная булева константа.
Сейчас нам необходимо перейти к следующему примеру, проекту каталога Ех03, после его запуска на экране появляется вращающийся чайник и стрелки осей координат (рис. 9.4).
Буфер вершин заполняется данными для трех трехмерных объектов: цилиндра, конуса и чайника:
function TfrmD3D.InitVB : HRESULT;
const
radius =0.1; // Радиус цилиндра
var
Vertices : ^TCustomVertex;
hRet : HRESULT;
theta : Single;
i : Integer;
t : TextFile; // Данные модели хранятся в текстовом файле
wX, wY, wZ : Single;
egin hRet := FD3DDevice.CreateVertexBuffer((100 + 51 * 2 + 6322 * 3) *
SizeOf(TCustomVertex), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, FD3DVB);
if Failed(hRet) then begin
Result := hRet;
Exit;
end;
hRet := FDSDDevice.SetStreamSource(0, FD3DVB, SizeOf(TCustomVertex));
if Failed(hRet) then begin
Result := hRet;
Exit;
end;
hRet := FD3DDevice.SetVertexShader(D3DFVF_CUSTOMVERTEX);
if Failed(hRet) then begin
Result := hRet;
Exit; end; hRet := FD3DVB.Lock(0, (100 + 51 * 2 + 6322 * 3)*
SizeOf(TCustomVertex), PByte(Vertices), 0);
if Failed(hRet) then begin
Result := hRet;
Exit;
end;
// 100 вершин цилиндра, по часовой стрелке
Читать дальше
Конец ознакомительного отрывка
Купить книгу