3D Game Programming interactive and special effect
description
Transcript of 3D Game Programming interactive and special effect
3D Game Programming
interactive and special effect
3D Game Programming
interactive and special effect
Ming-Te ChiDepartment of Computer Science,
National Chengchi University
OutlineOutline
Interactive Graphics (CH12 in 4ed)
Intersection
Particles
INTERACTIVEINTERACTIVE
keyPressed 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 bufferingkey buffering
bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (f
or ascii ) --------------------------------------------------------void keyPressed (unsigned char key, int x, int y) {
keyStates[key] = true; // Set the state of the current key to pressed }
key bufferingkey buffering
void keyOperations (void) { } //--------------------------------------------void display (void) {
keyOperations();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background
… }
gluProject()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()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);
SelectionSelection
Naming Your Primitives///////////////////////////////// Define object names#define SUN 1#define MERCURY 2#define VENUS 3#define EARTH 4#define MARS 5
Planet examplePlanet example
void RenderScene(void){// Clear the window with current clearing colorglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Save the matrix state and do the rotationsglMatrixMode(GL_MODELVIEW);glPushMatrix();
// Translate the whole scene out and into viewglTranslatef(0.0f, 0.0f, -300.0f);
// Initialize the names stackglInitNames();glPushName(0);
// Name and draw the SunglColor3f(1.0f, 1.0f, 0.0f);glLoadName(SUN);DrawSphere(15.0f);
// Draw MercuryglColor3f(0.5f, 0.0f, 0.0f);glPushMatrix();
glTranslatef(24.0f, 0.0f, 0.0f);glLoadName(MERCURY);DrawSphere(2.0f);
glPopMatrix();
Working with selection modelWorking with selection model
glRenderModel()– GL_RENDER– GL_SELECTION– GL_FEEDBACK
// Process the mouse clickvoid 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)void ProcessSelection(int xPos, int yPos)
GLfloat fAspect;
// Space for selection bufferstatic GLuint selectBuff[BUFFER_LENGTH]; //64
// Hit counter and viewport storageGLint hits, viewport[4];
// Setup selection bufferglSelectBuffer(BUFFER_LENGTH, selectBuff);
// Get the viewportglGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and save the matrixglMatrixMode(GL_PROJECTION);glPushMatrix();
// Change render modeglRenderMode(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 directionglLoadIdentity();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 sceneRenderScene();
// Collect the hitshits = 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 matrixglMatrixMode(GL_PROJECTION);glPopMatrix();
// Go back to modelview for normal renderingglMatrixMode(GL_MODELVIEW);}
ProcessPlanet(GLuint id)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;
}}
INTERSECTIONINTERSECTION
What you need to know 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 EquationsPlane Equations
A 3D Plane is defined by a normal and a distance along that normalPlane 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
0),,(),,( dzyxNzNyNx
dPzPyPxNzNyNx ),,(),,( P
(Nx, Ny, Xz)
So where do you start….?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 slowUse bounding volumes to approximate
each object’s real volume
Bounding Volumes 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 cullingFor 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 Tests2D 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 lineClosest point on a line
Handy for all sorts of things…
)()(
)()(
)0(
)0(
111
2
1
2
1
12
ACAB
ABPPPPelse
PPCAifelse
PPBAif
PPC
PPB
PPA
c
c
c
t
t
Pt
P1
P2Pc
Spheres as Bounding VolumesSpheres 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 BoxesAxis-Aligned Bounding Boxes
Specified as two points:
Normals are easy to calculateSimple point-inside test:
),,(),,,( maxmaxmaxminminmin zyxzyx
maxmin
maxmin
maxmin
zzz
yyy
xxx
Problems With AABB’sProblems With AABB’s
Not very efficientRotation 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 VolumesHeirarchical 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 TestsReducing Collision Tests
Testing each object with all others is O(N2)At minimum, do bounding sphere tests
firstReduce 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
PARTICLESPARTICLES
Dynamic Particle SimulationDynamic Particle Simulation
Simplest type of dynamics systemBased on basic linear ODE:
m
f
dt
dv
dt
dxv
dt
xd
m
f
dt
xda
maf
:rt timeposition w of derivative isvelocity
: is force todueon Accelerati
2
2
2
2
Particle MovementParticle Movement
Particle Definition:– Position x(x,y,z)– Velocity v(x,y,z)– Mass m
m
ftvv
tvpp
fffft
ttt
tttt
zyx
),,( force and epFor timest
CollisionsCollisions
Once we detect a collision, we can calculate new path
Use coefficient of resititutionReflect vertical componentMay have to use partial time step
32
Contact ForceContact Force
A force that acts at the point of contact between two objects
33
Using Particle DynamicsUsing 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 InitParticle 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);
updateupdatevoid 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); }}
collisioncollisionint 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 BooksHelpful 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 tricksLex & Yacc (published by O’reilly)
– Not about CD, but useful for reading data files
about PC hardwareabout 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++ compilersabout 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 speedupAvoid 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 ComputingNumerical 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 enginePhysics engine
2D– Box2D http://box2d.org/
3D– bullet3D http://bulletphysics.org– PhysX http://developer.nvidia.com/physx