420 likes | 514 Views
3D Game Programming interactive and special effect. Ming-Te Chi Department of Computer Science, National Chengchi University. Outline. Interactive Graphics ( CH12 in 4ed ) Intersection Particles. INTERACTIVE. keyPressed . glutKeyboardFunc(keyPressed);
E N D
3D Game Programminginteractive and special effect Ming-Te Chi Department of Computer Science, National Chengchi University
Outline • Interactive Graphics (CH12 in 4ed) • Intersection • Particles
keyPressed glutKeyboardFunc(keyPressed); ------------------------------------------ void keyPressed (unsigned char key, int x, int y) { If (key == ‘a’) { // If they ‘a’ key was pressed // Perform action associated with the ‘a’ key } }
key buffering bool* keyStates = newbool[256]; // Create an array of boolean values of length 256 (for ascii ) -------------------------------------------------------- void keyPressed (unsigned char key, int x, int y) { keyStates[key] = true; // Set the state of the current key to pressed }
key buffering voidkeyOperations (void) { } //-------------------------------------------- void display (void) { keyOperations(); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background … }
gluProject() glGetIntegerv(GL_VIEWPORT,viewport);glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);gluProject( (GLdouble)objX,(GLdouble)objY,(GLdouble)objZ, mvmatrix,projmatrix,viewport, &win_x,&win_y,&win_z );
gluUnProject() glGetDoublev( GL_MODELVIEW_MATRIX, modelview ); glGetDoublev( GL_PROJECTION_MATRIX, projection ); glGetIntegerv( GL_VIEWPORT, viewport ); winX = (float)x; winY = (float)viewport[3] - (float)y; glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ ); gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
Selection • Naming Your Primitives /////////////////////////////// // Define object names #define SUN 1 #define MERCURY 2 #define VENUS 3 #define EARTH 4 #define MARS 5
Planet example void RenderScene(void) { // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Save the matrix state and do the rotations glMatrixMode(GL_MODELVIEW); glPushMatrix(); // Translate the whole scene out and into view glTranslatef(0.0f, 0.0f, -300.0f); // Initialize the names stack glInitNames(); glPushName(0);
// Name and draw the Sun glColor3f(1.0f, 1.0f, 0.0f); glLoadName(SUN); DrawSphere(15.0f); // Draw Mercury glColor3f(0.5f, 0.0f, 0.0f); glPushMatrix(); glTranslatef(24.0f, 0.0f, 0.0f); glLoadName(MERCURY); DrawSphere(2.0f); glPopMatrix();
Working with selection model • glRenderModel() • GL_RENDER • GL_SELECTION • GL_FEEDBACK // Process the mouse click void MouseCallback(int button, int state, int x, int y) { if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) ProcessSelection(x, y); }
void ProcessSelection(int xPos, int yPos) GLfloat fAspect; // Space for selection buffer static GLuint selectBuff[BUFFER_LENGTH]; //64 // Hit counter and viewport storage GLint hits, viewport[4]; // Setup selection buffer glSelectBuffer(BUFFER_LENGTH, selectBuff); // Get the viewport glGetIntegerv(GL_VIEWPORT, viewport); // Switch to projection and save the matrix glMatrixMode(GL_PROJECTION); glPushMatrix();
// Change render mode glRenderMode(GL_SELECT); // Establish new clipping volume to be unit cube around // mouse cursor point (xPos, yPos) and extending two pixels // in the vertical and horizontal direction glLoadIdentity(); gluPickMatrix(xPos, viewport[3] - yPos + viewport[1], 2,2, viewport); // Apply perspective matrix fAspect = (float)viewport[2] / (float)viewport[3]; gluPerspective(45.0f, fAspect, 1.0, 425.0); // Draw the scene RenderScene();
// Collect the hits hits = glRenderMode(GL_RENDER); GLuint nErr = glGetError(); // If a single hit occurred, display the info. if(hits == 1) ProcessPlanet(selectBuff[3]); else glutSetWindowTitle("Nothing was clicked on!"); // Restore the projection matrix glMatrixMode(GL_PROJECTION); glPopMatrix(); // Go back to modelview for normal rendering glMatrixMode(GL_MODELVIEW); }
ProcessPlanet(GLuint id) void ProcessPlanet(GLuint id) { switch(id) { case SUN: glutSetWindowTitle("You clicked on the Sun!"); break; case MERCURY: glutSetWindowTitle("You clicked on Mercury!"); break; case VENUS: glutSetWindowTitle("You clicked on Venus!"); break; } }
What you need to know • Basic geometry • vectors, points, homogenous coordinates, affine transformations, dot product, cross product, vector projections, normals, planes • Math helps… • Linear algebra, calculus, differential equations
Plane Equations (Nx, Ny, Xz) • A 3D Plane is defined by a normal and a distance along that normal • Plane Equation: • Find d: • For test point (x,y,z), if plane equation > 0: point on ‘front’ side (in direction of normal), < 0: on ‘back’ side = 0: directly on plane • 2D Line ‘Normal’: negate rise and run, find d using the same method P
So where do you start….? • First you have to detect collisions • With discrete timesteps, every frame you check to see if objects are intersecting (overlapping) • Testing if your model’s actual volume overlaps another’s is too slow • Use bounding volumes to approximate each object’s real volume
Bounding Volumes • Convex-ness is important. • Spheres, cylinders, boxes, polyhedra, etc. • Really you are only going to use spheres, boxes, and polyhedra (…and probably not polyhedra) • Spheres are mostly used for fast culling • For boxes and polyhedra, most intersection tests start with point inside-outside tests • That’s why convexity matters. There is no general inside-outside test for a 3D concave polyhedron.
2D Point Inside-Outside Tests • Convex Polygon Test • Test point has to be on same side of all edges • Concave Polygon Tests • 360 degree angle summation • Compute angles between test point and each vertex, inside if they sum to 360 • Slow, dot product and acos for each angle!
Closest point on a line • Handy for all sorts of things… Pt P2 Pc P1
Spheres as Bounding Volumes • Simplest 3D Bounding Volume • Center point and radius • Point in/out test: • Calculate distance between test point and center point • If distance <= radius, point is inside • You can save a square root by calculating the squared distance and comparing with the squared radius !!! • (this makes things a lot faster) • It is ALWAYS worth it to do a sphere test before any more complicated test. ALWAYS. I said ALWAYS.
Axis-Aligned Bounding Boxes • Specified as two points: • Normals are easy to calculate • Simple point-inside test:
Problems With AABB’s • Not very efficient • Rotation can be complicated • Must rotate all 8 points of box • Other option is to rotate model and rebuild AABB, but this is not efficient
Heirarchical Bounding Volumes • Sphere Trees, AABB Trees, OBB Trees • Gran Turismo used Sphere Trees • Trees are built automagically • Usually precomputed, fitting is expensive • Accurate bounding of concave objects • Down to polygon level if necessary • Still very fast • See papers on-line Approximating Polyhedra with Spheres for Time-Critical Collision Detection, Philip M. Hubbard
Reducing Collision Tests • Testing each object with all others is O(N2) • At minimum, do bounding sphere tests first • Reduce to O(N+k) with sweep-and-prune • See SIGGRAPH 97 Physically Based Modelling Course Notes • Spatial Subdivision is fast too • Updating after movement can be complicated • AABB is easiest to sort and maintain • Not necessary to subdivide all 3 dimensions
Dynamic Particle Simulation • Simplest type of dynamics system • Based on basic linear ODE:
Particle Movement • Particle Definition: • Position x(x,y,z) • Velocity v(x,y,z) • Mass m
Collisions Once we detect a collision, we can calculate new path Use coefficient of resititution Reflect vertical component May have to use partial time step
Contact Force • A force that acts at the point of contact between two objects
Using Particle Dynamics • Each timestep: • Update position (add velocity) • Calculate forces on particle • Update velocity (add force over mass) • Model has no rotational velocity • You can hack this in by rotating the velocity vector each frame • Causes problems with collision response
Particle Init for(i=0; i<num_particles; i++) { particles[i].mass = 1.0; particles[i].color = i%8; for(j=0; j<3; j++) { particles[i].position[j] = 2.0*((float) rand()/RAND_MAX)-1.0; particles[i].velocity[j] = speed*2.0*((float) rand()/RAND_MAX)-1.0; } } glPointSize(point_size);
update void myIdle() { int i, j, k; float dt; present_time = glutGet(GLUT_ELAPSED_TIME); dt = 0.001*(present_time - last_time); for(i=0; i<num_particles; i++) { for(j=0; j<3; j++) { particles[i].position[j] += dt*particles[i].velocity[j]; particles[i].velocity[j] += dt*forces(i,j)/particles[i].mass; } collision(i); } }
collision int i; for (i=0; i<3; i++) { if(particles[n].position[i]>=1.0) { particles[n].velocity[i] = -coef*particles[n].velocity[i]; particles[n].position[i] = 1.0-coef*(particles[n].position[i]-1.0); } if(particles[n].position[i]<=-1.0) { particles[n].velocity[i] = -coef*particles[n].velocity[i]; particles[n].position[i] = -1.0-coef*(particles[n].position[i]+1.0); } }
Helpful Books • Real Time Rendering • Lots of these notes derived from this book • Graphics Gems series • Lots of errors, find errata on internet • Numerical Recipes in C • The mathematical computing bible • Game Programming Gems • Not much on CD, but lots of neat tricks • Lex & Yacc (published by O’reilly) • Not about CD, but useful for reading data files
about PC hardware • Cache Memory • Linear memory access at all costs! • Wasting cycles and space to get linear access is often faster. It is worth it to do some profiling. • DO NOT USE LINKED LISTS. They are bad. • STL vector<T> class is great, so is STL string • vector<T> is basically a dynamically-sized array • vector.begin() returns a pointer to front of array • Conditionals are Evil • Branch prediction makes conditionals dangerous • They can trash the pipeline, minimize them if possible
about C/C++ compilers • Compilers only inline code in headers • The inline keyword is only a hint • If the code isn’t in a header, inlining is impossible • Inlining can be an insane speedup • Avoid the temptation to be too OO • Simple objects should have simple classes • Eg: writing your own templated, dynamically resizable vector class with a bunch of overloaded operators is probably not going to be worth it in the end.
Numerical Computing • Lots of algorithms have degenerate conditions • Learn to use isinf(), isnan(), finite() • Testing for X = 0 is dangerous • If X != 0, but is really small, many algorithms will still degenerate • Often better to test fabs(X) < (small number) • Avoid sqrt(), pow() – they are slow
Physics engine • 2D • Box2D http://box2d.org/ • 3D • bullet3D http://bulletphysics.org • PhysX http://developer.nvidia.com/physx