Голосование

Какую версию Delphi Вы используете?

Delphi 4 и ниже
Delphi 5
Delphi 7
Delphi 2005
Delphi 2006
Delphi 2007
Delphi 2009
Delphi 2010



Посмотреть результаты
Другие опросы ...

 

Лента RSS, новости сайта Новости сайта
Лента RSS, новости форума Новости форума
  Bookmark and Share

Архив исходников

   
  Базы данных
  Графика & Мультимедиа
  Сети & Интернет
  Система
  Разное
   

Кнопки, Ссылки и Баннеры ...

 


Automatic translation


English German French Italian Spanish
Portuguese Greece Japan Chinese Korean


Ссылки и Баннеры


скрыть

 

Delphi Sources

Delphi Sources

СТАТЬИ

 

. : Организация камеры в 3D играх : .

 

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

   Итак, что такое камера в 3D игре? Это виртуальное "око" игрока, то, посредством чего он воспринимает игру визуально. В понятие "камера" входят: угол обзора и положение которое задается радиус вектором и 3 углами относительно осей координат.

 Один из самых простых методов выглядит так:
 

 procedure TCamera.SetRender;
 begin
  gluLookAt(e.X, e.Y, e.Z, c.X, c.Y, c.Z, Up.X, Up.Y, Up.Z);
 end;


   В процедуру gluLookAt передается всего 3 радиус-вектора:
      e – точка в которую обращена камера
      c – положение камеры в пространстве
      Up – указывает направление "вверх" для камеры.
   По-поводу первых двух надеюсь вопросов нет, но вот с вычислением третьего придется изрядно попотеть…

   Однако, зачем что-то вычислять, если это можно доверить графическому API?
 

 procedure TCamera.SetRender;
 begin
  glLoadIdentity;
  glRotatef(Angle.Z, 0, 0, 1);
  glRotatef(Angle.X, 1, 0, 0);
  glRotatef(Angle.Y, 0, 1, 0);
  glTranslatef(-Pos.X, -Pos.Y, -Pos.Z);
 end;


 где
  Angle – вектор описывающий углы поворота относительно каждой из осей координат (в градусах);
  Pos – положение камеры в пространстве, также задающееся радиус-вектором.

   Данный метод бесспорно и прост и удобен, но такие операции как glRotate и glTranslate производят умножение видовой матрицы на другую матрицу. Это конечно же не критично для современных компьютеров, но все же вполне оптимизируемо. Чем мы и займемся…

   Для того чтобы что-либо оптимизировать мы должны понять принцип работы всех трех операций.
   Как известно, перед выводом геометрии на дисплей над ней производится несколько операций, а именно – умножение на матрицу вида и матрицу проекции.
   Нам же достаточно работы с матрицей вида (MODELVIEW). Сама же матрица вида представляется 16 вещественными числами, т.е. матрица имеет размерность 4х4.

   Итак, разберем все операции из предыдущего примера по отдельности:
  glLoadIdentity – преобразует текущую (видовую, проекции, текстуры) матрицу в единичную
 

 1  0  0  0
 0  1  0  0
 0  0  1  0
 0  0  0  1


  glRotatef
– домножает текущую матрицу вида на матрицу поворота относительно одной из осей координат.
   Имея 3 оси координат, соответственно можно вычислить всего 3 матрицы поворота:

Относительно оси OX:
 

 1  0  0  0
 0  c  s  0
 0 –s  c  0
 0  0  0  1


Относительно оси OY:
 

 c  0 -s  0
 0  1  0  0
 s  0  c  0
 0  0  0  1


Относительно оси OZ:

 

 c  s  0  0
-s  c  0  0
 0  0  1  0
 0  0  0  1


 где s и c – соответственно синусы и косинусы угла поворота.

  glTranslatef – производит домножение матрицы вида на матрицу сдвига:
 

 1  0  0  0
 0  1  0  0
 0  0  1  0
 x  y  z  1


 где x, y, z – приращение к соответствующим координатам векторов в новой системе координат.

   Итак, с сутью операций разобрались, теперь можно приступить к оптимизации, которая будет заключаться в ручном вычислении матрицы вида!
   Для этого нам понадобятся 3 угла и позиция камеры.
   Нам необходимо перемножить 3 матрицы поворота, и порядок их перемножения которых имеет большое значение.
   В итоге, перемножение матриц [Z]*[X]*[Y] будет выглядеть так:
 

 [ E  F  0 ]   [ 1  0  0 ]   [ C  0 -D ]   [ CE+BDF AF BCF-ED ]
 [-F  E  0 ] X [ 0  A  B ] X [ 0  1  0 ] = [ BDE-CF AE DF+BCE ]
 [ 0  0  1 ]   [ 0 -B  A ]   [ D  0  C ]   [     AD -B     AC ]


 где
 

A = cos(Angle.X);
B = sin(Angle.X);
C = sin(Angle.Y);
D = cos(Angle.Y);
E = cos(Angle.Z);
F = sin(Angle.Z);


   Заметьте, что C и D определены "не верно", т.к. мы попутно приводим матрицу к некоему базису. Это связано с направлением оси Z в OpenGL.

   Теперь необходимо рассчитать матрицу вида, которая выгладит так:

 

 x.x    x.y    x.z   -dot(x, Pos)
 y.x    y.y    y.z   -dot(y, Pos)
 z.x    z.y    z.z   -dot(z, Pos)
   0      0      0             1


 где x, y, z – вектора построенные на соответствующих компонентах матрицы:
 

 x = (CE+BDF, AF, BCF-ED)
 y = (BDE-CF, AE, DF+BCE)
 z = (    AD, -B,     AC)


   Pos – положение камеры в пространстве.
   Операция dot осуществляет скалярное произведение векторов.

   И сам код осуществляющий расчет:

 

 procedure TCamera.SetRender;
 var
  A, B, C, D, E, F : single;
  cx, cy, cz       : TVector;
 begin
  with Angle do
   begin
   A := cos(X);
   B := sin(X);
   C := sin(Y);
   D := cos(Y);
   E := cos(Z);
   F := sin(Z);
   end;
  cx := Vector(C*E+B*D*F, A*F, B*C*F-E*D);
  cy := Vector(B*D*E-C*F, A*E, D*F+B*C*E);
  cz := Vector(A*D,        -B,       A*C);
  // заполнение матрицы
  m[0]:=cx.X;  m[4]:=cx.Y;  m[8] :=cx.Z;  m[12]:=-V_Dot(cx, Pos);
  m[1]:=cy.X;  m[5]:=cy.Y;  m[9] :=cy.Z;  m[13]:=-V_Dot(cy, Pos);
  m[2]:=cz.X;  m[6]:=cz.Y;  m[10]:=cz.Z;  m[14]:=-V_Dot(cz, Pos);
  m[3]:=0;     m[7]:=0;     m[11]:=0;     m[15]:=1;
  // установка матрицы проекции
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(FOV, Width/Height, 0.1, 100);
  glMatrixMode(GL_MODELVIEW);
  // установка матрицы вида
  glLoadMatrixf(@m);
 end;


   Здесь матрица описывается в виде одномерного массива из 16 элементов типа single.
 

 m: array [0..15] of single;

   Углы (Angle) задаются в радианах.
   FOV – угол обзора камеры, который рекомендуется ставить равным 90;
   Width и Height - ширина и высота поля вывода соответственно;
   Vector – функция создания переменной типа TVector по трем значениям (x, y, z);
   V_Dot – скалярное умножение векторов (x1*x2 + y1*y2 + z1*z2).

   Сама процедура выглядит устрашающе по сравнению со вторым методом, но работает значительно шустрее. Вызов ее рекомендуется производить перед началом рендеринга карты и объектов на ней, чтобы изменения матрицы вида отразились на их выводе.

 

Дата: 11.01.2006, Автор: XProger.






Назад

   

 
















































































































 

© 2004-2017 "DS"

Отправить письмо / Реклама


ВКонтакте   Facebook   Twitter