Archived

This topic is now archived and is closed to further replies.

ms291052

World Mesh Collisions

Recommended Posts

ms291052    223
I''m using a .x file as my world geometry and have been having trouble with my collision detection. As of now I have been calling D3DXIntersect just before updating the CameraPos each frame to make sure the camera would still be inside the world mesh. If it is, I move the camera, otherwise I set velocity to (0,0,0)
bool PointInRoom(D3DXVECTOR3 pos)
{
	D3DXVECTOR3 up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	BOOL bHit;
    DWORD dwFace;
    FLOAT fBary1, fBary2, fDist;
	DWORD count;
	D3DXIntersect(g_Room.Mesh.m_pMesh, &pos, &up, &bHit, &dwFace, &fBary1, &fBary2, &fDist, 0, &count);
	if(count%2) return true;
	else return false;
	return 1;
}
...
float vmag = MagnitudeSq(g_Player.GetVelocity());
		D3DXVECTOR3 pos;
		if(vmag == 0)
			pos = g_Player.GetPosition();
		else
			pos = (g_Player.GetPosition() + (g_Player.GetVelocity()/sqrtf(vmag))*g_Player.radius);
		if(!PointInRoom(pos))
		{
			g_Player.SetVelocity(Origin);
		}
The only problem is that it''s very unreliable in terms of where the camera/player actually stops. I''m trying to do collision detection between the Geometry Mesh and the sphere of the g_Player object (g_Player.radius). Problem 1: I''ve found that sometimes the player stops moving anywhere between 1E-4 to 3.5 units away from the mesh (the g_Player radius is roughly 2.4). Problem 2: Whenever the velocity gets going fast enough the player actually stops farther away from the surface (I achieved absolutely insane distances by setting the gravity skyhigh). Also if I use exponential gravity (i.e. -9.8 ms^-2) the stopping distance is terrible. If anyone could help me fix these two problems, or point me in the direction of any Mesh-Mesh collision, Mesh-Sphere collision, or other sources that may apply in the least I would be greatful.

Share this post


Link to post
Share on other sites
Shyrakai    122
(Part of?) the problem is that, the faster you are moving, the more distance you cover between time T and time (T + 1). I realize that is obvious, but the result in this case is that your current algorithm can end up stopping things as far from the edge of the world as
(magnitude_of_velocity * position_update_time_increment)
which is obviously going to be higher with higher velocities.

Assuming you don''t change much else, I would suggest that you make your processing of the "if(!PointInRoom(pos))" condition more sophisticated. If you determine that moving the character one increment using their current velocity would place them outside of the world, then in addition to cancelling their velocity you need to move them as close to the edge of the world as you want them to be. I don''t know what all of your options are for doing this (it is easy if you can calculate your current distance from the edge of the world), but one brute-force approach that only uses the information you already have is given below. (Note that this is pseudocode, so don''t try to compile it, and there is almost _guaranteed_ to be a more efficient solution using information other than whether a point is in the world or not, and I took out your multiplication by player radius because it doesn''t make sense to me. Also, I''m assuing that the velocity vector is in units of distance-per-position-update, not distance-per-second.)

if (!PointInRoom(pos)) {
D3DXVECTOR3 tmp_velocity = g_Player.GetVelocity();

/*
* if we''ve left the room, keep halving velocity and moving
* towards the edge of the room until we''re inside with
* velocity less than the player radius
*/
do {
/* if moving in increments >= radius, halve the velocity) */
if (Magnitude(tmp_velocity) >= g_Player.radius) {
tmp_velocity /= 2.0;
}

/* move toward edge of room from wherever we are */
if (PointInRoom(pos)) {
pos += tmp_velocity;
} else {
pos -= tmp_velocity;
}
} while ((Magnitude(tmp_velocity) >= g_Player.radius) ||
!PointInRoom(pos));

g_Player.SetVelocity(Origin);
}

g_Player.SetLocation(pos);

Share this post


Link to post
Share on other sites