Thread: gravity: jittery camera.

  1. #1
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071

    gravity: jittery camera.

    Iv'e added a gravity function to start off my physics engine, however it produces a result that nicely simulates an earthquake.

    Code:
    vector3d generic::gravity(vector3d pos, vector3d dir, vector3d v)
    {	
    	if(_ceCollision->checkcollision(pos)==false)
    	{
    		speed = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
    		v.x += (((dir.x*(9.81))/233.3333333)-(glbAirRes*v.x*speed))*dt;
    		v.y += (((dir.y*(9.81))/233.3333333)-(glbAirRes*v.y*speed))*dt;
    		v.z += (((dir.z*(9.81))/233.3333333)-(glbAirRes*v.z*speed))*dt;
    		
    		pos = v;
    	}
    	else
    	{
    		speed = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
    		v.x += (((dir.x*(9.81))/233.3333333)-(glbAirRes*v.x*speed))*dt;
    		v.y += (((dir.y*(9.81))/233.3333333)-(glbAirRes*v.y*speed))*dt;
    		v.z += (((dir.z*(9.81))/233.3333333)-(glbAirRes*v.z*speed))*dt;
    
    		pos.x = -v.x;
    		pos.y = -v.y;
    		pos.z = -v.z;
    	}
    	
    	return pos;
    }
    The jittering is caused by the code in bold I believe; that is, the pushing back of the position on a collision. The problem is, I don't know how to fix it.

    thanx
    -psychopath
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I don't know . . . but a double has more presicion than this: 233.3333333.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3

    Join Date
    May 2005
    Posts
    1,042
    What the hell are you trying to do in your code?
    I'm not immature, I'm refined in the opposite direction.

  4. #4
    Registered User
    Join Date
    Jan 2002
    Location
    Vancouver
    Posts
    2,212
    Don't push back after a collision, predict a collision before it happens.

  5. #5
    vae victus! skorman00's Avatar
    Join Date
    Nov 2003
    Posts
    594
    you don't want to just push back, you want to push back by the pentration depth of the collision. That's not the same as negating v.

  6. #6
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071
    Well. Its quite clear to me now that I need a book on game physics more than I thought at first.
    >>Don't push back after a collision, predict a collision before it happens.<<
    &
    >>you don't want to just push back, you want to push back by the pentration depth of the collision. That's not the same as negating v.<<
    I'm not even going to ask you to explain how to do these things. I'm just gonna get a book .

    >>I don't know . . . but a double has more presicion than this: 233.3333333.<<
    233.3333333 is a number I came up with to keep things at a reasonable speed. Don't ask me how I got it. I can't remember.
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

  7. #7

    Join Date
    May 2005
    Posts
    1,042
    Your code is very confusing. I see what you are trying to do (I've implemented the same thing before) but I'm willing to bet money there are bugs, on top of you not being familiar with the algorithm.

    In general, it's best to test for a ray/plane intersection to predict the point of collision before penetrating the surface. Once you've got the general idea implemented you will have to work around floating point inaccuracies, else you'll fall through the world with code that appears to have been implemented correctly.

    To give you a start, here is some code I wrote to determine if a point lies inside a triangle. It hasn't been rigourously tested yet. Basic idea on how to do this:

    1_ Compute your start point and endpoint for the frame (where you currently are and where you'd like to go). I like to extrapolate the length of the move a little bit.

    2_ For every item you wish to collide against (in this case a polygon soup of triangles) determine where the ray formed by the start point and end point intersects the current plane (if it doesn't, continue to the next polygon).

    3_ Determine whether or not the plane intersection lies inside the current triangle. If the time that you collided with this polygon is less than the currently stored time of intersection, replace the time of intersection with the current one.

    I left out a LOT of details.

    Code:
    //Fixme: investigate to see how vector length plays into uncertainty here
    //Normal x DiffVector = InwardVector
    //InwardVector Dot Point >= 0 or >= -.0001
    BOOL	CCWPointInTri(float	P1X,float	P1Y,float	P1Z,
    					  float	P2X,float	P2Y,float	P2Z,
    					  float	P3X,float	P3Y,float	P3Z,
    					  float	NormalX,float	NormalY,float	NormalZ,
    					  float	PointX,float PointY,float	PointZ)
    {
    	Vector3	Point1(P1X,P1Y,P1Z);	Vector3	Point2(P2X,P2Y,P2Z);	Vector3	Point3(P3X,P3Y,P3Z);
    	Vector3	Normal(NormalX,NormalY,NormalZ);
    	Vector3 Point(PointX,PointY,PointZ);
    	Point -= Point1;	//Translates to local coordinates
    
    	Vector3	DiffVector	=	Point2 - Point1;
    	Vector3	InwardVector(0,0,0);
    	InwardVector	=	CrossProduct(&Normal,&DiffVector);
    
    	if(DotProduct(&InwardVector,&Point)< -.0001)
    		return	FALSE;
    
    	DiffVector	=	Point3 - Point2;
    	InwardVector	=	CrossProduct(&Normal,&DiffVector);
    	if(DotProduct(&InwardVector,&Point)< -.0001)
    		return	FALSE;
    
    	DiffVector	=	Point1 - Point3;
    	InwardVector	=	CrossProduct(&Normal,&DiffVector);
    	if(DotProduct(&InwardVector,&Point)< -.0001)
    		return	FALSE;
    
    	return	TRUE;
    }
    Just to give you a very basic idea of how that code is supposed to work, here's a picture. The red lines are the unnormalied inward facing vectors (they need not be normalized). If a point that is on the same plane as the triangle is in front of each of these inward facing vectors (the dotproduct between the point and the inward facing vector is greater than 0) then the point in question is inside the triangle.
    Last edited by BobMcGee123; 07-30-2005 at 10:37 AM.
    I'm not immature, I'm refined in the opposite direction.

  8. #8
    vae victus! skorman00's Avatar
    Join Date
    Nov 2003
    Posts
    594
    >>Don't push back after a collision, predict a collision before it happens.<<
    &
    >>you don't want to just push back, you want to push back by the pentration depth of the collision. That's not the same as negating v.<<
    I'm not even going to ask you to explain how to do these things. I'm just gonna get a book .
    Too bad, I'm gonna explain them anyway!!! By predicting it, I believe Brian was trying to say something like: Next frame, object A will be here, which will mean there will be a collision with object B. move it next to object B instead of inside of it. Which is also what I was getting at. Since you don't have the luxury of going at the speed of true real time, you have to make up for some of the time loss.

    Using the nifty method BobMcGee showed you up there, you may be able to figure out where the collision exactly happened, depending on how you're handling your objects. When you do find that out, you can either just move that object to that point, or subtract that points position from the colliding objects theoretical position (meaning where it would be if collisions didn't exists) to get the "penetration depth." Then you can move the object back by that depth.

    My book recommendation: Mathematics for 3D Game Programming and Computer Graphics. Very heavy, and some sections will require 3-4 read overs. I needed to anyway.

  9. #9
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071
    hmm, I think I get it...but probably not. Could something similar to this work?
    Code:
    vector3d nextpos;
    vector3d currentpos;
    vector3d nextpoint;
    vector3d v = 0;
    
    calculatevelocity(vector3d lastv, vector3d dir)
    {
       speed = sqrt(lastv.x*lastv.x + lastv.y*v.y + lastv.z*v.z);
       v.x += (((dir.x*(9.81))/233.3333333)-(glbAirRes*v.x*speed))*dt;
       v.y += (((dir.y*(9.81))/233.3333333)-(glbAirRes*v.y*speed))*dt;
       v.z += (((dir.z*(9.81))/233.3333333)-(glbAirRes*v.z*speed))*dt;
    
       return v;
    }
    
    gravity(vector3d dir)
    {
       v = calculatevelocity(v, dir);
       vector3d nextpos = currentpos+v;
       if(_ceCollision->check(nextpos))
       {
           nextpoint = _ceCollision->collisionpoint(nextpos, false);
           pos = nextpoint-v;
       }
       return pos;
    }
    -psychopath
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Just to give you a very basic idea of how that code is supposed to work, here's a picture. The red lines are the unnormalied inward facing vectors (they need not be normalized). If a point that is on the same plane as the triangle is in front of each of these inward facing vectors (the dotproduct between the point and the inward facing vector is greater than 0) then the point in question is inside the triangle.
    Just because the dot product works out does NOT mean the point in question is inside of the triangle. What it does mean is that you know which side of the triangle the point is on, but this does NOT mean the point lies in the same plane as the triangle.

    The actual process of computing whether or not the point in question is inside of the triangle involves computing the barycentric coords of the point in relation to the triangle. What the dot product will tell you quickly is whether or not the point is colliding or will collide with the triangle - given the current velocity vector and position of the triangle in question. However, much more is needed to actually compute whether or not the point is inside of the triangle.

    Sometime back I posted a huge thread which contained source code to compute the point of intersection between a ray and a triangle. Now even though you are not testing a ray and triangle there is a portion of the code which computes the barycentric position of the point at which the ray intersects the triangle. This code can be converted to discard the ray and simply compute whether or not the point lies inside of the triangle.

    Perhaps I'm mistaken here, but more is needed than just the dot product.

    And on a side note using any old floating point value to get the frames per second to work out is tying your program to one specific platform and one specific clock speed. This code would fail miserably on another machine with different clock speeds. Instead of using constants what you need to do is base all of your movements and physics off of time - in other words a computer running at 1GHz and one runnning at 3GHz would produce the same animation speed or the same simulation speed - to a certain point. The 3GHz computer will process the information more quickly, but the game will run just about identical on both machines. I'm talking about actual game mechanics and not just frame rates or rendering speeds. If a car moves 100ft in 1 second on super slow computer A then it had better do the same on super computer B and vice versa.
    Last edited by VirtualAce; 07-30-2005 at 09:00 PM.

  11. #11

    Join Date
    May 2005
    Posts
    1,042
    EDIT: I re-read your post, and it seems you don't even understand that the math involved in the code I posted produces vectors that point towards the middle of the triangle. I originally assumed you understood at least that much and your only complaint was that I glossed over the actual calculation of how the ray intersects the triangle plane (the easiest and most intuitive part of the algorithm)....maybe you are confused because there is no plane distance value? The reason for that is that everything becomes centered around the origin. I really just don't know where in the hell you are coming from.
    /EDIT

    Bubba you are 100% mistaken and it is because you are too quick to try to correct me without reading what I said. I admitted to leaving a lot out, but I specifically mentioned calculating where the ray intersects the triangle plane. My method works, I've used it before, and for triangle intersections nothing else is faster* (only uses vector multiplies, no trig or sqrting).

    2_ For every item you wish to collide against (in this case a polygon soup of triangles) determine where the ray formed by the start point and end point intersects the current plane (if it doesn't, continue to the next polygon).

    3_ Determine whether or not the plane intersection lies inside the current triangle.

    The basic idea behind plane surfing:

    You take the dotproduct between the start point and the end point with respect to the plane normal, minus the plane distance, store it in (startdist and enddist)**. If this is a polygon collision test, the start point must be in front (positive) and the end point must be behind (negative). If they both have the same sign (another place to write in numerical tolerances!) you can continue to the next polygon.

    To get the intersection point, compute a value between 0 and 1 used as an interpolator. This is the ratio of the absolute values of abs(startdist) and (abs(startdist) + abs(enddist))...this is also the time variable I mentioned above.

    Code:
    float i_total_dist = 1/(fabs(startdist) + fabs(enddist)); //start should be positive but i throw in fabs just for uniformity here
    float collision_frac = fabs(startdist) * i_total_dist; //for speed and ease of readability for me
    
    Vector CollisionPoint = StartPoint + ((EndPoint - StartPoint) * collision_frac);
    That is the basic idea of how to get the point where the ray intersects the triangle's plane. Then, you perform the test using the code I posted above to determine whether or not it actually resides inside the triangle. Iteratre through all of the polygons in the soup of possible collision hulls, storing the closest time of collision.

    In a practical implementation you also need to throw in an epsilon, and check to make sure that the collision_frac is clamped between 0 and 1:
    Code:
    float i_total_dist = 1/(fabs(startdist) + fabs(enddist)); //start should be positive but i throw in fabs just for uniformity here
    float collision_frac = (fabs(startdist) - EPSILON) * i_total_dist; //for speed and ease of readability for me
    
    Vector CollisionPoint = StartPoint + ((EndPoint - StartPoint) * collision_frac);


    .03125 (1/32) is a good epsilon
    *this isn't entirely true, because you can precompute the inward facing plane normals: speed for an increased memory footprint...but it is still ultimately using the same method.

    **If it's a sphere, then you do:
    startdist = dotproduct(Plane.normal,StartPos) - PlaneDist - SphereRadius.

    If it's a bounding box you find the vectors which go most against the plane normal:
    Code:
    		Vector3	VecEff;
    		
    		Vector3	maxs = mBSPColInfo.mfCurrMaxs;
    		Vector3	mins = mBSPColInfo.mfCurrMins;
    
    		if(plane->vNormal.x < 0)
    			VecEff.x = maxs.x;
    		else
    			VecEff.x = mins.x;
    
    		if(plane->vNormal.y < 0)
    			VecEff.y = maxs.y;
    		else	
    			VecEff.y = mins.y;
    
    		if(plane->vNormal.z < 0)
    			VecEff.z = maxs.z;
    		else
    			VecEff.z = mins.z;
    		
    		//You can safely add offset, because the effective vector goes AGAINST the plane normal and will
    		//subsequently always be negative
    		float	offset = DotProduct(&plane->vNormal, &VecEff);
    		
    		float	sd	=	DotProduct(&plane->vNormal, &mBSPColInfo.BSPStart) - plane->d + offset;// b;
    		float	ed	=	DotProduct(&plane->vNormal, &mBSPColInfo.BSPEnd) - plane->d + offset;// b;
    Last edited by BobMcGee123; 08-01-2005 at 01:35 AM.
    I'm not immature, I'm refined in the opposite direction.

  12. #12
    vae victus! skorman00's Avatar
    Join Date
    Nov 2003
    Posts
    594
    Code:
       v = calculatevelocity(v, dir);
       vector3d nextpos = currentpos+v;
       if(_ceCollision->check(nextpos))
       {
           nextpoint = _ceCollision->collisionpoint(nextpos, false);
           pos = nextpoint-v;
       }
    You'll probably have to send currentpos to that _ceCollision->check() function. If you're dealing with fast objects, the displacment can be much greater than the size of the object...ever play a game where you can go through a wall if you go fast enough? Well, that's why. Also, I'm not sure why you would want to subtract v from nextpoint...I would think that nextpoint is right where you want to be. Instead of v, you may want half of that objects width, assuming that all your positions are the center of the objects.

  13. #13
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071
    hmm, so It would look like this?
    Code:
       v = calculatevelocity(v, dir);
       vector3d nextpos = currentpos+v;
       if(_ceCollision->check(currentpos))
       {
           nextpoint = _ceCollision->collisionpoint(?, false);
           pos = nextpoint-2.0f;
       }
    where I put the bolded ?, would that be the nextpos or currentpos? (function returns the collision point for the given argument)

    -psychopath
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

  14. #14
    vae victus! skorman00's Avatar
    Join Date
    Nov 2003
    Posts
    594
    you would want both. You'll use both points in order to work with the path the object followed in between frames. Please let me know if you're not sure why that is, because it's hard for me to explain that without visualization. I'm not sure what that bool is for though, but I'm sure you have it under control.

  15. #15
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Interpolating to find a point of intersection is not what I would do. There are several ways to go about this but the simple ray to triangle intersection test will do the trick nicely. Find the point of intersection or more importantly find the interval in which the intersection takes place. Don't just test the raw geometry because that will certainly cause interpenetration. Find the interval of time where the two objects definitely will collide. If the interval comes up as infinite then you know they will not collide in the next frame. If they interpenetrate then 'back-up' to the point of intersection and then fire off the physics code to correctly calculate the impulses.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. camera rotation matrix
    By Vick jr in forum Game Programming
    Replies: 5
    Last Post: 05-26-2009, 08:16 AM
  2. LNK2001 ERROR!!! need help
    By lifeafterdeath in forum C++ Programming
    Replies: 7
    Last Post: 05-27-2008, 05:05 PM
  3. Problems moving the camera
    By Mavix in forum Game Programming
    Replies: 8
    Last Post: 01-30-2008, 12:52 PM
  4. RTS camera movement
    By blurrymadness in forum C++ Programming
    Replies: 0
    Last Post: 04-22-2007, 10:37 PM
  5. Camera rotation/movement in 3D world
    By tegwin in forum Game Programming
    Replies: 11
    Last Post: 01-24-2003, 01:43 PM