Elite Games - Свобода среди звезд!

Уроки для программистов - Камера и спрайт

Глава 5. Камера и спрайт

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

type
JLCamera=class(JLSceneObj) объявляем потомком класса JLSceneObj
v1,v2,v3,v4:TDotVector3; просто объявите, зачем скажу позже.
Fov:integer; угол обзора

constructor Create; override;
destructor Destroy; override;

procedure Bind;

procedure Render; override;
procedure Update; override;
procedure LoadFromFile(var f:file); override;
procedure SaveToFile(var f:file); override;

procedure Assign(a:JLSceneObj); override;
end;


Эта процедура делает данную камеру активной. Для этого нужно завести глобальные переменные, хранящие имя активной камеры (у меня это JL_ACTIVE_CAM) и еще текущий угол обзора (JL_SCR_FOV). JLResize-вызов gluPerspective, который устанавливает угол обзора.

procedure JLCamera.Bind;
begin
JL_ACTIVE_CAM:=IdName;
JL_SCR_FOV:=Fov;
JLResize;
end;



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

procedure JLCamera.Render;
begin
glPushMatrix;
Trans.DoTransform;
glPointSize(10);
glBegin(GL_POINTS);
glVertex3d(0,0,0);
glEnd;
glPopMatrix;
if WithChild then RenderChildren;
end;


Теперь я расскажу зачем нужны v1,v2,v3,v4. Дело в том, что есть такое понятие как спрайт. Спрайт (он же биллборд) – прямоугольник всегда направленный на камеру. Создается впечатление объемности. Спрайтами делают много эффектов, начиная со свечения из дюз корабля, заканчивая системами частиц.

Итак, как же повернуть спрайт к камере?

Спрайт – это четырехугольник, значит, нам нужно узнать 4 координаты. Допустим, у нас есть положение спрайта в пространстве. Значит, нам нужно к этому положению прибавить вектора для получения 4 вершин. Вот v1,v2,v3,v4 – это и есть эти вектора. Для всех спрайтов эти вектора одинаковые, они изменяются только в зависимости от камеры, значит, поместим их в неё.

Как и где высчитать эти вектора?

Будем считать их по Update.


procedure JLCamera.Update;
var modl:tdotMatrix16;
VR,VU:TDotVector3;
begin
это DEBUG команда
if Trans=nil then raise Exception.Create('Trans = nil at <'+IdName+'>');

glGetFloatv( GL_MODELVIEW_MATRIX, @ modl );

VR:=dotVector3(modl[0], modl[4], modl[8]);
VU:=dotVector3(modl[1], modl[5], modl[9]);

V1:=dotVector3(-VR.X-VU.X,-VR.Y-VU.Y,-VR.Z-VU.Z);
V2:=dotVector3(VR.X-VU.X,VR.Y-VU.Y,VR.Z-VU.Z);
V3:=dotVector3(VR.X+VU.X,VR.Y+VU.Y,VR.Z+VU.Z);
V4:=dotVector3(-VR.X+VU.X,-VR.Y+VU.Y,-VR.Z+VU.Z);
end;


glGetFloatv( GL_MODELVIEW_MATRIX, @ modl );
этой командой мы берем матрицу трансформации в переменную modl. Кстати, modl является не стандартным типом математической библиотеки dot.

type
TDotMatrix16 = array [0..15] of Single;

Почему именно так? Стандартный формат dot матрицы – 4х4, а нужно 1х16-это формат OpenGL.

Потом идут расчеты этих четырех векторов.


Вариантом оптимизации является пересчитывать эти вектора только в случае поворота камеры и не пересчитывать вообще, если в сцене нет спрайтов.


Теперь обозначим класс спрайта.


type
JLSprite=class(JLSceneObj)
Color:TDotVector4; цвет
TexID:string; имя текстуры
size:single; размер спрайта

constructor Create; override;
destructor Destroy; override;

procedure Render; override;
procedure Update; override;
procedure LoadFromFile(var f:file); override;
procedure SaveToFile(var f:file); override;

procedure Assign(a:JLSceneObj); override;
end;


Текстуры.. Пока о них не будем говорить, это будет в следующей главе.


В принципе, все процедуры понятны, кроме Render.


procedure JLSprite.Render(WithChild:boolean);
var v1,v2,v3,v4:TDotVector3;
const
Tex1:TDotVector2=(x:0;y:0);
Tex2:TDotVector2=(x:1;y:0);
Tex3:TDotVector2=(x:1;y:1);
Tex4:TDotVector2=(x:0;y:1);
begin
v1:=dotVecAdd3(JLGetActiveCamera.V1,trans.pos);
v2:=dotVecAdd3(JLGetActiveCamera.V2,trans.pos);
v3:=dotVecAdd3(JLGetActiveCamera.V3,trans.pos);
v4:=dotVecAdd3(JLGetActiveCamera.V4,trans.pos);

if TexID<>'' then
textures.GetObjByName(TexID).Bind;

glColor3fv(@ color);


glBegin(GL_QUADS);
glTexCoord2fv(@ tex1);
glVertex3fv(@ v1);
glTexCoord2fv(@ tex2);
glVertex3fv(@ v2);
glTexCoord2fv(@ tex3);
glVertex3fv(@ v3);
glTexCoord2fv(@ tex4);
glVertex3fv(@ v4);
glEnd;
end;


JLGetActiveCamera – глобальная функция, возвращающая указатель на активную камеру (имя которой хранится в JL_ACTIVE_CAM). У меня выглядит так:


function JLGetActiveCamera:JLCamera;
begin
result:=JLCamera(scene.Objects.GetObjByName(JL_ACTIVE_CAM));
end;


textures – некий класс-хранитель текстур. Очевидно, что по textures.GetObjByName(TexID) возвращается указатель на текстуру с именем TexID. Подробнее об этом классе – в следующей главе.

Вот, у нас уже есть каркасы для камеры, спрайта и геометрии. Они легко расширяемы. В следующих главах мы переделаем расчет координат спрайта на шейдеры и встроим поддержку VBO в геометрию. Но вначале текстуры.
Jurec
К началу раздела | Наверх страницы Сообщить об ошибке
Уроки для программистов - Камера и спрайт
Все документы раздела: Для тех, кто хочет писать игры | Движок на OpenGL | Создание игр в Game Maker | Bump mapping | Использование Direct Input | XNA framework |


Дизайн Elite Games V5 beta.18
EGM Elite Games Manager v5.17 02.05.2010