Do it yourself Do it yourself 3D Games with 3D Games with OpenGL OpenGL Szirmay-Kalos László Dept. of Control Engineering and Information Technology Budapest University of Technology email: [email protected] Web: http://www.iit.bme.hu/~szirmay
Dec 19, 2015
Do it yourselfDo it yourself3D Games with OpenGL3D Games with OpenGL
Szirmay-Kalos László
Dept. of Control Engineering and Information Technology
Budapest University of Technology
email: [email protected]
Web: http://www.iit.bme.hu/~szirmay
Subtasks of GamesSubtasks of Games
Rendering the scene from the point of view of the avatar (virtual self)
Controlling the avatar through the input devices (keyboard, mouse)
Controlling the „intelligent” virtual objects (AI)
Simulating the physical world
Libraries for input and outputLibraries for input and output
rendering
virtual worldmodell
input
simulation
OpenGL
Windows + GLUT
Interaction schemesInteraction schemes
printfscanf
printfscanf
var1
var2
Program driven:event - variable correspondance: PC
event
state
Eventhandler
Event driven:event - variablecorrespondance: state
Input/Output managementInput/Output management
Operatingsystem
WindowsGLUT
main
DisplayFunc
KeyboadFunc
IdleFunc
OpenGLgraphicshardware
application
initializationcallback registration
callbacksSpecialFunc
OpenGLOpenGL
Rendering API (library)– Rendering of 2D and 3D objects– follows the drawing state concept– Image operations
Independent of the windowing and operation systems– Window management should be done
separately
glX, wgl glu
OpenGLOpenGL
hw
application
gl
GLUT
Xwindow, MS-Windows
Window system
Windowingbridge
Convenience,tessellators
Window management
OpenGL syntax (C API)OpenGL syntax (C API)
glVertex3dv( … )
# of parameters2 - (x, y)3 - (x, y, z), (R, G, B)4 - (x, y, z, h) (R, G, B, A)
Data type b - byteub - unsigned bytes - shorti - intf - floatd - double
Vector or scalarv - vector - scalar
part of OpenGL API
InitializationInitialization
#include <GL/gl.h>#include <GL/glu.h>#include <GL/glut.h>
void main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(600, 600); // initialization glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow( "Space Game" );
glutDisplayFunc( DisplayFunc ); // callback registration glutIdleFunc( IdleFunc ); glutKeyboardFunc( KeyboardFunc ); glutSpecialFunc( SpecialKeyboardFunc ); glutMainLoop();}
R,G,B - R,G,B - Z
Demo 2: Demo 2: Single and double bufferingSingle and double buffering
single:sgame/Files/sgamesing.exe
double: sgame/Files/sgame.exe
Double buffering for animationDouble buffering for animation
frame buffer
1.
frame buffer
2.
monitor
glClear(GL_COLOR_BUFFER_BIT);drawing…glutSwapBuffers( );
draw
display
Rendering with OpenGLRendering with OpenGL
world definition modell-view transformperspective transform
1325628 1325628
1.2.
clipping z-buffering display
Why do we need Why do we need perspective transform?perspective transform?
What is seen in a pixel?
perspective transform
x1z1
x2z2
X = d = d
y1z1
y2z2Y = d = d
X = x1 = x2
Y = y1 = y2
Definition of transformationsDefinition of transformations
Tmodell Tview Tperspective
Tmodellview
xyz
XYZ
move, rotatescaleobjects
eye positionviewing directionview up
field of viewaspect ratiofront-back clipping
TviewportXP
YP
Elementary transformationsElementary transformations glTranslate: r’ = r + p glScale: x’= Sx x; y’= Sy y; z’ = Sz z
glRotate (ex. Rotation around axis z):
r’ = rSx 0 0
0 Sy 0
0 0 Sz
r’ = rcos sin
-sin cos
Homogeneous coordinatesHomogeneous coordinates Translation cannot fit into a 3x3 matrix
– Let us work with 4x4 matrices
[r’, 1] = [r, 1] = [r A + p, 1]
a11 a12 a13 0a21 a22 a23 0
a31 a32 a33 0
p1 p2 p3 1
A
p
[r’,1] = (...([r,1] Tn) Tn-1)... T1) = [r,1] (TnTn-1... T1)
Definition of transformationsDefinition of transformations
world definition
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); glLoadIdentity( );gluPerspective(fov,w/h,front,back);
glMatrixMode(GL_MODELVIEW); glLoadIdentity( );gluLookAt(eyex, eyey, eyez,
lookatx, lookaty, lookatz, vupx, vupy, vupz);
glTranslatef(px, py, pz); glRotatef(angle, axx, axy, axz);
eye
lookat
fov
w
h
w
h
Scene Definition OpenGLScene Definition OpenGLglBegin(GL_TRIANGLES);
glColor3f( 1, 1, 0 ); glVertex3f( x11, y11, z11 );glVertex3f( x12, y12, z12 );glVertex3f( x13, y13, z13 );
glColor3f( 0, 1, 0 ); glVertex3f( x21, y21, z21 );glVertex3f( x22, y22, z22 );glVertex3f( x23, y23, z23 );
glEnd();
x11,y11,z11
x12,y12,z12
x13,y13,z13
glColor4f(R,G,B,A)
Texture Mapping in OpenGLTexture Mapping in OpenGL
glEnable(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, texture_id); // which textureglBegin(GL_TRIANGLES);glTexCoord2f(u1, v1); glVertex3f(x1, y1, z1);glTexCoord2f(u2, v2); glVertex3f(x2, y2, z2);glTexCoord2f(u3, v3); glVertex3f(x3, y3, z3);glEnd();glDisable(GL_TEXTURE_2D);
(u1, v1)
(u2, v2)
(u3, v3)
x1,y1,z1
x2,y2,z2
x3,y3,z3
Definition of TexturesDefinition of TexturesglEnable(GL_TEXTURE_2D);glGenTextures(1, &texture_id);glBindTexture(GL_TEXTURE_2D, texture_id);
// load imageint width, height;unsigned char * image;image = LoadImage( filename, &width, &height );
// store textureglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image );
Images, image formatsImages, image formats Head:
– type, size (width, height) – bits-per-pixel, indexed-true color, lookup table
Body:– width x height number of pixels: (R,G,B) or idx– Encoding, compression (run length, LZW, Huffmann,
FFT, wavelet) Standard formats:
– TARGA, BMP, GIF, JPEG, TIFF, PCX
TARGA (.TGA)TARGA (.TGA)002
9 zeros
lower byte of widthupper byte of widthlower byte of heightupper byte of height
Bits-per-pixel: 2432
Body
Head: Body: b1g1r1
…
b2g2r2
Definition of surfaces as Definition of surfaces as triangle meshes: Tessellationtriangle meshes: Tessellation1. Find a parametric equation:
x(u,v) = x0 + r cos 2u sin v y(u,v) = y0 + r sin 2u sin vz(u,v) = z0 + r cos v u,v [0,1]
2. Select points in the unit rectangle
Quadrics: SphereQuadrics: Sphere// definitionGLUquadricObj * quadric;quadric = gluNewQuadric( );gluQuadricTexture(quadric, GL_TRUE);
// drawglBindTexture(GL_TEXTURE_2D, texture_id);gluSphere(quadric, R, 16, 10);
Rotating Earth: initRotating Earth: initGLUquadricObj * quadric;unsigned int earth_texture;
void Init( ) { quadric = gluNewQuadric( ); gluQuadricTexture(quadric, GL_TRUE);
glGenTextures(1, &earth_texture); glBindTexture(GL_TEXTURE_2D, earth_texture_id); glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
image = LoadImage(”earth.tga”, &width, &height ); glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);}
GLUT timer controlGLUT timer controllong time;
void IdleFunc( ) { // idle call back
float old_time = time; time = glutGet( GLUT_ELAPSED_TIME );
float dt = time - old_time;
AnimateIt( dt ); DrawIt( );
}
Rotating Earth: animate, drawRotating Earth: animate, drawvoid 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);
glPushMatrix( ); glRotatef( angle, 0, 0, 1 ); glBindTexture(GL_TEXTURE_2D, earth_texture); gluSphere( quadric, 1.0, 16, 10 ); glPopMatrix( ); glutSwapBuffers( );}
Earth Revolves around Earth Revolves around the Sun the Sun
dist
rot_angle
rev_angle
void AnimateIt( float dt ) { rot_angle += rot_speed * dt; rev_angle += rev_speed * dt;}
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: Rotating Earth Demo 3: Rotating Earth revolves around the Sunrevolves around the Sun
sgame/earth/earth.exe
Creating the spaceCreating the spacevoid DrawIt( ) { glBindTexture(GL_TEXTURE_2D, space_texture);
glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-SS, -SS, -SS);
glTexCoord2f(0, 1); glVertex3i(-SS, SS, -SS);
glTexCoord2f(1, 1); glVertex3i( SS, SS, -SS);
glTexCoord2f(1, 0); glVertex3i( SS, -SS, -SS); ... glEnd();}
SS,SS,SS
-SS,-SS,-SS
Game ObjectGame Object ControlIt:
– interacts with the others, ”thinks” and sets the available controls (e.g. rockets)
InteractIt: – communication between two objects
AnimateIt: – moves to the next position and orientation
DrawIt: – renders the object with OpenGL
Simulation loop (Game loop)Simulation loop (Game loop)
void IdleFunc( ) { // idle call back float old_time = time; time = glutGet( GLUT_ELAPSED_TIME ); float dt = time - old_time;
avatar -> ProcessInput( ); world -> Control( dt ); world -> Animate( dt );
glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); avatar -> SetCameraTransform(); world -> Draw(); glutSwapBuffers( );}
dt
Game dataflowGame dataflow
InputProcessing:
KeyboardFunc,SpecialFunc
input
Simulate:IdleFunc
virtualworld
Render
Representation of the Representation of the virtual worldvirtual world
Dynamic objects (kill) Different object types (heterogeneous collection) Linked list (hierarchical structures, trees)
ship1 ship2avatar
space sun
world
bulletexplosion
Join: add new element
SpaceshipSpaceship Complex geometry
– quadrilateral mesh Complex texture Physical animation
– forces (gravitation, rockets)– collisions
Behaviour (AI)– control rockets
avoid collisions, escape from avatar, chase avatar
Animate: using NewtonAnimate: using Newton’s laws’s lawsforcem
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();}
velocity
position
Orientation ControlOrientation Control
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;
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( ); }
modell_head
world_head = velocity.UnitVector();
Ship :: ControlItShip :: ControlItvoid Ship :: ControlIt( float dt ) { force = Vector(0, 0, 0); Interact( world );}
ship1 ship2avatar
space sun
world
bulletexplosion
void Ship::InteractIt( GameObject * object )
Ship: InteractItShip: InteractItvoid Ship :: InteractIt( GameObject * object ) { if ( object->GetType( ) == PLANET ) {
}
if ( object->GetType( ) == AVATAR ) {
}}
F = f m·M r2
avatar avatar
bullet
aiming angle
Ship: InteractItShip: InteractIt
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();
}
F = f m·M r2
Ship: InteractItShip: InteractIt
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)); }}
avatar avatar
bullet
aim
Collision detection between Collision detection between two slow objectstwo slow objects
dist = obj1.position - obj2.positionmin = obj1.BoundingRadius() + obj2.BoundingRadius()if (dist.Length() < min) Collision!
given t
Problem with fast objects
t
t + t
BulletBullet Seemingly complex geometry Similar look from all directions Easier to define its image
Hit detection = fast collision detectiontransparent
BillboardsBillboards Single semi-transparent texture on an
oriented quadrilateral
pos
pos
QUAD
QUAD
Tmodell Tview Tperspectivexyz
XYZ
positionorientation
camera positioncamera orientation
Bullet :: DrawItBullet :: DrawItvoid Bullet :: DrawIt() {
Set transformation to compensate the rotation of the camera transform
glEnable(GL_BLEND); // transparency glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(-size, -size); glTexCoord2f(1, 0); glVertex2f(size, -size); glTexCoord2f(1, 1); glVertex2f(size, size); glTexCoord2f(0, 1); glVertex2f(-size, size); glEnd();
glDisable(GL_BLEND);}
How can we store How can we store transparent textures?transparent textures?
Some image file formats allow not only RGB triplets, but also RGBA quadruples
Store the texture into two images– image 1: rgb– image 2: a gray-scale image of alpha
Compensate camera Compensate camera transformtransform
float viewMatrix[16];glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix);
glMultMatrixf( viewMatrix );
0001tx, ty, tz
Rotation invert
pos.x, pos.y, pos.z
Collision detection with fast objects: Collision detection with fast objects:
ray-tracingray-tracing
velocity
rel_velocity = velocity - vel2ray: position + rel_velocity·t
If (ray intersects bounding sphere first AND tintersect < dt) Collision!
hit_object = world->Intersect(position,velocity,t);
ship1 ship2 avatar space sun
world
bulletexplosion
position
vel2
Bullet :: ControlItBullet :: ControlItvoid Bullet :: ControlIt( float dt ) { GameObject * hit_object = world -> Intersect(position, velocity, t);
if ( t > 0 && t <= dt ) {Kill(); // bullet disappearsVector hit_point = position + velocity * t;int hit_type = hit_object -> GetType();if ( hit_type == AVATAR ) exit(1); // player is killedelse { world -> Join( new Explosion( hit_point ) ); if (hit_type == SHIP) hit_object -> Kill();}
} age += dt; if ( age > 10 ) Kill(); // bullet disappears}
ExplosionExplosion Seemingly complex, randomly
animated structure
Similar look from all directions Collection of billboards
Particle system
Particle SystemsParticle Systems
position: position += velocity * dtvelocity: velocity += acceleration * dtacceleration: acceleration = force / weight
lifetimeage: age += dt; if (age > lifetime) Kill();
size, dsize: size += dsize * dt;weight, dweight: weight += dweight * dtcolor, dcolor: color += dcolor * dt
global force field(smoke)
randominitialvalues
Explosion settingsExplosion settings
position = Rand( center, 0.1 ); // initially focusedlifetime = Rand( 2.0, 1.0 );
size = 0.001; // initially smalldsize = Rand( 1.0, 0.5 ) / lifetime / 2.0;
velocity = Rand( Vector(0, 0, 0), 0.4 ); // symmetricacceleration = Rand( Vector(0, 0, 0), 0.4 );
// 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.5, 0, -1) / lifetime / 2;
Rand(mean, var) mean
var
AvatarAvatar
Keyboard controls its behavior:– ProcessInput
Its position and orientation will be the camera position and orientation before rendering– SetCameraTransform
Like a ship but is not drawn– Control: gravitation, bullet collision
Avatar :: SetCameraTransformAvatar :: SetCameraTransformAvatar :: SetCameraTransform( ) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(position.x, position.y, position.z,
position.x + velocity.x, position.y + velocity.y, position.z + velocity.z,
up.x, up.y, up.z);}
eye
lookat
up = [0, 1, 0]
Keyboard ProcessingKeyboard Processing
KeyboardFuncSpecialFunc
input
IdleFunc:GameLoop
virtualworld
IsSpace, IsLeft, IsRight, IsUp, IsDown
Avatar :: ProcessInputAvatar :: ProcessInputAvatar :: ProcessInput( GLUTWindow * input ) { if ( input->IsSpace( ) )// shoot
world -> Join(new Bullet(position, velocity));
Vector head = velocity.UnitVector();
if ( input->IsUp() ) force += up * (-1); if ( input->IsDown() ) force += up; if ( input->IsLeft() ) force += up % head; if ( input->IsRight() ) force += head % up;}
Game Game EngineEngine
GameObjectposition, velocity, accelerationControlIt(float dt )AnimateIt(float dt)InteractIt( GameObject * o) DrawIt( )IntersectIt(Ray r, float& t)
MemberControl, Animate, DrawInteract, Intersect, Join
TexturedObject
next
AvatarProcessInput()
SetCameraTransform()
TextureLoad( char * fname)
BillBoardDrawIt()
ParticleSystemEmit(int n)
Particle
GLUTWindow
GameEngineDisplayFunc
IdleFuncKeyPress
world
avatar
500 C++ lines