Skip to main content
GameDev.net gamedev.net
🔒 Locked

DirectX COLLISION DETECTION

Started by GENTS Jul 3, 2004 at 8:15 AM 44 replies 19.9k views
Original Post
GENTS
GENTS
I've tried with D3DXIntersect() and with a CD Library (http://users.volja.net/fajrvehr/) but I can't find the right way to detect collisions! I'm also a problem with my code... After I load my mesh and move and rotate in the 3D space, I lock Vertex and Index buffers to find vertex positions, face normals, etc... but I've always .X file vertex positions and not moved or rotated... How can I find this new positions?! Where it's possible that I'm wrong?! and also: How can I divide my Level-mesh in different parts so that I can compute different bounding boxes or spheres for walls, chairs, doors, windows, etc ?!?! I hope that you that are a DirectX MASTER could help me to find a collision detection soluton.... THANKS A LOT!!! [Edited by - GENTS on July 10, 2004 9:46:05 AM]
superpig
superpig
DirectX is not, nor was it ever, something aimed at handling collision detection.

There's a *huge* array of techniques out there that cover CD. You might want to start by looking into BSPs or Octrees. That's the "dividing your level mesh up" that you mentioned.

Also, being given the untransformed positions when you lock the .X file buffer is completely normal behavior. Direct3D transforms a copy of each vertex when you render - it doesn't touch the buffer itself (unless you're telling it to, but that's a different operation). So the vertex positions, stored in the buffer, never change.

Just how much detail do you want in your collision detection? The approach you'll frequently see used is to maintain two sets of data - one for rendering (with tex coords, positions, normals, etc etc), and one for collision detection (just positions, and it may have fewer triangles, sorta thing).
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
tomek_zielinski
tomek_zielinski
If you use d3dxintersect, your mesh isn't transformed by world transform.

if you want to use it, tranform your ray(starting end ending point) by world tranform and use transformed ray.

it sholud work
www.tmreality.com
GENTS
GENTS
Thanks for replies...

Quote:
Original post by tomek_zielinski
tranform your ray(starting end ending point)


How can I tranform my ray?! Using D3DXVec3TransformCoord()?!

Quote:
Original post by superpig
The approach you'll frequently see used is to maintain two sets of data - one for rendering (with tex coords, positions, normals, etc etc), and one for collision detection (just positions, and it may have fewer triangles, sorta thing).


I'm trying to do exactly what you've said!!! But How can I manage vertex buffer to find vertex' positions every frame?!

If I've my collision vertex originary position... How can I trasform their position?! Should I mul for a sort of transformation matrix or should I copy renderable vertex positions in my collision vertex coords?! Or exist another way?!

THANKS FOR REPLIES!!!
tomek_zielinski
tomek_zielinski
Yes extacly -> D3DXVec3TransformCoord()

If you set world transform to M, the it's just like you would tranform your ray by inverse of M(D3DXMatrixInverse).

So

SetTransform( d3dts_world, &m);
D3DXMatrixInverse( &m_inv, &m );
D3DXVec3TransformCoord( &v1_tr, &v1, &m_inv );
D3DXVec3TransformCoord( &v2_tr, &v2, &m_inv );

it should work if i haven't overlooked sth.
www.tmreality.com
paranoia33
paranoia33
That worked great for me!! exept that D3DXMatrixInverse takes 3 arguments...the second 1 is not needed for this and is just set to null. So ti would be

D3DXMatrixInverse( &m_inv,NULL,&m );

/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/Current Projects:PEngine - Full 3d FPS engine
tomek_zielinski
tomek_zielinski
Quote:
Original post by GENTS
Ok..
Now I'll try D3DXIntersect() for my collisions test...

But doesn't exist a more rapid implementation of that function?!

Is more rapid D3DXIntersectTri() ?!



more rapid - you mean faster?

if you have dense mesh with many triangles that testing each triangle isn't a good way...

you need to have some sort of tree to speed up thing.

but instead of building it by yourself you can use someone's else work - collision library.

i;ve just done lightmapper for my game and i've been using Newton engine to do raycating. Althoung probably not the fastest tyhing in the world it;'s accurate and at quite good speed.

The most important thing is that its extremely easy to use:

nwtWorld = NewtonCreate(NULL,NULL);NewtonCollision *nwtCol = NewtonCreateTreeCollision( nwtWorld, NULL );NewtonTreeCollisionBeginBuild( nwtCol );	for(unsigned int i=0; i<pl.size(); i++)	{		NewtonTreeCollisionAddFace( nwtCol, 3, (const float*)&face, 12, 0 );	}NewtonTreeCollisionEndBuild( nwtCol, 1);nwtBody = NewtonCreateBody (nwtWorld, nwtCol);NewtonReleaseCollision (nwtWorld, nwtCol);NewtonDestroy(nwtWorld);and then if you want to cast a ray:if( NewtonBodyRayIntersect( nwtBody, (float*)&v0, (float*)&v1out ) > 1.0f ){// anything you anmt}



It's very simple - if you ant to try:
http://www.physicsengine.com

there are also other libs: ODE, Tokamak, pure collision dsetection library OpCode etc.
www.tmreality.com
GENTS
GENTS
Yes, FASTER!!!

I've tried a CD Library (http://users.volja.net/fajrvehr/), but I can't still find a working solution with it...

I've tried with D3DXIntersect Function, but I've some problem, 'cause it doesn't work always with a mesh, and I don't understand the cause...

Probably I've to use D3DXVec3TransformNormal for my rayDir vector ?!
tomek_zielinski
tomek_zielinski
Hey - if you have got ray, then you can treat it like two points - starting and ending/middle/any-point-on-ray point. Then you can transform each point usign D3DXVec3TransformCoord.

-OR-

you can

transform strting point with D3DXVec3TransformCoord
and
direction vector using D3DXVec3TransformNormal, but you HAVE TO supply inverse-transpose of rotation matrix
www.tmreality.com
tomek_zielinski
tomek_zielinski
And I think if you couldn't get proper collisions no matter what library you are using so the problem seems to be with the ray...
www.tmreality.com
GENTS
GENTS
I've tried with this:


bool CObjCollection::CheckCollision( CObjCollection ObjToCheck )
{
Colliding = false;
BOOL bHit;
float distance;
D3DXMATRIX m, m_i, m_p;
D3DXVECTOR3 vOrig, vDir;

// origin of the ray = position of the character
vOrig = m_vPosition;

/* I want to check if in the direction in which
my character is moving is there another mesh
*/
vDir.x = vOrig.x + (float)acos(dir);
vDir.z = vOrig.z + (float)asin(dir);

vDir.y = vOrig.y;

// Get View MATRIX
g_pD3DDevice->GetTransform( D3DTS_WORLD, &m );
D3DXMatrixInverse( &m_i, NULL, &m );

// Transform Coords
D3DXVec3TransformCoord( &vOrig, &vOrig, &m_i );
D3DXVec3TransformCoord( &vDir, &vDir, &m_i );

// Test for intersection with the mesh
D3DXIntersect( ObjToCheck.m_pObjectList->MeshData.pMesh, &vOrig, &vDir, &bHit, NULL, NULL, NULL, &distance, NULL, NULL );
if( bHit == TRUE){
if(distance < Radius )
Colliding = true;
}


return Colliding;

}

<\code>

BUT IT STILL DOESN'T WORK!!!

Where is the problem?!
tomek_zielinski
tomek_zielinski
 /* I want to check if in the direction in whichmy character is moving is there another mesh*/vDir.x = vOrig.x + (float)acos(dir);vDir.z = vOrig.z + (float)asin(dir);//--------------------------------------------------// what's 'dir'?? I don't understand why you're 'acos'-ing and 'asin'-ing the same thing? if  a==cos(angle)  then    angle=acos(a)  // not taking domain into accountif  b==sin(angle)  then    angle=asin(b)  // not taking domain into accountso this thing is broken int your code...(or I cheated on my math exams's?)and why are you adding vOrig to vDir?? is it direction vector or coordinate?I think that it should be:vDir.x = (float)cos(player_angle);vDir.z = (float)sin(player_angle);vDir.y = 0;  // //^^^ it's correct if (0,1,0) vector point up ^^^//--------------------------------------------------// Get View MATRIXg_pD3DDevice->GetTransform( D3DTS_WORLD, &m );D3DXMatrixInverse( &m_i, NULL, &m );// Transform CoordsD3DXVec3TransformCoord( &vOrig, &vOrig, &m ); // wrong->transform coord with matrix!D3DXVec3TransformCoord( &vDir, &vDir, &m_i ); // ok->tranform normal with inverse-transpose!


I think it should solve your problem
www.tmreality.com
tomek_zielinski
tomek_zielinski
in case you've aleready read it - read it once again bacause I've just made some changes to previous post
www.tmreality.com
tomek_zielinski
tomek_zielinski
And one more thing:

if you create pure device you cannot get matrices from it....
in such case cache matrices in variables
www.tmreality.com
tomek_zielinski
tomek_zielinski
Hey! Nice you are glad but try it first:)
I haven't given you any guarantee:)

If it don't work, I'v got another idea.
www.tmreality.com
paranoia33
paranoia33
My Collision Detection is basically the same system and i got it working today...here are just a few observations of my own on the code:

g_pD3DDevice->GetTransform( D3DTS_WORLD, &m );D3DXMatrixInverse( &m_i, NULL, &m );// Transform CoordsD3DXVec3TransformCoord( &vOrig, &vOrig, &m_i ); //right -> you do want to do this. If you think about it; The player's X,Y,Z are in would space. So you want to move it back to the meshes local space before it went through any transformations. Which you would use the inverse matrix for that.D3DXVec3TransformCoord( &vDir, &vDir, &m_i ); // wrong (i think, didnt work for mine) this mean you are treating the direction vector like a point. Wouldnt you want to use D3DXVec3TransformNormal to accomplish this? First you would use D3DXMatrixTranspose right..


i could be wrong....but that is what worked in my engine


[Edited by - paranoia33 on July 5, 2004 9:30:33 PM]
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/Current Projects:PEngine - Full 3d FPS engine
tomek_zielinski
tomek_zielinski
Paranoia33 is right - here you have corrected code:

// Get View MATRIX
g_pD3DDevice->GetTransform( D3DTS_WORLD, &m );
D3DXMatrixInverse( &m_i, NULL, &m );

D3DXMatrixTranspose( &m_iit, &m );

// Transform Coords
D3DXVec3TransformCoord( &vOrig, &vOrig, &m_i );
D3DXVec3TransformNormal( &vDir, &vDir, &m_iit );

If you transform coord with 'm' then you need to trasform coord with inverse-transpose of 'm'. So if you transform coord with inverse of 'm' then inverse-transpose of inverse of 'm' is simply transpose of 'm'. <- it's quite easy event though it look difficult;)


[Edited by - tomek_zielinski on July 6, 2004 8:07:56 AM]
www.tmreality.com

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.