Жарков В.А. - Visual C++ 2005, DirectX 9.0c и Microsoft Agent в компьютерной графике, мультимедиа и играх (Листинги книги) - 2005
.pdf70 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
DesigningLine(D, H, -B, C, H, -A);
DesigningLine(C, H, -A, R, H, 0);
DesigningLine(R, H, 0, 0, 1, 0);
DesigningLine(C, H, A, 0, 1, 0);
DesigningLine(D, H, B, 0, 1, 0);
DesigningLine(D, H, -B, 0, 1, 0);
DesigningLine(C, H, -A, 0, 1, 0); DesigningLine(-R, -H, 0, -C, -H, A); DesigningLine(-C, -H, A, -D, -H, B); DesigningLine(-D, -H, B, -D, -H, -B); DesigningLine(-D, -H, -B, -C, -H, -A); DesigningLine(-C, -H, -A, -R, -H, 0); DesigningLine(-R, -H, 0, 0, -1, 0); DesigningLine(-C, -H, A, 0, -1, 0); DesigningLine(-D, -H, B, 0, -1, 0); DesigningLine(-D, -H, -B, 0, -1, 0); DesigningLine(-C, -H, -A, 0, -1, 0); DesigningLine(R, H, 0, -D, -H, B); DesigningLine(R, H, 0, -D, -H, -B); DesigningLine(C, H, A, -D, -H, B); DesigningLine(C, H, A, -C, -H, A); DesigningLine(D, H, B, -C, -H, A); DesigningLine(D, H, B, -R, -H, 0); DesigningLine(D, H, -B, -R, -H, 0); DesigningLine(D, H, -B, -C, -H, -A); DesigningLine(C, H, -A, -C, -H, -A); DesigningLine(C, H, -A, -D, -H, -B); Icosahedron_last = NumLines;
}
//Объявляем структуру Line и массивы этой структуры: public: value struct Line
{
//Объявляем массивы для соединения точек (points): public: array<float>^ fr_points;
public: array<float>^ to_points;
//Массивы для соединения преобразованных точек: //(transformed (tr) points):
public: array<float>^ fr_tr_points; public: array<float>^ to_tr_points; //Создаем и инициализируем массивы, т.е.
//всем элементам каждого массива присваиваем 0: public: void Initialize()
{
fr_points = gcnew array<float>(5); to_points = gcnew array<float>(5); fr_tr_points = gcnew array<float>(5); to_tr_points = gcnew array<float>(5);
Глава 24. Изображение и управление трехмерными объектами |
71 |
}
};
//Объявляем массив Lines структуры Line, оператором gcnew //создаем массив из 100 элементов и инициализируем его, //т.е всем элементам массива присваиваем значение nullptr: public: static array<Line>^ Lines = gcnew array<Line>(100);
//Объявляем и инициализируем переменную для индекса массива: public: int static NumLines = 0;
//Проектируем линию между точками (x1,y1,z1),(x2,y2,z2): public: void DesigningLine(float x1, float y1, float z1, float x2, float y2, float z2)
{
NumLines = NumLines + 1; //Инициализируем и рассчитываем массив: Lines[NumLines].Initialize(); Lines[NumLines].fr_points[1] = x1; Lines[NumLines].fr_points[2] = y1; Lines[NumLines].fr_points[3] = z1; Lines[NumLines].fr_points[4] = 1; Lines[NumLines].to_points[1] = x2; Lines[NumLines].to_points[2] = y2; Lines[NumLines].to_points[3] = z2; Lines[NumLines].to_points[4] = 1;
}
//Применяем матрицу переноса (translation matrix) //ко всем линиям, используя MatrixApplyFull.
//Преобразование не имеет 0, 0, 0, 1 в последнем столбце: public: void TransformAllDataFull(array<float,2>^ M)
{
TransformDataFull( M, 1, NumLines);
}
//Применяем матрицу переноса (translation matrix)
//ко всем выделенным линиям, используя MatrixApplyFull. //Преобразование не имеет 0, 0, 0, 1 в последнем столбце: public: void TransformDataFull(array<float,2>^ M,
int line1, int line2)
{
for (int i = line1; i <= line2; i++)
{
MatrixApplyFull( Lines[i].fr_points, M, Lines[i].fr_tr_points);
MatrixApplyFull( Lines[i].to_points, M, Lines[i].to_tr_points);
}
}
72 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
//Рисуем выделенные преобразованные линии: public: void DrawSolid(Bitmap^ bmp,
int first_line, int last_line, Color color, bool clear)
{
float x1, y1, x2, y2; Graphics^ g; Pen^ pen;
//Задаем толщину линии рисования, например, 2 //(цвет линии мы задали в методе Designing): pen = gcnew Pen(color, 2);
//Связываем объект g с изображением bmp: g = Graphics::FromImage(bmp);
if (clear) g->Clear(System::Drawing::Color::Black); //Рисуем линии:
for (int i = first_line; i <= last_line; i++)
{
x1 = Lines[i].fr_tr_points[1];
y1 = Lines[i].fr_tr_points[2];
x2 = Lines[i].to_tr_points[1];
y2 = Lines[i].to_tr_points[2];
//Масштабируем, нормализуем и рисуем многогранник: g->DrawLine(pen,
(x1 * bmp->Width / 4) + bmp->Width / 2.0F, bmp->Height / 2.0F - (y1 * bmp->Height / 4), (x2 * bmp->Width / 4) + bmp->Width / 2.0F, bmp->Height / 2.0F - (y2 * bmp->Height / 4));
}
//Высвобождаем ресурсы от объектов g и pen: g->Dispose(); pen->Dispose();
}
//Строим единичную матрицу:
public: void MatrixIdentity(array<float,2>^ M)
{
for (int i = 1; i <= 4; i++)
{
for (int j = 1; j <= 4; j++)
{
if (i == j) M[i, j] = 1; else M[i, j] = 0;
}
}
}
//Строим матрицу преобразования (3-D transformation matrix) //для перспективной проекции вдоль оси z на плоскость x,y //с центром объекта (фокусом) в начале координат
//и c центром проецирования на расстоянии (0, 0, Distance): public: void MatrixPerspectiveXZ(array<float,2>^ M,
float Distance)
Глава 24. Изображение и управление трехмерными объектами |
73 |
{
MatrixIdentity(M);
if (Distance != 0) M[3, 4] = -1 / Distance;
}
//Строим матрицу преобразования (3-D transformation matrix) //для проецирования с координатами:
//центр проецирования (cx, cy, cz), фокус (fx, fy, fx), //вектор от объекта до экрана UP <ux, yx, uz>,
//тип проецирования (type_of_projection): //PerspectiveProjection или ParallelProjection: public: void MatrixTransformation(array<float,2>^ M, int type_of_projection,
float Cx, float Cy, float Cz, float Fx, float Fy, float Fz, float ux, float uy, float uz)
{
array<float,2>^ M1 = gcnew array<float,2>(5, 5); array<float,2>^ M2 = gcnew array<float,2>(5, 5); array<float,2>^ M3 = gcnew array<float,2>(5, 5); array<float,2>^ M4 = gcnew array<float,2>(5, 5); array<float,2>^ M5 = gcnew array<float,2>(5, 5); array<float,2>^ M12 = gcnew array<float,2>(5, 5); array<float,2>^ M34 = gcnew array<float,2>(5, 5); array<float,2>^ M1234 = gcnew array<float,2>(5, 5); float sin1 = 0, cos1 = 0; float sin2 = 0, cos2 = 0; float sin3, cos3; float A, B, C; float d1, d2, d3; array<float>^ up1 = gcnew array<float>(5); array<float>^ up2 = gcnew array<float>(5); //Переносим фокус (центр объекта) в начало координат: MatrixTranslate( M1, -Fx, -Fy, -Fz);
A = Cx - Fx; B = Cy - Fy; C = Cz - Fz;
d1 = (float)Math::Sqrt(A * A + C * C); if (d1 != 0)
{
sin1 = -A / d1; cos1 = C / d1;
}
d2 = (float)Math::Sqrt(A * A + B * B + C * C); if (d2 != 0)
{
sin2 = B / d2; cos2 = d1 / d2;
}
//Вращаем объект вокруг оси y, чтобы разместить //центр проекции в y-z плоскости: MatrixIdentity(M2);
//Если d1 = 0, тогда центр проекции
//уже находится на оси y и в y-z плоскости: if (d1 != 0)
74 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
{
M2[1, 1] = cos1; M2[1, 3] = -sin1; M2[3, 1] = sin1; M2[3, 3] = cos1;
}
//Вращаем вокруг оси x,
//чтобы разместить центр проекции на оси z: MatrixIdentity(M3);
//Если d2 = 0, то центр проекции //находится в начале координат. //Это делает проекцию невозможной: if (d2 != 0)
{
M3[2, 2] = cos2; M3[2, 3] = sin2; M3[3, 2] = -sin2; M3[3, 3] = cos2;
}
//Вращаем вектор UP:
up1[1] = ux; up1[2] = uy; up1[3] = uz; up1[4] = 1;
MatrixApply( up1, M2, up2); MatrixApply( up2, M3, up1);
//Вращаем вокруг оси z, чтобы разместить //вектор UP в y-z плоскости:
d3 = (float)Math::Sqrt(up1[1] * up1[1] + up1[2] * up1[2]);
MatrixIdentity( M4);
//Если d3 = 0, то вектор UP равен нулю: if (d3 != 0)
{
sin3 = up1[1] / d3; cos3 = up1[2] / d3; M4[1, 1] = cos3; M4[1, 2] = sin3; M4[2, 1] = -sin3; M4[2, 2] = cos3;
}
//Проецируем:
if (type_of_projection == PerspectiveProjection) MatrixPerspectiveXZ( M5, d2);
else
MatrixIdentity( M5); if (d2 != 0)
MatrixPerspectiveXZ( M5, d2); else
MatrixIdentity( M5); //Комбинируем преобразования: m3MatMultiply( M12, M1, M2); m3MatMultiply( M34, M3, M4); m3MatMultiply( M1234, M12, M34);
if (type_of_projection == PerspectiveProjection) m3MatMultiplyFull( M, M1234, M5);
Глава 24. Изображение и управление трехмерными объектами |
75 |
else
m3MatMultiply( M, M1234, M5);
}
//Строим матрицу преобразования (3-D transformation matrix) //для перспективного проецирования (perspective projection): //центр проецирования (r, phi, theta),
//фокус (fx, fy, fx),
//вектор от объекта до экрана UP <ux, yx, uz>, //тип проецирования (type_of_projection): //PerspectiveProjection:
public: void Projection( array<float,2>^ M, int type_of_projection, float R,
float phi, float theta, float Fx, float Fy, float Fz, float ux, float uy, float uz)
{
float Cx, Cy, Cz, r2;
//Переходим к прямоугольным координатам: Cy = R * (float)Math::Sin(phi);
r2 = R * (float)Math::Cos(phi); Cx = r2 * (float)Math::Cos(theta); Cz = r2 * (float)Math::Sin(theta);
MatrixTransformation( M, type_of_projection, Cx, Cy, Cz, Fx, Fy, Fz, ux, uy, uz); // M
}
//Строим матрицу преобразования, чтобы получить //отражение напротив плоскости, проходящей
//через (p1, p2, p3) с вектором нормали <n1, n2, n3>:
public: void m3Reflect( array<float,2>^ M, float p1, float p2, float p3,
float n1, float n2, float n3)
{
array<float,2>^ T =
gcnew array<float,2>(5, 5);//Перенос. array<float,2>^ R1 =
gcnew array<float,2>(5, 5); //Вращение 1. array<float,2>^ r2 =
gcnew array<float,2>(5, 5); //Вращение 2. array<float,2>^ S =
gcnew array<float,2>(5, 5); //Отражение. array<float,2>^ R2i =
gcnew array<float,2>(5, 5); //Не вращать 2. array<float,2>^ R1i =
gcnew array<float,2>(5, 5); //Не вращать 1. array<float,2>^ Ti =
gcnew array<float,2>(5, 5); //Не переносить.
76 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
float D, L;
array<float,2>^ M12 = gcnew array<float,2>(5, 5); array<float,2>^ M34 = gcnew array<float,2>(5, 5); array<float,2>^ M1234 = gcnew array<float,2>(5, 5); array<float,2>^ M56 = gcnew array<float,2>(5, 5); array<float,2>^ M567 = gcnew array<float,2>(5, 5); //Переносим плоскость к началу координат: MatrixTranslate( T, -p1, -p2, -p3); MatrixTranslate( Ti, p1, p2, p3);
//Вращаем вокруг оси z,
//пока нормаль не будет в y-z плоскости: MatrixIdentity( R1);
D = (float)Math::Sqrt(n1 * n1 + n2 * n2); R1[1, 1] = n2 / D; R1[1, 2] = n1 / D; R1[2, 1] = -R1[1, 2]; R1[2, 2] = R1[1, 1]; MatrixIdentity( R1i);
R1i[1, 1] = R1[1, 1]; R1i[1, 2] = -R1[1, 2]; R1i[2, 1] = -R1[2, 1]; R1i[2, 2] = R1[2, 2];
//Вращаем вокруг оси x, когда нормаль будет по оси y: MatrixIdentity( r2);
L = (float)Math::Sqrt(n1 * n1 + n2 * n2 + n3 * n3); r2[2, 2] = D / L; r2[2, 3] = -n3 / L;
r2[3, 2] = -r2[2, 3]; r2[3, 3] = r2[2, 2]; MatrixIdentity( R2i);
R2i[2, 2] = r2[2, 2]; R2i[2, 3] = -r2[2, 3]; R2i[3, 2] = -r2[3, 2]; R2i[3, 3] = r2[3, 3];
//Рисуем отражение объекта перпендикулярно x-z плоскости: MatrixIdentity( S); S[2, 2] = -1;
//Комбинируем матрицы: m3MatMultiply( M12, T, R1); m3MatMultiply( M34, r2, S); m3MatMultiply( M1234, M12, M34); m3MatMultiply( M56, R2i, R1i); m3MatMultiply( M567, M56, Ti); m3MatMultiply( M, M1234, M567);
}
//Строим матрицу преобразования для поворота на угол theta //вокруг линии, проходящей через (p1, p2, p3)
//в направлении <d1, d2, d3>.
//Угол theta откладывается против часовой стрелки, //если мы смотрим вниз в направлении, //противоположном направлению линии:
public: void m3LineRotate( array<float,2>^ M, float p1, float p2, float p3,
float d1, float d2, float d3, float theta)
{
array<float,2>^ T =
Глава 24. Изображение и управление трехмерными объектами |
77 |
|||
gcnew array<float,2>(5, 5);//Перенос. |
|
|||
array<float,2>^ R1 = |
|
|
|
|
gcnew array<float,2>(5, 5); //Вращение 1. |
|
|||
array<float,2>^ r2 = |
|
|
|
|
gcnew array<float,2>(5, 5); //Вращение 2. |
|
|||
array<float,2>^ Rot3 = |
|
|
|
|
gcnew array<float,2>(5, 5); //Отражение. |
|
|||
array<float,2>^ R2i = |
|
|
|
|
gcnew array<float,2>(5, 5); //Не вращать 2. |
|
|||
array<float,2>^ R1i = |
|
|
|
|
gcnew array<float,2>(5, 5); //Не вращать 1. |
|
|||
array<float,2>^ Ti = |
|
|
|
|
gcnew array<float,2>(5, 5); //Не переносить. |
|
|||
float D, L; |
|
|
|
|
array<float,2>^ M12 = gcnew array<float,2>(5, 5); |
|
|||
array<float,2>^ M34 = gcnew array<float,2>(5, 5); |
|
|||
array<float,2>^ M1234 = gcnew array<float,2>(5, 5); |
|
|||
array<float,2>^ M56 = gcnew array<float,2>(5, 5); |
|
|||
array<float,2>^ M567 = gcnew array<float,2>(5, 5); |
|
|||
//Переносим плоскость к началу координат: |
|
|||
MatrixTranslate( T, -p1, -p2, -p3); |
|
|||
MatrixTranslate( Ti, p1, p2, p3); |
|
|||
//Вращаем вокруг оси z, |
|
|
|
|
//пока линия не окажется в y-z плоскости: |
|
|||
MatrixIdentity( R1); |
|
|
|
|
D = (float)Math::Sqrt(d1 * d1 + d2 * d2); |
|
|||
R1[1, 1] = d2 / D; R1[1, 2] = d1 / D; |
|
|||
R1[2, 1] = -R1[1, 2]; R1[2, 2] = R1[1, 1]; |
|
|||
MatrixIdentity( R1i); |
|
|
|
|
R1i[1, 1] = R1[1, 1]; R1i[1, 2] = -R1[1, 2]; |
|
|||
R1i[2, 1] = -R1[2, 1]; R1i[2, 2] = R1[2, 2]; |
|
|||
//Вращаем вокруг оси x, когда линия будет по оси y: |
|
|||
MatrixIdentity( r2); |
|
|
|
|
L = (float)Math::Sqrt(d1 * d1 + d2 * d2 + d3 * d3); |
|
|||
r2[2, 2] = D / L; r2[2, 3] = -d3 / L; |
|
|||
r2[3, 2] = -r2[2, 3]; r2[3, 3] = r2[2, 2]; |
|
|||
MatrixIdentity( R2i); |
|
|
|
|
R2i[2, 2] = r2[2, 2]; R2i[2, 3] = -r2[2, 3]; |
|
|||
R2i[3, 2] = -r2[3, 2]; R2i[3, 3] = r2[3, 3]; |
|
|||
//Вращаем вокруг линии (оси y): |
|
|||
MatrixYRotate( Rot3, theta); |
|
|||
//Комбинируем матрицы: |
R1); |
|
||
m3MatMultiply( M12, |
T, |
|
||
m3MatMultiply( M34, |
r2, |
Rot3); |
|
|
m3MatMultiply( M1234, |
M12, |
M34); |
|
|
m3MatMultiply( M56, |
R2i, |
|
R1i); |
|
m3MatMultiply( M567, |
M56, |
Ti); |
|
78 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
m3MatMultiply( M, M1234, M567);
}
//Строим матрицу преобразования (3-D transformation matrix) //для переноса на Tx, Ty, Tz:
public: void MatrixTranslate( array<float,2>^ M, float Tx, float Ty, float Tz)
{
MatrixIdentity( M);
M[4, 1] = Tx; M[4, 2] = Ty; M[4, 3] = Tz;
}
//Строим матрицу преобразования (3-D transformation matrix) //для поворота вокруг оси y (угол - в радианах):
public: void MatrixYRotate( array<float,2>^ M, float theta)
{
MatrixIdentity( M);
M[1, 1] = (float)Math::Cos(theta); M[3, 3] = M[1, 1];
M[3, 1] = (float)Math::Sin(theta); M[1, 3] = -M[3, 1];
}
//Применяем матрицу преобразования к точке, //где матрица не может иметь 0, 0, 0, 1 //в последнем столбце. Нормализуем только
//x и y компоненты результата, чтобы сохранить z информацию: public: void MatrixApplyFull(array<float>^ V,
array<float,2>^ M, array<float>^ Result)
{
int i, j; float value = 0; for (i = 1; i <= 4; i++)
{
value = 0;
for (j = 1; j <= 4; j++)
{
value = value + V[j] * M[j, i];
}
Result[i] = value;
}
//Повторно нормализуем точку (value = Result[4]): if (value != 0)
{
Result[1] = Result[1] / value; Result[2] = Result[2] / value;
}
else
{
//Не преобразовываем z - составляющую.
//Если значение z больше, чем от центра проекции,
Глава 24. Изображение и управление трехмерными объектами |
79 |
//эта точка будет удалена: Result[3] = Single::MaxValue;
}
Result[4] = 1;
}
//Применяем матрицу преобразования к точке: public: void MatrixApply(array<float>^ V, array<float,2>^ M, array<float>^ Result)
{
Result[1] = V[1] * |
M[1, 1] + V[2] * M[2, 1] + |
V[3] * M[3, 1] |
+ M[4, 1]; |
Result[2] = V[1] * |
M[1, 2] + V[2] * M[2, 2] + |
V[3] * M[3, 2] |
+ M[4, 2]; |
Result[3] = V[1] * |
M[1, 3] + V[2] * M[2, 3] + |
V[3] * M[3, 3] + M[4, 3]; Result[4] = 1;
}
//Умножаем две матрицы. Матрицы //не могут содержать 0, 0, 0, 1 в последних столбцах:
public: void m3MatMultiplyFull(array<float,2>^ Result, array<float,2>^ A, array<float,2>^ B)
{
int i, j, k; float value; for (i = 1; i <= 4; i++)
{
for (j = 1; j <= 4; j++)
{
value = 0;
for (k = 1; k <= 4; k++)
value = value + A[i, k] * B[k, j]; Result[i, j] = value;
}
}
}
//Умножаем две матрицы:
public: void m3MatMultiply(array<float,2>^ Result, array<float,2>^ A, array<float,2>^ B)
{
Result[1, 1] = A[1, 1] * B[1, 1] + A[1, 2] * B[2, 1] + A[1, 3] * B[3, 1];
Result[1, 2] = A[1, 1] * B[1, 2] + A[1, 2] * B[2, 2] + A[1, 3] * B[3, 2];
Result[1, 3] = A[1, 1] * B[1, 3] + A[1, 2] * B[2, 3] + A[1, 3] * B[3, 3];
Result[1, 4] = 0;
Result[2, 1] = A[2, 1] * B[1, 1] + A[2, 2] * B[2, 1]