Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Do it yourself 3D 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 Demo 1: The goal sgame/SpaceGame I 3D Games Field objects Self Enemy AI Virtual reality rendering interaction control avatar virtual world Subtasks 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 output Windows + GLUT simulation input virtual world modell rendering OpenGL Interaction schemes printf scanf var1 event state printf var2 scanf Event handler Program driven: event - variable correspondance: PC Event driven: event - variable correspondance: state Input/Output management initialization callback registration Operating system Windows main DisplayFunc GLUT KeyboadFunc SpecialFunc callbacks IdleFunc graphics hardware OpenGL application OpenGL 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 OpenGL application GLUT glX, wgl glu Xwindow, MS-Windows gl hw Window system Windowing bridge Window management Convenience, tessellators OpenGL syntax (C API) part of OpenGL API glVertex3dv( … ) # of parameters 2 - (x, y) 3 - (x, y, z), (R, G, B) 4 - (x, y, z, h) (R, G, B, A) Data type b - byte ub - unsigned byte s - short i - int f - float d - double Vector or scalar v - vector - scalar R,G,BInitialization - R,G,B - Z #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(); } Demo 2: Single and double buffering single:sgame/Files/sgamesing.exe double: sgame/Files/sgame.exe Double buffering for animation draw frame buffer 1. frame buffer 2. glClear(GL_COLOR_BUFFER_BIT); drawing… glutSwapBuffers( ); display monitor Rendering with OpenGL world definition modell-view transform 2. perspective transform 1. 628 clipping z-buffering 1325 1325 628 display Why do we need perspective transform? perspective transform What is seen in a pixel? x1 x2 X = d z1 = d z2 X = x1 = x2 y2 y1 Y = d z1 = d z2 Y = y1 = y2 Definition of transformations X Y Z Tmodellview x y z Tmodell Tview Tperspective XP Tviewport YP move, rotate scale objects eye position viewing direction view up field of view aspect ratio front-back clipping Elementary transformations glTranslate: r’ = r + p glScale: x’= Sx x; y’= Sy y; z’ = Sz z r’ = r Sx 0 0 0 Sy 0 0 0 Sz glRotate (ex. Rotation around axis z): r’ = r cos f sin f 0 -sin f cos f 0 0 0 1 Homogeneous coordinates Translation cannot fit into a 3x3 matrix – Let us work with 4x4 matrices a11 A a12 a13 0 [r’, 1] = [r, 1] a21 a22 a23 = [r A + p, 1] 0 a31 a32 a33 p 0 p1 p2 p 3 [r’,1] = (...([r,1] Tn1) Tn-1)... T1) = [r,1] (TnTn-1... T1) Definition of transformations glViewport(0, 0, w, h); h glMatrixMode(GL_PROJECTION); glLoadIdentity( ); gluPerspective(fov,w/h,front,back); w fov eye w h lookat glMatrixMode(GL_MODELVIEW); glLoadIdentity( ); gluLookAt(eyex, eyey, eyez, lookatx, lookaty, lookatz, vupx, vupy, vupz); glTranslatef(px, py, pz); world definition glRotatef(angle, axx, axy, axz); Scene Definition OpenGL 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(); Texturing Texture Mapping in OpenGL (u2, v2) x3,y3,z3 (u1, v1) (u3, v3) x2,y2,z2 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); which texture z1); z2); z3); Definition of Textures glEnable(GL_TEXTURE_2D); glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); // load image int width, height; unsigned char * image; image = LoadImage( filename, &width, &height ); // store texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image ); Images, 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) Head: 0 0 2 9 zeros lower byte of width upper byte of width lower byte of height upper byte of height Bits-per-pixel: 24 32 Body Body: b1 g1 r1 b2 g2 r2 … Definition of surfaces as triangle meshes: Tessellation 1. Find a parametric equation: x(u,v) = x0 + r cos 2u sin v y(u,v) = y0 + r sin 2u sin v z(u,v) = z0 + r cos v u,v [0,1] 2. Select points in the unit rectangle Quadrics: Sphere // definition GLUquadricObj * quadric; quadric = gluNewQuadric( ); gluQuadricTexture(quadric, GL_TRUE); // draw glBindTexture(GL_TEXTURE_2D, texture_id); gluSphere(quadric, R, 16, 10); Rotating Earth: init GLUquadricObj * 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 control long 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, 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); glPushMatrix( ); glRotatef( angle, 0, 0, 1 ); glBindTexture(GL_TEXTURE_2D, earth_texture); gluSphere( quadric, 1.0, 16, 10 ); glPopMatrix( ); glutSwapBuffers( ); } Demo 3: Rotating Earth sgame/earth/earth1.exe Earth Revolves around the Sun 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: Rotating Earth revolves around the Sun sgame/earth/earth.exe SS,SS,SS Creating the space void DrawIt( ) { glBindTexture(GL_TEXTURE_2D, space_texture); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-SS, -SS, -SS); -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(); } ControlIt(dt) Games AnimateIt(dt), DrawIt() rendering interaction control avatar virtual world Game 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) dt 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( ); } Game dataflow Input Processing: KeyboardFunc, SpecialFunc input Simulate: IdleFunc virtual world Render Representation of the virtual world Dynamic objects (kill) Different object types (heterogeneous collection) Linked list (hierarchical structures, trees) world ship1 ship2 space avatar sun bullet explosion Join: add new element Spaceship Complex geometry – quadrilateral mesh Complex texture Physical animation – forces (gravitation, rockets) – collisions Behaviour (AI) – control rockets avoid collisions, escape from avatar, chase avatar Building a ship: Polygon modelling in Maya Extruding Extruding (still) Extruding (once more) Extruding (final) Smoothing by Subdivision Subdivision surfaces = 1/4 = 1/4 + 1/4 = 1/2 + 1/16 + 1/16 Subdivision smoothing: 1 level Subdivision smoothing: 2 levels Texturing modell texture Definition of the parameterization in Maya (0,0) (1,1) Definition of the parameterization Creating a texture for the ship Textured ship Animate: using Newton’s laws 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 Orientation Control 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; 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( ); } Ship :: ControlIt void Ship :: ControlIt( float dt ) { force = Vector(0, 0, 0); Interact( world ); } void Ship::InteractIt( GameObject * object ) world ship1 ship2 space avatar sun bullet explosion Ship: InteractIt void Ship :: InteractIt( GameObject * object ) { if ( object->GetType( ) == PLANET ) { F = f m·M r2 } if ( object->GetType( ) == AVATAR ) { bullet avatar } } avatar aiming angle Ship: InteractIt 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(); } Ship: InteractIt bullet avatar avatar aim 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)); } } Collision detection between two slow objects Problem with fast objects t given t t+t dist = obj1.position - obj2.position min = obj1.BoundingRadius() + obj2.BoundingRadius() if (dist.Length() < min) Collision! Bullet Seemingly complex geometry Similar look from all directions Easier to define its image transparent Hit detection = fast collision detection Billboards Single semi-transparent texture on an oriented quadrilateral pos pos QUAD QUAD x y z Tmodell position orientation Tview Tperspective camera position camera orientation X Y Z Bullet :: DrawIt void 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); glTexCoord2f(1, 0); glTexCoord2f(1, 1); glTexCoord2f(0, 1); glEnd(); glDisable(GL_BLEND); } glVertex2f(-size, -size); glVertex2f(size, -size); glVertex2f(size, size); glVertex2f(-size, size); How can we store 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 transform float viewMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix); 0 Rotation 0 0 tx, ty, tz 1 invert pos.x, pos.y, pos.z glMultMatrixf( viewMatrix ); Collision detection with fast objects: ray-tracing position vel2 velocity rel_velocity = velocity - vel2 ray: position + rel_velocity·t 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 Bullet :: ControlIt void Bullet :: ControlIt( float dt ) { GameObject * hit_object = world -> Intersect(position, velocity, t); if ( t > 0 && t <= dt ) { Kill(); // bullet disappears Vector hit_point = position + velocity * t; int hit_type = hit_object -> GetType(); if ( hit_type == AVATAR ) exit(1); // player is killed else { world -> Join( new Explosion( hit_point ) ); if (hit_type == SHIP) hit_object -> Kill(); } } age += dt; if ( age > 10 ) Kill(); // bullet disappears } Explosion Seemingly complex, randomly animated structure Similar look from all directions Collection of billboards Particle system Particle Systems global force field (smoke) random initial values 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 Explosion settings var Rand(mean, var) position = Rand( center, 0.1 ); lifetime = Rand( 2.0, 1.0 ); mean // initially focused size = 0.001; // initially small dsize = Rand( 1.0, 0.5 ) / lifetime / 2.0; velocity = Rand( Vector(0, 0, 0), 0.4 ); // symmetric acceleration = 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; Avatar 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 :: SetCameraTransform Avatar :: 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 up = [0, 1, 0] lookat Keyboard Processing KeyboardFunc SpecialFunc input IsSpace, IsLeft, IsRight, IsUp, IsDown IdleFunc: GameLoop virtual world Avatar :: ProcessInput Avatar :: ProcessInput( GLUTWindow * input ) { if ( input->IsSpace( ) ) // shoot world -> Join(new Bullet(position, velocity)); Vector head = velocity.UnitVector(); 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 Game Engine 500 C++ lines Texture Load( char * fname) Particle avatar Avatar ProcessInput() SetCameraTransform() ParticleSystem TexturedObject BillBoard Emit(int n) DrawIt() Space Game GameEngine Avatar BillBoard Self ProcessInput ControlIt InteractIt Bullet ControlIt TexturedObject Space DrawIt Ship Planet DrawIt DrawIt InteractIt AnimateIt ControlIt SpaceGame 350 C++ lines