Голосование

Ожидаете ли Вы увольнения в связи с кризисом?

Меня никогда не уволят
Боюсь что все-таки могут
Меня собираются увольнять
Меня уже уволили
Я сам собираюсь уйти
Я никогда и не работал



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

 

Лента 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-2016 "DS"

E-mail: Отправить письмо


ВКонтакте   Twitter   Facebook