Demo 1: A cél
3D Játékok készítése OpenGL környezetben Szirmay-Kalos László Irányítástechnika és Informatika Tanszék Budapesti Műszaki és Gazdaságtudományi Egyetem email:
[email protected] Web: http://www.iit.bme.hu/~szirmay
3D játékok
Enemy AI
sgame/SpaceShootGame
Virtuális valóság képszintézis
interakció
Self Field objects
vezérlés
avatar Virtuális világ
Játékok feladatai Képszintézis az avatár nézőpontjából z Az avatár vezérlése a beviteli eszközökkel (keyboard, mouse) z Az „intelligens” virtuális objektumok vezérlése (AI) z A fizikai világ szimulációja
I/O könyvtárak
z
Windows + GLUT
szimuláció input Virtuális világmodell
képszintézis
OpenGL
R,G,B - R,G,B - Z
Initiacializáció
Input/Output menedzsment inicializáció callback regisztráció Operációs rendszer Windows
main
#include
#include #include
DisplayFunc GLUT KeyboadFunc SpecialFunc callbacks
void main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(600, 600); // ablak kijelölés glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow( "Space Game" );
IdleFunc Grafikus hardver
glutDisplayFunc( DisplayFunc ); // callback regisztráció glutIdleFunc( IdleFunc ); glutKeyboardFunc( KeyboardFunc ); glutSpecialFunc( SpecialKeyboardFunc ); glutMainLoop();
OpenGL applikáció
}
Demo 2: Szimpla és dupla bufferelés
Dupla bufferelés
single:sgame/Files/sgamesing.exe
draw
frame buffer 2.
double: sgame/Files/sgame.exe
glClear(GL_COLOR_BUFFER_BIT); drawing… glutSwapBuffers( );
frame buffer 1.
display
monitor
Képszintézis OpenGLOpenGL-lel
A transzformáció lánc X Y Z
Tmodellview
Világ + mozgás
Nézeti transzformáció
2.
Perspektív transzformáció
628
1325 1325 628
Láthatóság: z-buffer
Tmodell
megjelenítés
Tview
Tperspective
XP Tviewport
YP eltolás, forgatás nagyítás
1. ∞
vágás
x y z
szempozíció Nézeti irány Függőleges
Látószög Képoldal arány Első-hátsó vágás
Tárgyak geometriai definíciója
Texturing
glBegin(GL_TRIANGLES);
x12,y12,z12 x13,y13,z13 x11,y11,z11
glColor3f( 1, 1, glVertex3f( x11, glVertex3f( x12, glVertex3f( x13,
0 ); y11, z11 ); y12, z12 ); y13, z13 );
glColor3f( 0, 1, glVertex3f( x21, glVertex3f( x22, glVertex3f( x23,
0 ); y21, z21 ); y22, z22 ); y23, z23 );
glColor4f(R,G,B,A) glEnd();
Felületek mint háromszöghálók: Tesszelláció
Textúra leképzés (u2, v2)
1. Keressük meg a felület paraméteres egyenletét x(u,v) = x0 + r cos 2πu sin πv y(u,v) = y0 + r sin 2πu sin πv z(u,v) = z0 + r cos πv u,v ∈ [0,1]
x3,y3,z3
(u1, v1)
(u3, v3) x2,y2,z2
2. Háromszögesítsük a paraméterteret
x1,y1,z1 glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture_id); // glBegin(GL_TRIANGLES); glTexCoord2f(u1, v1); glVertex3f(x1, y1, glTexCoord2f(u2, v2); glVertex3f(x2, y2, glTexCoord2f(u3, v3); glVertex3f(x3, y3, glEnd(); glDisable(GL_TEXTURE_2D);
z which texture
θ
z1); z2); z3);
x
Kvadratikus felületek: Gömb
// definition GLUquadricObj * quadric = gluNewQuadric( ); gluQuadricTexture(quadric, GL_TRUE); // draw glBindTexture(GL_TEXTURE_2D, texture_id); gluSphere(quadric, R, 16, 10);
ϕ
y
GLUT idővezérlés float time; void IdleFunc( ) {
// idle call back
float old_time = time; time = glutGet( GLUT_ELAPSED_TIME ); float dt = time - old_time; AnimateIt( dt ); DrawIt( ); }
Forog a Föld: animate, animate, draw void AnimateIt( float dt ) { angle += rot_speed * dt; if (angle > 360.0) angle -= 360.0; } void DrawIt( ) { glClearColor(0, 0, 0, 0); // R,G,B,A glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
Demo 3: Forog a föld
sgame/earth/earth1.exe
glPushMatrix( ); glRotatef( angle, 0, 0, 1 ); glBindTexture(GL_TEXTURE_2D, earth_texture); gluSphere( quadric, 1.0, 16, 10 ); glPopMatrix( ); glutSwapBuffers( ); }
A Föld kering a Nap körül void AnimateIt( float dt ) { rot_angle += rot_speed * dt; rev_angle += rev_speed * dt; } rot_angle
rev_angle dist
void DrawIt( ) { glPushMatrix( ); glRotatef(rev_angle, 0, 0, 1); glTranslatef(dist, 0, 0 ); glRotatef(rot_angle, 0, 0, 1); glBindTexture(GL_TEXTURE_2D, earth_texture); gluSphere(quadric, 1, 16, 10); glPopMatrix( ); glutSwapBuffers( ); }
Demo 3: A Föld kering a Nap körül sgame/earth/earth.exe
SS,SS,SS
Az űr void DrawIt( ) { glBindTexture(GL_TEXTURE_2D, space_texture); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-SS, -SS, -SS);
-SS,-SS,-SS
ControlIt(dt)
Játékok
AnimateIt(dt), DrawIt()
képszintézis
interakció
glTexCoord2f(0, 1); glVertex3i(-SS, SS, -SS); glTexCoord2f(1, 1); glVertex3i( SS, SS, -SS); glTexCoord2f(1, 0); glVertex3i( SS, -SS, -SS); ... glEnd(); }
vezérlés
avatár Virtuális világ
Szimulációs hurok (Játék hurok)
Játékobjektumok z
dt
ControlIt:
void IdleFunc( ) { // idle call back float old_time = time; time = glutGet( GLUT_ELAPSED_TIME ); float dt = time - old_time;
– ”gondolkodik” és a lehetséges vezérléséket alkalmazza (pl. rakéták) z
InteractIt:
avatar -> ProcessInput( ); world -> Control( dt ); world -> Animate( dt );
– Társalog másokkal, figyeli a többieket z
AnimateIt:
glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); avatar -> SetCameraTransform(); world -> Draw(); glutSwapBuffers( );
– A következő helyre és orientációba megy z
DrawIt: – Felrajzolja magát a képernyőre }
Az űrhajó
A virtuális világ z z z z
Objektumok dinamikusak (öldöklés) Különböző objektumtípusok (heterogén kollekció) Láncolt lista (fák)
– négyszögháló
Komplex textúra z Fizikai animáció z
world ship1
ship2
space avatar
sun
Komplex geometria
– erők (gravitáció, rakéták) – ütközések
bullet explosion
z
Viselkedés (AI) – A rakéták vezérlése
Join: új elem hozzávétele
Az űrhajó felépítése: Maya
z
Ütközés elkerülés, avatártól menekülés, avatár üldözése
Kihúzás
Megint kihúzás
És megint kihúzás
Az utolsó kihúzás
Subdivision surfaces = 1/4 Σ = 1/4 Σ + 1/4 Σ = 1/2 + 1/16 Σ + 1/16 Σ
Aláosztásos simítás: 1 szint
Aláosztásos simítás: 2. szint
Textúrázás
Paraméterezés: Maya
(1,1)
(0,0)
modell
textúra
A textúrázott űrhajó
Animate: Animate: Newton mozgástörvényei m
force position velocity
void Ship :: AnimateIt( float dt ) { acceleration = force/m; velocity += acceleration * dt; position += velocity * dt; } void Ship :: DrawIt() { glPushMatrix( ); glTranslatef(position.x, position.y, position.z); glBegin( GL_QUADS ); ... ; glEnd( ); glPopMatrix(); }
modell_head
Orientáció beállítása world_head = velocity.UnitVector(); void Ship :: DrawIt() { glPushMatrix( ); glTranslatef(position.x, position.y, position.z); Vector modell_head( 0, 0, 1 ); Vector world_head = velocity.UnitVector(); Vector rotate_axis = modell_head % world_head;
Ship :: ControlIt void Ship :: ControlIt( float dt ) { force = Vector(0, 0, 0); Interact( world ); } void Ship::InteractIt( GameObject * object ) world ship1
ship2
float cos_rotate_angle = world_head * modell_head; glRotatef( acos(cos_rotate_angle)* 180 / M_PI, rotate_axis.x,rotate_axis.y,rotate_axis.z); glBegin( GL_QUADS ); ... ; glEnd( ); glPopMatrix( );
space
sun
bullet explosion
avatar
}
Ship: Ship: InteractIt
Ship: Ship: InteractIt
void Ship :: InteractIt( GameObject * object ) { if ( object->GetType( ) == PLANET ) {
F = f m·M r2
}
if ( object->GetType( ) == AVATAR ) { bullet
avatar
avatar
F = f m·M r2 if ( object->GetType( ) == PLANET ) { Planet * planet = (Planet *)object; Vector dist = planet->position - position; float r = dist.Length(); force += dist * f * mass * planet->mass /r/r/r; if ( r < planet->Radius() * 2 ) force += (position - planet->position)/r; if ( r < planet->Radius()+BoundingRadius() ) Kill();
aiming angle
} }
}
Ship: Ship: InteractIt bullet
avatar
avatar
Ütközésdetektálás lassú objektumok között Probléma, ha az objektum gyors
aim
t if ( object->GetType( ) == AVATAR ) { Avatar * avatar = (Avatar *)object; Vector goal = avatar -> position - position; force += goal * 0.05; cosaim = velocity.UnitVector()*goal.UnitVector(); if (cosaim > 0.9) { world-> Join( new Bullet(position, velocity)); } }
given t
t+∆t
dist = obj1.position - obj2.position min = obj1.BoundingRadius() + obj2.BoundingRadius() if (dist.Length() < min) Collision!
Lövedék Nagyon komplex geometria z Hasonló kinézet minden irányból z Könnyebb a képét használni z
Plakátok: Billboards Egyetlen félig átlátszó textúra egy téglalapon
z
pos pos QUAD
transparent QUAD
z
x y z
Ütközésdetektálás = gyors mozgás
A modell transzformáció forgatási részével a nézeti transzformáció forgatási részét kompenzáljuk
pozíció orientáció
position vel2 velocity
glVertex2f(-size, -size); glVertex2f(size, -size); glVertex2f(size, size); glVertex2f(-size, size);
X Y Z
Tperspective
kamera pozíció kamera orientáció
rel_velocity = velocity - vel2 ray: position + rel_velocity·t
glEnable(GL_BLEND); // transparency glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBegin(GL_QUADS); glTexCoord2f(0, 0); glTexCoord2f(1, 0); glTexCoord2f(1, 1); glTexCoord2f(0, 1); glEnd();
Tview
Gyors ütközésdetektálás: rayray-tracing
Bullet :: DrawIt void Bullet :: DrawIt() {
Tmodell
If (ray intersects bounding sphere first AND tintersect < dt) Collision! hit_object = world->Intersect(position,velocity,t); world ship1
ship2
avatar
space
sun
bullet explosion
glDisable(GL_BLEND); }
Robbanás Nagyon komplex geometria z Hasonló kinézet minden irányból z Plakátgyűjtemény
Részecske rendszerek
z
z
Részecske rendszer
Globális erőtér (szél fújja a füstöt)
Véletlen Kezdeti értékek
position: velocity: acceleration:
position += velocity * dt velocity += acceleration * dt acceleration = force / weight
lifetime age:
age += dt; if (age > lifetime) Kill();
size, dsize: weight, dweight: color, dcolor:
size += dsize * dt; weight += dweight * dt color += dcolor * dt
Robbanás paraméterei
Avatár
var Rand(mean, var)
mean
z
– ProcessInput
// initially focused
position = center; lifetime = Rand( 2.0, 1.0 );
A viselkedését a klaviatúra vezérli:
z
A helye és iránya viszi a kamerát
z
Olyan mint egy űrhajó, de nem rajzoljuk
– SetCameraTransform
size = 0.001; // initially small dsize = Rand( 0.5, 0.25 ) / lifetime; velocity = Rand( Vector(0, 0, 0), 0.4 ); // symmetric acceleration = Rand( Vector(0, 0, 0), 0.4 );
– Control: gravitáció, lövedék ütközés
// from yellow opaque animate to reddish transparent color = Rand( Color(1, 0.5, 0, 1), Color(0, 0.5, 0, 0) ); dcolor = Color(0, -0.25, 0, -1) / lifetime;
Klaviatúra kezelés
Avatar :: ProcessInput Avatar :: ProcessInput( GLUTWindow * input ) {
KeyboardFunc SpecialFunc
input
if ( input->IsSpace( ) )// shoot world -> Join(new Bullet(position, velocity));
IsSpace, IsLeft, IsRight, IsUp, IsDown
Vector head = velocity.UnitVector(); virtual world
IdleFunc: GameLoop
if if if if
( ( ( (
input->IsUp() ) input->IsDown() ) input->IsLeft() ) input->IsRight() )
force force force force
+= += += +=
up * (-1); up; up % head; head % up;
}
GLUTWindow
GameEngine DisplayFunc IdleFunc KeyPress
GameObject position, velocity, acceleration ControlIt(float dt ) AnimateIt(float dt) InteractIt( GameObject * o) DrawIt( )
IntersectIt(Ray r, float& t)
world Member Control, Animate, Draw Interact, Intersect, Join
next
Űrjáték
Játékmotor 500 C++ sor
Texture Load( char * fname) Particle
GameEngine Avatar
BillBoard
Self ProcessInput ControlIt InteractIt
Bullet ControlIt
avatar Avatar ProcessInput() SetCameraTransform()
TexturedObject BillBoard DrawIt()
ParticleSystem Emit(int n)
TexturedObject
Space DrawIt
Ship Planet DrawIt DrawIt InteractIt AnimateIt ControlIt SpaceGame
350 C++ sor
Terepek
Egy földi lövöldözős játék
ég
magasságmező textúra
terep karakterek
Terep ütközésdetektálás
Ellenség z
if (height(x,y) > z) Ütközés!
Bonyolult, animált geometia – Clip-ek = kulcskeretek z
z
Áll, fut, támad, haldoklik, szenved,
+ mesh animáció
x,y
Textúrák (animált) Mesterséges intelligencia z Ütközés: befoglaló gömb z
Terepen járás: Pozíció(x, y) = (x, y, height(x,y) + lábmagasság)
Futás clip: clip: 1. kulcskeret
z
Futás clip: clip: 2. kulcskeret
Futás clip: clip: 3. kulcskeret
Futás clip: clip: 4. kulcskeret
Futás clip: clip: 5. kulcskeret
Futás clip: clip: 6. kulcskeret
t= 0
Mesh animáció:
Mozgásvezérlés
Idő: t AI gép Két közrefogó keyframe
Lináris interpoláció csúcspontonként t= 1
AI állapot
Idő: t Clip = start, stop frame
Keyframe animáció
Csúcspont pozíciók Csúcspont pozíciók
kulcskeretek
Mesterséges intelligencia Dist < 4 && Avatar_angle < 40
Dont Care
Escape Dist > 6
Dist < 4 && Avatar_angle > 60
Avatar_angle < 20 Dist < 1 && Aim_angle < 10
Chase
Attack Dist > 1
Ütközés golyóval
Dying
Aim_angle
Avatar_angle
Avatar
Textúrázás Textúrázás