Читать интересную книгу Графика DirectX в Delphi - Михаил Краснов

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 52 53 54 55 56 57 58 59 60 ... 69

Надеюсь, неспешная работа с этим примером позволит вам хорошо разобраться с матрицами, определяющими вид картинки.

Подготовка моделей

Конусы и цилиндры, сфера и правильные многогранники - все подобные геометрические фигуры легко описываются и могут украсить вашу программу. Пример - проект каталога Ех04, в котором рисуется икосаэдр (рис. 9.6).

Этот многогранник описан двадцатью независимыми треугольниками. Координаты вершин и нормали я предварительно вычислил и использую в программе конкретные значения.

Знаний, которые мы уже получили, достаточно, чтобы создать более-менее интересные построения. Пример - проект каталога Ех05, где рисуется простая модель человечка. Используются две геометрические формы: цилиндр и икосаэдр. С помощью клавиш перемещения курсора конечностями человечка можно управлять, заставляя его поднимать и опускать руки и ноги, но нельзя заставить поднять обе ноги одновременно (рис. 9.7).

Для построения ног применяются цилиндры единичной длины, руки строятся цилиндрами длиной 0.75 единиц. Движения конечностей осуществляются плавно:

const

INCR = 0.05; // Приращение для углов, задает темп вращения цилиндров

var

Down : BOOL = False; // Флаг, указывающий, нажата ли кнопка мыши

оХ : Integer; // Используются для навигации в пространстве

оУ : Integer;

Angle : Single = 0;

sHeight : Single = 0;

// Левая/правая стороны - с точки обзора зрителя

R_hand_up_angle, // Текущий угол поворота верхней части правой руки

R_hand_down_angle, // Текущий угол поворота нижней части правой руки

L_hand_up_angle, // Углы для частей левой руки

L_hand_down_angle,

R_foot_up_angle, // Углы для частей правой ноги

R_foot_down_angle,

L_foot_up_angle, // Углы поворотов левой ноги

L_foot_down_angle : Single;

R_hand_move, // Флаги перемещений конечностей

L_hand_move,

R_foot_move,

L_foot_move : BOOL;

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

procedure TfrmD3D.DrawScene;

var

matRotateX, matRotateZ : TDSDMatrix;

matScale, matTranslate : TD3DMatrix;

matWrk : TD3DMatrix; // Вспомогательная матрица текущей трансформации

begin

Timer; // Пересчет текущих значений углов поворота конечностей

// Икосаэдр головы

SetTranslateMatrix(matTranslate, 0.0, -3.0, 0.0);

// Масштабируем единичный многогранник

SetScaleMatrix (matScale, 0.5, 0.5, 0.5);

matWrk := MatrixMul(matScale, matTranslate);

with FDSDDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

SetMaterial(MaterialYellow); // Желтого цвета

DrawPrimitive(D3DPT_TRIANGLELIST, 0, 20);

end;

// Цилиндры левой ноги

SetTranslateMatrixfmatTranslate, -0.2, 0.0, 0.0);

SetRotateXMatrix(matRotateX, L_foot_up_angle);

// Запоминаем положение верхней части

matWrk := MatrixMul(matTranslate, matRotateX);

with FD3DDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

SetMaterial(MaterialBlue); // Ноги - синего цвета

// Цилиндр единичной длины

DrawPrimitive(D3DPT_TRIANGLESTRIP, 60, 98);

end;

// Перемещаемся к концу цилиндра единичной длины

SetTranslateMatrix(matTranslate, 0.0, 1.0, 0.0);

// Поворот нижней части конечности

SetRotateXMatrix(matRotateX, L_foot_down_angle);

// Трансформации осуществляются относительно предыдущего состояния

// системы координат

matWrk := MatrixMul(matWrk, MatrixMul(matTranslate, matRotateX));

with FD3DDevi do begin

SetTransform(D3DTS_WORLD, matWrk);

DrawPrimitive(D3DPT_TRIANGLESTRIP, 60, 98);

end;

// Правая нога

SetTranslateMatrixfmatTranslate, 0.2, 0.0, 0.0);

SetRotateXMatrix(matRotateX, R_foot_up_angle);

// Запоминаем текущее положение верхней части правой ноги

matWrk := MatrixMul(matTranslate, matRotateX);

with FDSDDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

DrawPrimitive(D3DPT_TRIANGLESTRIP, 60, 98);

end;

// Трансформации в новой системе координат

SetTranslateMatrix(matTranslate, 0.0, 1.0, 0.0);

SetRotateXMatrix(matRotateX, R_foot_down_angle);

// Поворот и сдвиг - относительно текущей трансформации

matWrk := MatrixMul(matWrk, MatrixMul(matTranslate, matRotateX));

with FD3DDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

DrawPrimitive(D3DPT_TRLANGLESTRIP, 60, 98);

end;

// Туловище

// Цилиндр с левой стороны туловища

SetTranslateMatrix(matTranslate, -0.2, 0.0, 0.0);

SetRotateZMatrix(matRotateZ, 5 * Pi / 6) ;

with FD3DDevice do begin

SetTransform(D3DTS_WORLD, MatrixMul(matTranslate, matRotateZ));

SetMaterial(MaterialGreen); // Текущий цвет - зеленый

DrawPrimitive(D3DPT_TRJANGLESTRIP, 60, 98);

end;

// Цилиндр правой части туловища

SetTranslateMatrix(matTranslate, 0.2, 0.0, 0.0);

SetRotateZMatrix(matRotateZ, -5 * Pi / 6);

FD3DDevice.SetTransform(D3DTS_WORLD,

MatrixMul(matTranslate, matRotateZ));

FD3DDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 60, 98);

// Цилиндр верхней части туловища

SetTranslateMatrix(matTranslate, -1.0, -1.0, 0.0);

SetScaleMatrix (matScale, 1.0, 2.0, 1.0); // Растягиваем цилиндр

SetRotateZMatrix(matRotateZ, Pi / 2);

FD3DDevice.SetTransform(D3DTS_WORLD, MatrixMul(matRotateZ,

MatrixMul(matTranslate, matScale)));

FD3DDevice.DrawPrimitive(D3DPT TRIANGLESTRIP, 60, 98);

// Цилиндр нижней части туловища

SetTranslateMatrix(matTranslate, 0.0, -0.25, 0.0);

SetScaleMatrix (matScale, 1.0, 0.5, 1.0); // Уменьшаем цилиндр

SetRotateZMatrix(matRotateZ, Pi / 2) ;

FD3DDevice.SetTransform(D3DTS_WORLD, MatrixMul(matRotateZ,

MatrixMul(matTranslate, matScale)));

FD3DDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 60, 98);

// Левая рука

// Верхняя часть

SetTranslateMatrix(matTranslate, -1.0, -1.0, 0.0);

SetRotateZMatrix(matRotateZ, R_hand_up_angle);

matWrk := MatrixMul(matTranslate, matRotateZ);

with FD3DDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

SetMaterial(MaterialRed); // Текущий цвет - красный

// Цилиндр длиной 0.75

DrawPrimitive(D3DPT_TRIANGLESTRIP, 160, 98);

end;

// Сдвигаемся к концу цилиндра

SetTranslateMatrix(matTranslate, 0.0, 0.75, 0.0);

SetRotateZMatrix(matRotateZ, R_hand_down_angle);

matWrk := MatrixMul(matWrk, MatrixMul(matTranslate, matRotateZ));

with FD3DDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

DrawPrimitive(D3DPT_TRIANGLESTRIP, 160, 98);

end;

// Правая рука

SetTranslateMatrix(matTranslate, 1.0, -1.0, 0.0);

SetRotateZMatrix(matRotateZ, L_hand_up_angle);

matWrk := MatrixMul(matTranslate, matRotateZ);

with FD3DDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

DrawPrimitive(D3DPT_TRIANGLESTRIP, 160, 98);

end;

SetTranslateMatrix(matTranslate, 0.0, 0.75, 0.0);

SetRotateZMatrix(matRotateZ, L_hand_down_angle);

matWrk := MatrixMul(matWrk, MatrixMul{matTranslate, matRotateZ));

with FDSDDevice do begin

SetTransform(D3DTS_WORLD, matWrk);

DrawPrimitive(D3DPT_TRIANGLESTRIP, 160, 98);

end;

end;

При нажатии клавиш управления курсором меняются значения флагов, и наблюдаем мы сцену зеркально.

procedure TfrmD3D.FormKeyDown(Sender: TObject; var Key: Word;

Shift: TShiftState);

begin

if Key = VKJ3SCAPE then Close else

// Клавиша "влево" - правая рука

if Key = VK_LEFT then R_hand_move := not R_hand_move else

// Клавиша "вправо" - левая рука

if Key = VK_RIGHT then L_hand_move := not L_hand_move else

// Клавиша "вверх" - правая нога

if Key = VK_UP then begin

// Двигается, если не поднята левая нога

if L_foot_up_angle < 1.0 then R_foot_move := not R_foot_move;

end else

// Клавиша "вниз" - левая нога

if Key = VK_DOWN then begin

// Двигается, если не поднята правая нога

if R_foot_up_angle < 1.0 then L_foot_move := not L_foot_move;

end;

end;

При установленных флагах значения углов поворотов увеличиваются на величину INCR:

procedure TfrmDSD.Timer;

begin

if R_hand_move then begin // Правая рука поднимается

if R_hand_up_angle < Pi / 2 then begin // He достигнут предел

R_hand_up_angle := R_hand_up_angle + INCR; // Верхняя часть руки

R_hand_down_angle := R_hand_down_angle - INCR; // Нижняя часть

end // Предел достигнут, движется только нижняя часть руки

else if (R_hand_up_angle >= Pi / 2) and (R_hand_down_angle < 0.0)

then R_hand_down_angle := R_hand_down_angle + INCR;

end else // Правая рука опускается или уже опущена

if R_hand_up_angle > 0.0 then begin

R_hand_up_angle := R_hand_up_angle - INCR; if R_hand_down_angle < 0.0

then R_hand_down_angle := R_hand_down_angle + INCR;

end;

if L_hand_move then begin // Левая рука поднимается

if L_hand_up_angle > -Pi / 2 then begin

L_hand_up_angle := L_hand_up_angle - INCR;

L_hand_down_angle := L__hand_down_angle + INCR;

end else if (L_hand_up_angle <= Pi / 2) and (L_hand_down_angle > 0.0)

then L_hand_down_angle := L_hand_down_angle - INCR;

end else if L__hand__up_angle < 0.0 then begin

L_hand_up_angle := L_hand_up_angle + INCR;

if L_hand_down_angle > 0.0

then L_hand_down_angle := L_hand_down_angle - INCR;

end;

if R_foot_move then begin // Правая нога поднимается

if R_foot_up_angle < Pi / 2 then begin

R_foot_up_angle := R_foot__up_angle + INCR;

R_foot_down_angle := R_foot_down_angle - INCR;

end else if (R_foot_up_angle >= Pi / 2) and (R_foot_down_angle < 0.0)

then R_foot_down_angle := R_foot_down_angle + INCR;

end else if R_foot_up_angle > 0.0 then begin

R_foot_up_angle := R_foot_up_angle - INCR; if R_foot_down_angle < 0.0

then R_foot_down_angle := R_foot_down_angle + INCR;

end;

if L_foot_move then begin // Движение левой ноги

if L_foot_up_angle < Pi / 2 then begin

L_foot_up_angle := L_foot_up_angle + INCR;

L_foot_down_angle := L_foot_down_angle - INCR;

end else

if (L_foot_up_angle >= Pi / 2) and (L_foot_down_angle < 0.0)

then L_foot_down_angle := L_foot_down_angle + INCR;

end else

if L_foot_up_angle > 0.0 then begin

L_foot_up_angle := L_foot_up_angle - INCR;

if L_foot_down_angle < 0.0

then L_foot_down_angle := L_foot_down_angle + INCR;

end;

end;

Из этого примера мы также можем вынести для себя механизм удобной навигации в пространстве. Матрица проекций задается один раз, при инициализации:

procedure TfrmD3D.FormCreate(Sender: TObject);

var

hRet : HRESULT;

matView, matProj : TDSDMatrix;

begin

hRet := InitD3D;

if Failed (hRet) then ErrorOut ('InitDSD', hRet);

hRet := InitVB;

if Failed (hRet) then ErrorOut ('InitVertex', hRet);

SetupLights;

MaterialRed := InitMaterial(1, 0, 0, 1);

MaterialBlue := InitMaterial(0, О, 1,1);

MaterialGreen := InitMaterial(О, 1, 0, 1) ;

MaterialYellow := InitMaterial(1, 1, 0, 1) ;

// Первоначальная установка видовой матрицы

SetViewMatrix(matView, D3DVector(2, 1, 5),

D3DVector(0, 0, 0), D3DVector(0, -1, 0));

FD3DDevice.SetTransform(D3DTS_VIEW, matView);

// Матрица проекций задается один раз

SetProjectionMatrix(matProj, 1, 1, 1, 20);

FD3DDevice.SetTransform(D3DTS_PROJECTION, matProj);

end;

Положение точки зрения и параметры матриц я подобрал с помощью пройденного нами примера с осями координат.

1 ... 52 53 54 55 56 57 58 59 60 ... 69
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Графика DirectX в Delphi - Михаил Краснов.
Книги, аналогичгные Графика DirectX в Delphi - Михаил Краснов

Оставить комментарий