physics simulation problems

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
fisk
Posts: 9
Joined: Sun Jan 07, 2007 11:11 am

physics simulation problems

Post by fisk »

Im working on a simple billiard simulator and have run into some issues.

1st issue is that even though Im limiting the fps to avoid division by zero later and also using the time it took to render last frame as an appoximation for the timestep used in the eulers, the velocity still seems to shift as I change the fps limit. this is quite bothersome as I want the simulation to count over time and not frames.

2nd issue is that the rotation changes randomly it seems. started out trying to compute it with quarternions but never got it working at all so cut it down to this simplified version depending on the translation. this got them rotating and most of the balls look good except for a few that starts spinning in the wrong direction, same effect as a backspin which isnt implemented.


Im afraid Ive stared myself blind on them. any help would be greatly appriciated.

#MAIN.CPP

Code: Select all

std::vector<rigidBody> bodies;
std::vector<scene::ISceneNode*> spheres;

std::vector<rigidBody>::iterator iterRB;
std::vector<scene::ISceneNode*>::iterator iterSP;

u32 timeStart, timeEnd, timeElapsed, timePerFrame = 5, framecount = 0;

while( device->run() )
{
	framecount++;
	timeElapsed = device->getTimer()->getTime() - timeStart;
	timeStart = device->getTimer()->getTime();

	*dtPointer = timeElapsed/1000.0f;
	if (framecount == 1)
		{ *dtPointer = timePerFrame/1000.0f; }

	runSimulation(bodies.begin(), bodies.end(), dtPointer);

	iterRB = bodies.begin();
	iterSP = spheres.begin();

	do {
		(*iterSP)->setPosition((*iterRB).x);
		(*iterSP)->setRotation((*iterRB).o);
		(*iterRB).forces.clear();

		if ((*iterRB).v.getLength() < 0.01)
		{
			(*iterRB).v = vector3df(0.0f, 0.0f, 0.0f);
			(*iterRB).w = vector3df(0.0f, 0.0f, 0.0f);
		}
		else { computeFriction( iterRB, dtPointer ); }

		iterRB++;
		iterSP++;

	} while ( iterRB != bodies.end() && iterSP != spheres.end() );

	iterSP = spheres.begin();
	iterRB = bodies.begin();
	do {
		if ((*iterRB).v != vector3df(0.0f, 0.0f, 0.0f))
		{
			iterSPCompare = spheres.begin();
			iterSPCompare++;
			iterRBCompare = bodies.begin();
			iterRBCompare++;

			do {
				if (iterSPCompare != iterSP && (*iterRB).forces.size()==1)
				{
					distance = (*iterSP)->getPosition().getDistanceFrom((*iterSPCompare)->getPosition());

					if( distance < radius*2 )
					{
						F = collisionForce(iterRB,iterRBCompare, dtPointer);

						(*iterRB).forces.push_back( force(F , vector3df(0.0f,0.0f,0.0f)) );
						(*iterRBCompare).forces.push_back( force(-F, vector3df(0.0f,0.0f,0.0f)) );
					}
				}
				iterSPCompare++;
				iterRBCompare++;
			} while (iterSPCompare != spheres.end() && iterRBCompare != bodies.end());
		}
		iterSP++;
		iterRB++;
	} while ( iterRB != bodies.end() && iterSP != spheres.end() );

	if ( device->isWindowActive() )
	{
		if (driver->beginScene(true, true, video::SColor(0,255,255,190)))
		{
			smgr->drawAll();
			guienv->drawAll();
			driver->endScene();
		}

		timeEnd = device->getTimer()->getTime();
		timeElapsed = timeEnd - timeStart;
		if (timeElapsed < timePerFrame)
		{
			Sleep(timePerFrame - timeElapsed);
		}
	}
}
device->drop();
#SIMULATION.H

Code: Select all

void runSimulation (std::vector<rigidBody>::iterator sim_iter_begin, std::vector<rigidBody>::iterator sim_iter_end, f32 * dtPointer) 
{
	while (sim_iter_begin != sim_iter_end) 
	{          	
		computeForceAndTorque( &(*sim_iter_begin) );
		computeAcceleration( &(*sim_iter_begin) ); 	

		euler( &(*sim_iter_begin), dtPointer );
	      
		sim_iter_begin++;
	}
}

void euler (rigidBody *rb, f32 * dtPointer)  // THE MIGHTY EULER
{ 
	rb->v = rb->v + rb->a*(*dtPointer);
	rb->x = rb->x + rb->v*(*dtPointer);
	rb->o = rb->o + rb->w*(*dtPointer);
	
	if (rb->o.X < -180) rb->o.X += 180;
	if (rb->o.X > 180)  rb->o.X -= 180;		
	if (rb->o.Y < -180) rb->o.Y += 180;
	if (rb->o.Y > 180)  rb->o.Y -= 180;			
	if (rb->o.Z < -180) rb->o.Z += 180;
	if (rb->o.Z > 180)  rb->o.Z -= 180;
}
#PHYSICS.H

Code: Select all

class force 
{
	public:
	vector3df r, f; 
	 			
	force (vector3df initF, vector3df initR) 
	{
		f = initF;	//force
		r = initR;	//distance from mass centre
	}
};

class rigidBody 
{
	public:
	
   	float m; 		// mass
   	matrix4 IbodyInv;	// inertia tensor

	// State variables
	vector3df x; 		// position
	vector3df o;		// orientation
   
	// Derived quantities
	vector3df v; 		// speed
	vector3df a;		// acceleration
	vector3df w;		// angular velocity

	// Computed quantities
	vector3df F; 		// total force acting on a body
	vector3df T;		// total torque acting on a body
	std::vector<force> forces; // list of forces acting on the body


	rigidBody (vector3df position) 
	{
		x = position;
		m = 0.17;
	}
   
};

void computeForceAndTorque(rigidBody *rb) 
{
	rb->F.set(0.0f,0.0f,0.0f);
	rb->T.set(0.0f,0.0f,0.0f);
	
	std::vector<force>::iterator force_iter;
	force_iter = rb->forces.begin();

	if ( rb->forces.size() != 0)
	{
		do {
			if( (*force_iter).r == vector3df(0.0f, 0.0f, 0.0f) )
			{ 
				rb->F = rb->F + (*force_iter).f; 
			}

			if( (*force_iter).r != vector3df(0.0f, 0.0f, 0.0f) )
			{
				rb->T = rb->T + (*force_iter).r.crossProduct( (*force_iter).f);
			}
		        force_iter++;
        	} while ( force_iter != rb->forces.end() );
	}
}

void computeAcceleration (rigidBody *rb) 
{ 		
	rb->a = (rb->F / rb->m);
}
Post Reply