Archived

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

How 2 use D3DXIntersect?

This topic is 5122 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The DX8 documentation isn''t much help in places. I was wondering if anyone could tell me how to use D3DXIntersect for detecting collisions betwen two meshes or point to tutorials of the subject. I''m using VC6, ;-)

Share this post


Link to post
Share on other sites
D3DXIntersect tests to see if there is an intersection between a ray and a mesh, not two meshes.

Depending on how accurate you want your collision detection to be, you may be able to get away with just testing to see if the bounding volumes of the two meshes collided.

As far as tutorials go, you can find a few right here on gamedev. Also, you can use google and search for "collision detection" and you''ll see a lot of usefull links.

neneboricua

Share this post


Link to post
Share on other sites
Well its not that I don't under stand what its for. The thing is that I'm not so sure as to how to practically use it. I'm a total newbie to this guys and like I don't seem to understand the parameters that are passed to this fnction d3dxintersect. The thing is that I want to text whether one 3D mesh intersects with another 3D mesh.

I checked out almost all of gamedev, but I can't find any tutorial that specifically deals with collision detection in DX. I'm using DX8 and VC6, maybe I've missed something, but I haven't found any tutorials dealing with collision detection in DX8.

At the moment I'm not very concerned with the accuracy. Just wanna know how to work this function any help please.


[edited by - ParityCheck on November 13, 2003 9:21:34 AM]

Share this post


Link to post
Share on other sites
Just use D3DXComputeBoundingSphere and/or D3DXComputeBoundingBox if you''re not as concerned with accuracy. Spheres and boxes are a lot easier to do Collision Detection with than an arbitrary mesh, and thus save a lot of processor speed.

Share this post


Link to post
Share on other sites
quote:
Original post by ParityCheck
Well its not that I don''t under stand what its for. The thing is that I''m not so sure as to how to practically use it. I''m a total newbie to this guys and like I don''t seem to understand the parameters that are passed to this fnction d3dxintersect. The thing is that I want to text whether one 3D mesh intersects with another 3D mesh.


D3DXIntersect isn''t used for collision detection between meshes. It''s used for ray casting and ray tracing.
quote:

I checked out almost all of gamedev, but I can''t find any tutorial that specifically deals with collision detection in DX. I''m using DX8 and VC6, maybe I''ve missed something, but I haven''t found any tutorials dealing with collision detection in DX8.

You really don''t need tutorials for collision detection written specifically in DX to be usefull. Collision detection is really independent of the API you use. Granted, some of the D3DX functions make implementing collision detection easier but any generic article on collision detection should get you up and running.

The easiest collision detection you could have between two objects whould be to check if their bounding spheres intersected. Use D3DXComputeBoundingSphere to calculate a sphere that fits around your mesh. If you think about it, detecting if there is a collision between two spheres is pretty easy. The code would look something like this:

bool DetectCollision( const D3DXVECTOR3 &vCenter1, FLOAT fRadius1, const D3DXVECTOR3 &vCenter2, FLOAT fRadius2 )
{
D3DXVECTOR3 vTemp;
D3DXVec3Subtract( &vTemp, &vCenter2, &vCenter1 );
FLOAT distance = D3DXVec3Length( &vTemp );
if( distance <= fRadius1+fRadius2 )
{
return true;
}
return false;
}

Here, vCenter1 is the center of the bounding sphere of your first mesh and fRadius1 is the bounding sphere''s radius. vCenter2 and fRadius2 are the same but for the other mesh. If the distance between the centers of the two spheres is less than the sum of the spheres radii (I think that''s how you spell the plural for radius), then there is a collision, otherwise there is not.

Hope this helps,
neneboricua

Share this post


Link to post
Share on other sites
I''ve tried the code mentioned above but my program exits upon reaching the code module. I tried to check whats the problem and it appears that the code exits at D3DXVec3Length(&vTemp).


bool CDirectX::DetectCollision()
{
BotFactory->GetMeshBoundingSphere(pBotCenter, pBotRadius);
aBullet->GetMeshBoundingSphere(pBulletCenter, pBulletRadius);

D3DXVECTOR3 vTemp;
D3DXVec3Subtract(&vTemp, pBulletCenter, pBotCenter);
float distance = D3DXVec3Length(&vTemp);

if(distance<= *pBotRadius+*pBulletRadius)
return true;
else
return false;

};



pBulletCenter and pBotCenter are pointers I''ve declared and are initialising by this function in my mesh class:



D3DXComputeBoundingSphere(lpMesh,lpMesh->GetNumVertices(),D3DFVF_XYZ, pCenter, pRadius)




Another weird thing is that the radii returned by the D3DXComputeBoundingShpere line is zero??

what could be the problem guys

Share this post


Link to post
Share on other sites
The problem is that you're not using D3DXComputeBoundingSphere correctly. Note that you should only compute the bounding sphere of a mesh once (during initialization).

Also, take a look at the parameters to the function. The first one is a pointer to the position of the first vertex, not a pointer to the mesh itself. You've got the second parameter right. The third one is the size of the FVF for the mesh. Do what the documentation says and use the D3DXGetFVFVertexSize function for this parameter. The code to compute the bounding sphere of a mesh would look something like this:

HRESULT MyMesh::ComputeBoundingSphere()
{
HRESULT hr;

VertexType *pVertices = NULL;
if( FAILED( hr = m_pMesh->LockVertexBuffer( D3DLOCK_READONLY, (VOID**)&pVertices ) ) )
return DXTRACE_ERR_MSGBOX( "LockVertexBuffer", hr );

if( FAILED( hr = D3DXComputeBoundingSphere( pVertices, m_pMesh->GetNumVertices(), D3DXGetFVFVertexSize(m_pMesh->GetFVF()), &m_vCenter, &m_fRadius ) ) )
return DXTRACE_ERR_MSGBOX( "D3DXComputeBoundingSphere", hr );

m_pMesh->UnlockVertexBuffer();

return S_OK;
}


In this code, m_pMesh is a pointer to a D3D mesh object. m_vCenter is D3DXVECTOR3 that contains the center of the bounding sphere, and m_fRadius is a FLOAT that contains the radius of the bounding sphere. These are all class member variables, but you can change them to whatever you want.

Also note that "VertexType" is a struct defined by your app. You need to know what information is stored in the vertices of your mesh to create this type. The standard vertex type look something like this:

struct VertexType
{
D3DXVECTOR3 position;
D3DXVECTOR3 normal;
FLOAT tu, tv;
};

This vertex structure has space for a position, normal, and texture coordinates. If you're not sure what vertex format your model uses, you can force it to use the vertex structure you want by using ID3DXMesh::CloneMeshFVF() to make a copy of the original mesh but make the copy use your vertex structure instead. Take a look at the EnhancedMesh or OptimizedMesh samples that come with the SDK if you need more info on how to mess with .x models

neneboricua

[edited by - neneboricua19 on November 19, 2003 12:47:22 PM]

Share this post


Link to post
Share on other sites
I''ve tried the mentioned code and made alterations but now my program seems to exit upon creration of my mesh. Below is my

Mesh object constructor


CMesh::CMesh(LPDIRECT3DDEVICE8 alpDevice, char *pMeshPath)
{
lpDevice = alpDevice;
Status = new CText(lpDevice);

LPD3DXMESH pMesh=NULL;
LPD3DXBUFFER lpMatBuffer = NULL;

if(FAILED(D3DXLoadMeshFromX(pMeshPath, D3DXMESH_SYSTEMMEM, lpDevice, NULL, &lpMatBuffer, &nMaterials, &pMesh)))
return;

D3DXMATERIAL* d3dXMaterial = (D3DXMATERIAL*)lpMatBuffer->GetBufferPointer();

lpTexture = new LPDIRECT3DTEXTURE8[nMaterials];
d3dMaterial = new D3DMATERIAL8[nMaterials];

for(DWORD i =0; i<nMaterials; i++)
{
d3dMaterial[i] = d3dXMaterial[i].MatD3D;
d3dMaterial[i].Ambient = d3dMaterial[i].Diffuse;

if(FAILED(D3DXCreateTextureFromFile(lpDevice,d3dXMaterial[i].pTextureFilename, &lpTexture[i])))
lpTexture[i] = NULL;

}

lpMatBuffer->Release();
lpMatBuffer = NULL;

pMesh->CloneMeshFVF(D3DXMESH_MANAGED, D3D_MYVERTEX2,lpDevice, &lpMesh);

SetBoundingSphere();
WriteToLog("SetBoundingSphere() -> OK");

pMesh->Release();
pMesh = NULL;

D3DXComputeNormals(lpMesh,NULL);


};



The setboundingsphere() function is where trouble is, below is my setbounding sphere function. Its being called only once

during initislising of the object.


CMesh::SetBoundingSphere()
{
myVertex *pVertices = NULL;
lpMesh->LockVertexBuffer( D3DLOCK_READONLY, (BYTE**)&pVertices);
WriteToLog("lpMesh->LockVertexBuffer->OK");
D3DXComputeBoundingSphere( pVertices, lpMesh->GetNumVertices(), D3DXGetFVFVertexSize(lpMesh->GetFVF()), pCenter,

pRadius) //<--- My program exits here????

lpMesh->UnlockVertexBuffer();
};



the program exits at the D3DXComputeBoundingSphere code and pCenter and pRadius are two class variabvles holding the center

and radius of bounding sphere respectively. I''d really appreciate help on this guys

Share this post


Link to post
Share on other sites
You should REALLY check the HRESULT values that D3D returns. Also, what does the debug spew say? The debug spew will tell you why a particular function has failed. In case you weren''t aware of it, you should do all your development work using the Debug Runtimes. You can easily switch between the Debug and Retail Runtimes by going to Control Panel->DirectX and then clicking on the Direct3D tab. Make sure that the Debug Output Level is at the maximum and put a bullet beside the "Debug Runtime" options. Now D3D will output debug messages that will tell you exactly why certain functions have failed.

In your SetBoundingSphere function, the data type for the variable "pVertices" should be D3D_MYVERTEX2, because that''s what you cloned the mesh to use.

One thing I noticed is that in your constructor, it seems like you''ve assumed that every material will definately have a textrue associated with it. This might be fine in your case but there are models out there that use textures with some materials and don''t use textures with others. Just something to keep in mind. If you know that all the models you will be loading have textures associated with each material, then everything''s fine.

Hope this helps,
neneboricua

Share this post


Link to post
Share on other sites
i just wanted to point out that in your first argument to the
ComputeBoundingSphere call.

youll have to change it a bit to get it to work properly if you are using DX9. it should go something like this.





D3DXComputeBoundingBox(&pVertices->v_position , m_pMesh->GetNumVertices(), //continued

D3DXGetFVFVertexSize(m_pMesh->GetFVF()),&m_Box_Min, &m_Box_Max );//ended




this is for a bounding box of course, but you have to be certain to reference your position property in your struct, and be sure if your struct doesnt contain a D3DXVECTOR3 to hold position, that you cast it to one during the call.


(D3DXVECTOR3)(&pVertices->v_position),



thanks for your replies neneboricua19, they have been helpful to me.

Dredd
________________________________________

"To die with your sword still in its sheath is most regrettable" -- Miyomoto Musashi




[edited by - Dreddnafious Maelstrom on December 2, 2003 4:43:15 PM]

Share this post


Link to post
Share on other sites
The D3D_MYVERTEX2 isn''t a datatype but just a defined combo of flags

#define D3D_MYVERTEX2 (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)


the thing is that I don''t seem to get any hresult value at all the code just seems to ''blow up'' within the statement

D3DXComputeBoundingSphere( pVertices, lpMesh->GetNumVertices(), D3DXGetFVFVertexSize(lpMesh->GetFVF()), pCenter, pRadius);


what could be the problem with this guys I really appreciate the help

Share this post


Link to post
Share on other sites
Are you running with the Debug Runtime installed? What does the debug spew say?

Also, make sure that pCenter and pRadius are really valid pointers that indeed point to something. Since you never allocate any space for these variables in your constructor, then I''m not sure they''re actually valid. Your CMesh class definition should be something like this:

class CMesh
{
public:
CMesh();
virtual ~CMesh();
// more stuff....

protected:
D3DXVECTOR3 vCenter;
FLOAT fRadius;
// more stuff....
}

Then your call to D3DXComputeBoundingSphere would look like this:

if( FAILED( D3DXComputeBoundingSphere( pVertices, lpMesh->GetNumVertices(), D3DXGetFVFVertexSize(lpMesh->GetFVF()), &vCenter, &fRadius ) ) )
MessageBox( NULL, "D3DXComputeBoundingSphere messed up", "Error", MB_OK );

I think that the problem is that you never allocated space to store the center and radius of your bounding sphere.

Do yourself a favor and use the Debug Runtimes. They''re completely invaluable for debugging code!

Hope this helps,
neneboricua

Share this post


Link to post
Share on other sites
I''ve got the debug runtime installed, but I''m not quite sure

how it works. I''ve set all the options mentioned, but my

program seems to exit as usual with out displaying any sort

of message as to what went wrong(assuming that the debug

runtime does that) . My app is running in full screen, but

I don''t think that should be a problem.

I''m initialisng my pointers pCenter and pRadius to Null, is

that possibly cousing trouble.

I mean like my program doesn''t even go pass the

D3DXComputeBoundingShere code.. even enclosing it within an

if statement doesn''t help, it doens''t even go within the if

bloc. This is getting spooky guys, any ideas, I really need to get this working

Share this post


Link to post
Share on other sites
Run your app in a window so you can see the debug messages. The Debug Runtimes write messages to Visual Studio''s debugger, so you either need to run your app in a window, or on a seperate monitor so you can step through the code.

It''s a good thing to initialize your the center and radius to NULL, but you have to make sure that you''ve allocated space for them somewhere. This kind of thing would normally happen in your constructor I don''t see the code there. If you''re using pointers as your variables instead of just taking the address of a variable, you should have something like this before you call D3DXComputeBoundingSphere:

pCenter = new D3DXVECTOR3();
pRadius = new FLOAT;

Then you should deallocate this memory before the object is destroyed:

delete pCenter;
delete pRadius;

Allocation should happen in your constructor, and deletion should happen in your destructor.

But for what you''re doing, it would probably be better to just have a D3DXVECTOR3 variable for the center and a FLOAT for the radius instead of having to allocate space dynamically.

neneboricua

Share this post


Link to post
Share on other sites
This is spooky, I just made a few changes such that instead of coputing my bounding sphere of the mesh from a function, I just hard coded it into the constructor and now its computing the bounding sphere?? This doesn''t seem to make any sense as I just copied the code from the function into the constructor and bid the function bye bye and now the code is running ok.

I still have to set the collision detection thing as thats not working for now. But This baffles me as to how could a few lines of code cease to work in a function when they work pretty ok in the constructor???

My detect collision is still a mess tthough, just a question where do I implement the detect collision function. In the game render loop or the mesh or do I have to create an arbitrary class that handles all this? Any suggestion would be highly appreciated as this is one of my first attempts to programming in DX

Share this post


Link to post
Share on other sites
I got the applictaion to compute the boudning sphere of my meshes and it seems to be doing that ok. The problem I am facing

now is detecting the collision. I am kinda confused as to where to implement the detect collision function entioned early on.

I am creating two meshes dynamically using arbitrary classes.

I have like a mesh class that
- creates the mesh and computes bounding sphere

I have 2 meshBuilder classes that actually create an individual instance of the mesh class respectively and cause movements

to their respective created meshes

The first meshbuilder just creates a mesh class object and leave it stationery.

The other meshbuilder class creates another instacne of the mesh class and moves the created mesh towards the first mesh.


Note the meshbuilders contain reference to an instance of the mesh class

I have 2 problems though

when I calculate the bounding spheres they get the vCenter and fRadisu values set fine. When I try to access them to compare the intersection they appear as zero which results in my program shutting down when the detect function is called. I think I''m mixing up with pointers of so.


The other question is where do I implement the detect collision function
- at the moment I''m thinking of calling the detectcollision function fro my main program render function. It seems crude but

at the moment I have a bit of stuff goin on in my render function.
What would be your suggestions guys I really appreciate all the help.

Share this post


Link to post
Share on other sites
quote:
Original post by neneboricua19
D3DXIntersect isn''t used for collision detection between meshes. It''s used for ray casting and ray tracing.



Not true. Ray/Triangle-intersections are used quite a lot for testing tri/tri intersections. Each edge of a polygon is used as a ray, to see if they intersect the triangle.

Share this post


Link to post
Share on other sites
Like I said I got my bounding spheres computed but now I

seem to be having trouble getting to compute the collision

detection. As mentioned I''m retrieveing the bounding sphere

center and radius via an intermediate class which mreates my

mesh, but somehwere along the way I lose my values?? I mean

they get calculated fine but on retrieval they reach the

calling class as zeros?? I think I must have messed up my

pointers or so here is the code for retruning the values of

the sphere center and float of my actual mesh class:


Mesh:: ReturnBoundingSphere(D3DXVECTOR3* m_pCenter, float*

m_pRadius)
{
m_pCenter = &pCenter;
m_pRadius = &pRadius;

}; //No problems here



here is the code of my intermediate class that gets the

values from the mesh and passes to the calling function


MeshBuilder::GetMeshBoundingSphere(D3DXVECTOR3* pCenter,

float* pRadius)
{
Mesh1->ReturnBoundingSphere(pCenter, pRadius);
};//Here the values returned are ZERO !!!





And here is my calling function i.e the detect collision

function, it calls to retrieve the values, and checks for

intersection. The problem is that the values returned are

zero so thats why I gues the program crashes.


DetectCollision()
{
MeshBuilder1->GetMeshBoundingSphere(pCenter1,

pRadius1);
MeshBuilder2->GetMeshBoundingSphere(pCenter2,

pRadius2);

float fdistance = D3DXVec3Length(pBotCenter);

D3DXVECTOR3 vTemp;
HRESULT hr;
D3DXVec3Subtract(&vTemp, pCenter2, pCenter1);
{
// WriteLog("D3DXVec3Subtract()",hr);

//return false;

}

float distance = D3DXVec3Length(&vTemp);

if(distance<= *pRadius1+*pRadius2)
return true;
else
return false;

};



What could be the problem cos I know that at the Mesh calss

the radii and centers are being computed just fine. Upon

retrieval something is going wrong

ANy help would be greatly appreciated guys

Share this post


Link to post
Share on other sites
as you asked how 2 use D3DXIntersect

to use it you need a mesh loaded in d3d. And a ray. a ray has two properties. 1) the point from where a ray is fired called origion of ray and 2) direction in which the ray is fired.

if the ray fired collided with a mesh D3DXIntersect will set BOOL *pHit to true.

Share this post


Link to post
Share on other sites
quote:
Original post by ParityCheck

Mesh::ReturnBoundingSphere(D3DXVECTOR3* m_pCenter, float*
m_pRadius)
{
m_pCenter = &pCenter;
m_pRadius = &pRadius;

}; //No problems here
[code]
quote:

This is just bad. There is almost never a need to return a pointer to member variables of a class. This is just bad programming and could lead to some SERIOUS problems if your code is going to be used by others. If you''re having problems with the pointers getting lost, then use references. They''re a little easier to keep straight in your head.

Also, from your variables, I can''t tell if pCenter is a pointer to a D3DXVECTOR3 variable or not. If it is indeed a pointer, then why are you taking it''s address (&pCenter) ? This gives you the address of a pointer, which in most cases is probably not what you intended.

All this pointer stuff is unnecessary and error prone. Please, do your code like this:

class Mesh
{
public:
Mesh();
virtual ~Mesh();
FLOAT GetBoundingSphereRadius() const
{
return m_fRadius;
}

const D3DXVECTOR3& GetBoundingSphereCenter() const
{
return m_vCenter;
}

// other stuff....


protected:
D3DXVECTOR3 m_vCenter;
FLOAT m_fRadius;
// more stuff...

};

//////////////////


DetectCollision()
{
const D3DXVECTOR3 &vCenter1 = MeshBuilder1->GetBoundingSphereCenter();
FLOAT fRadius1 = MeshBuilder1->GetBoundingSphereRadius();

const D3DXVECTOR3 &vCenter2 = MeshBuilder2->GetBoundingSphereCenter();
FLOAT fRadius2 = MeshBuilder2->GetBoundingSphereRadius();

D3DXVECTOR3 vTemp;
D3DXVec3Subtract(&vTemp, &vCenter2, &vCenter2);
FLOAT distance = D3DXVec3Length(&vTemp);
if(distance <= fRadius1+fRadius2)
return true;
else
return false;
};


If you have more questions on this, please start a new thread with a good subject. I doubt many people on the board have kept up with this thread since it''s gone sooooo far off topic. That way, you''ll get other people''s responses as well.

neneboricua

Share this post


Link to post
Share on other sites