Mesh.Intersect help

Started by
4 comments, last by __Daedalus__ 19 years, 9 months ago
Hello, I'm using Mesh.Intersect to get the terrain height below my character. Basically, it creates a ray originating at the player, and casts down. The returning intersect information is used to determine a collision with the terrain. This is something I've been working on longer than I care to admit. I hate it. And I hate trying to figure it out day after day. So please, if you know the answer, speak up. :) First, sure, it appears my intersect is working. It gives an intersect distance. But -- it doesn't follow the terrain accurately. It's almost like my character (airplane in this case) and the originating ray are in different places and it's driving me up a wall. The Mesh.Intersect method requires 2 vector3s. One is the origin, one is the direction of the ray. Basically, I put my origin in untransformed coordinates (assuming Mesh.Intersect works in object space). But no matter what I try, I can't get this to work. If my plane is at X: 5000, Y: 300, Z: 1 (before transforming), wouldn't that coorespond to the same X,Y,Z in object space? How are meshes organized? Like this? [100.....-100] Z 100 [............] [............] [... 0 ...] [............] [............] [100.....-100] Z -100 I mean in order of coordinates. Is 0 the center? Thanks. Terribly frustrated and burned out.
Advertisement
Assuming that your terrain mesh vertices are already in world space, my guess is that your ray isn't being specified properly.

---------------------------Hello, and Welcome to some arbitrary temporal location in the space-time continuum.

Hi Etnu.

Okay, I'm confused then. I assumed that a world transform just positioned the world in the right place to render the mesh. I didn't think that the mesh's data actually got transformed permantently.

For example:

You have a single terrain mesh. But you want to tile this mesh in world space.

So you do this: device.Transform.World(Matrix.Translate(0, 0, 0));

Then you render your mesh (which puts it in the center of the world).

To put the same mesh next to the first one, you call another Transform.World. This time putting it at 10, 0, 0).

And again, render the same mesh object.

I thought that with each transform, the mesh was translated from object space to world space. Not

But does this actually change the mesh's coordinates? I thought it just moved/rotated/whatever the world and the mesh's intrinsic coordinates remained unchanged.

Okay, if that's incorrect. How do I get transformed coordinates for my postion vector for the Mesh.Intersect.

Right now I'm using:

Mesh.Intersect(new Vector3(planeX, planeY, planeZ), new Vector3(0, -1, 0));

I'd need transformed coordinates for planeX, planeY, and planeZ.

The body coordinates of your meshes do not change permanently when you set a world transformation matrix - they are referenced. Incidentally, you must build all of your meshes around the origin (0,0,0) before exporting them from your modeler. Ok, with that out of the way...

You must specify your test ray in world coordinates. It is preferable to specify a test ray start position and a test ray end position rather than the direction normal though, OK! If the mesh you are testing the ray against (e.g. a terrain segment) is not around the origin then you must also specify the world transformation matrix you are using to position the mesh. The reason is you have to transform your test ray origin (which you specify in world coordinates) by the inverse of this world matrix to move the ray in to the mesh's body space for testing.

OK, with this in mind, you could desing a function that has the prototype:

BOOL CheckIntersectObject( ID3DXMesh* Mesh, D3DXVECTOR3* TestRayStart, D3DXVECTOR3* TestRayEnd, float* Length, D3DXMATRIX* ObjWorldMat = NULL );

The implementation will look like this

BOOL CheckIntersectObject( ID3DXMesh* Mesh, D3DXVECTOR3* TestRayStart, D3DXVECTOR3* TestRayEnd, float* Length, D3DXMATRIX* ObjWorldMat ){	BOOL		Hit;	float		u, v, Dist;	float		XDiff, YDiff, ZDiff, Size;	DWORD		FaceIndex;	D3DXVECTOR3 vecDirection;    D3DXVECTOR3 vecOrigin;    D3DXMATRIX  matInverse;	D3DXMatrixIdentity( &matInverse );	XDiff = TestRayEnd.x - TestRayStart.x;	YDiff = TestRayEnd.y - TestRayStart.y;	ZDiff = TestRayEnd.z - TestRayStart.z;    vecOrigin.x		= TestRayStart.x;    vecOrigin.y		= TestRayStart.y;    vecOrigin.z		= TestRayStart.z;    vecDirection.x	= XDiff;    vecDirection.y	= YDiff;    vecDirection.z	= ZDiff;    	// If the mesh to test hase a world transformation matrix	// inverse it here.	if( ObjWorldMat != NULL ) {        D3DXMatrixInverse( &matInverse, NULL, ObjWorldMat );	}    	// Transform the test ray origin and direction vector in to	// the body space of the mesh	D3DXVec3TransformCoord( &vecOrigin, &vecOrigin, &matInverse );    D3DXVec3TransformNormal( &vecDirection, &vecDirection, &matInverse );        	D3DXVec3Normalize(&vecDir, &vecDir);		// Do intersection test	D3DXIntersect( Mesh, &vecOrigin, &vecDirection, &Hit, &FaceIndex, &u, &v, &Dist, NULL, NULL);	if( Hit == TRUE ) 	{		Size = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);    		if( Dist > Size )			Hit = FALSE;		else 		{			if(Length != NULL)				*Length = Dist;		}	}		return Hit;}


This method returns TRUE is a hit happened with the mesh and puts the distance in the specified "length" variable. So if the terrain segement you are testing is the one around the origin you would call it without a matrix like this:

float Distance = 0.0f;BOOL Hit = FALSE;Hit = CheckIntersectObject( TerainMesh, &D3DXVECTOR3(5000.0f,300.0f,1.0f), &D3DXVECTOR3(5000.0f,-1000.0f,1.0f), &Distance );


Where as if you are testing an oriented terrain segment, you would have to include the world transformation matrix you are using to orient the segment in the function call. Like this:

float Distance = 0.0f;BOOL Hit = FALSE;D3DXMATRIX matTerrainSegmenPos;D3DXMatrixIdentity( &matTerrainSegmenPos );D3DXMatrixTranslation( &matTerrainSegmenPos, 10.0f, 0.0f, 0.0f );Hit = CheckIntersectObject( TerainMesh, &D3DXVECTOR3(5000.0f,300.0f,1.0f), &D3DXVECTOR3(5000.0f,-1000.0f,1.0f), &Distance, &matTerrainSegmenPos );

Also, you can see in that function call the end of the test ray is just a stupidly low position directly below the ray origin.

Hope that helps.

[Edited by - __Daedalus__ on July 26, 2004 5:16:42 PM]
Daedalus,

I really appreciate the time and effort you put in to that reply. I got similar results using your methods so I knew it had to be something else.

It turns out my ray coordinates were reversed making the collision detection 100% wrong in every direction. Once I corrected that, I got correct collisions.

And I'm much, much happier. :)

Thanks again. You'll no doubt be hearing from me again when I try to implement something else above my level.
Good stuff!

This topic is closed to new replies.

Advertisement