Picking class improvments

Started by
4 comments, last by Programmer16 18 years, 8 months ago
I made a simple picking sample for mouse detection and I encapsulated it into a class. I was looking for improvements, suggestions, etc. I also have 4 questions: 1) Will I be able to use this class for anything other else? 2) Is this one of those things that I shouldn't put into a class? 3) Does calling GetTransform() slow it down any (on a hardware vp HAL device)? 4) Is there a way that I could modify it to check for a quad, without calling IntersectsTriangle() twice?

class MousePicker
{
	IDirect3DDevice9*	m_pDevice;
	float				m_fWidth, m_fHeight;
	D3DXVECTOR3			m_RayOrigin, m_RayDirection;
public:
	MousePicker()
	{
		m_pDevice = 0;
	}

	MousePicker(IDirect3DDevice9* pDevice)
	{
		m_pDevice = pDevice;
		if(m_pDevice)
		{
			D3DVIEWPORT9 ViewPort;
			IDirect3DDevice9* m_pDevice;
			m_pDevice->GetViewport(&ViewPort);
			m_fWidth = (float)ViewPort.Width;
			m_fHeight = (float)ViewPort.Height;
		}
	}

	void SetDevice(IDirect3DDevice9* pDevice)
	{
		m_pDevice = pDevice;
		if(m_pDevice)
		{
			D3DVIEWPORT9 ViewPort;
			m_pDevice->GetViewport(&ViewPort);
			m_fWidth = (float)ViewPort.Width;
			m_fHeight = (float)ViewPort.Height;
		}
	}

	void CreateRay(float fMouseX, float fMouseY)
	{
		D3DXMATRIX ViewMtx, ProjMtx;
		m_pDevice->GetTransform(D3DTS_VIEW, &ViewMtx);
		m_pDevice->GetTransform(D3DTS_PROJECTION, &ProjMtx);
		
		D3DXMATRIX	Matrix;
		D3DXVECTOR3 Vector = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
		
		Vector.x = (((2.0f * fMouseX) / m_fWidth) - 1.0f) / ProjMtx._11;
		Vector.y = -(((2.0f * fMouseY) / m_fHeight) - 1.0f) / ProjMtx._22;
		Vector.z = 1.0f;
		
		D3DXMatrixInverse(&Matrix, 0, &ViewMtx);
		m_RayDirection.x = Vector.x * Matrix._11 + Vector.y * Matrix._21 + Vector.z * Matrix._31;
		m_RayDirection.y = Vector.x * Matrix._12 + Vector.y * Matrix._22 + Vector.z * Matrix._32;
		m_RayDirection.z = Vector.x * Matrix._13 + Vector.y * Matrix._23 + Vector.z * Matrix._33;
		m_RayOrigin.x = Matrix._41;
		m_RayOrigin.y = Matrix._42;
		m_RayOrigin.z = Matrix._43;
	}

	bool IntersectsTriangle(void* pVertices, unsigned int nOffset, float* pHitDistance)
	{
		D3DXMATRIX InverseMtx;
		D3DXMATRIX WorldMtx;
		m_pDevice->GetTransform(D3DTS_WORLD, &WorldMtx);
		D3DXMatrixInverse(&InverseMtx, 0, &WorldMtx);
		
		D3DXVECTOR3 RayObjOrigin = D3DXVECTOR3(0.0f, 0.0f, 0.0f), RayObjDirection = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
		D3DXVec3TransformCoord(&RayObjOrigin, &m_RayOrigin, &InverseMtx);
		D3DXVec3TransformNormal(&RayObjDirection, &m_RayDirection, &InverseMtx);
		D3DXVec3Normalize(&RayObjDirection, &RayObjDirection);
		
		return D3DXIntersectTri((D3DXVECTOR3*)pVertices, &((D3DXVECTOR3*)pVertices)[nOffset + 1], &((D3DXVECTOR3*)pVertices)[nOffset + 2], &RayObjOrigin, &RayObjDirection, 0, 0, pHitDistance) != 0;
	}
};


Thanks!
Advertisement
Definatly add intersection with a sphere and with an AABB. For speed's sake :).

Also, I think a NON-pure device, calling GetTransform doesn't actually get it from the card, but rather gets a copy of the matrices stored in system memory, so it should be quite quick.

EDIT: (sorry I'm editing after you replied, keep thinking of stuff)

If you're uncertain about using GetTransform, you could easily create a Frame() function, which performs the GetTransform once per frame, and saves the values for the entire frame's checking. This would solve problems on pure devices, too.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
Definatly add intersection with a sphere and with an AABB. For speed's sake :).


Ok, thanks! I'll have to research it, but it shouldn't be too hard [wink].
Ok, I've run into a problem with the class. I added a variable to my vertex class (diffuse), so now it has x,y,z and diffuse. But, now it doesn't detect my intersection. I'm thinking the problem is with my casting for D3DXIntersectTri().

Any suggestions?

Edit: Ok, I fixed it. I was correct, it was an error with my casting.

I tried adding a stride parameter to IntersectsRect(), then using that to "step over" the extra variable, but that didn't work.
Two options, really:

1) modify your vert struct, so the position is already a D3DXVECTOR3:
struct Vert {     D3DXVECTOR3 Pos;     D3DCOLOR Diffuse;}

Then, you'd just pass it in as Vert.Pos with no casting.

or 2) Simply use D3DXVECTOR3(float x, float y, float z) to convert your verts to D3DXVECTOR3s, like so:
        D3DXVECTOR3 Vec1 = D3DXVECTOR3(pVertices.x, pVertices.y, pVertices.z);        // Then pass in &Vec1 to the D3DXIntersectTri function.


EDIT Yes, again, sorry:
You also seem to have a small mistake (I think) in the last line of code you posted, as you don't use [nOffset] on the first vertex, but use [nOffset + 1] on the second and [nOffset + 2] on the third.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
Two options, really:

1) modify your vert struct, so the position is already a D3DXVECTOR3:
*** Source Snippet Removed ***
Then, you'd just pass it in as Vert.Pos with no casting.

or 2) Simply use D3DXVECTOR3(float x, float y, float z) to convert your verts to D3DXVECTOR3s, like so:
*** Source Snippet Removed ***

EDIT Yes, again, sorry:
You also seem to have a small mistake (I think) in the last line of code you posted, as you don't use [nOffset] on the first vertex, but use [nOffset + 1] on the second and [nOffset + 2] on the third.


Thank you for pointing that out (I hadn't noticed that.) I guess I'll just go with 1. Thanks for your help!

This topic is closed to new replies.

Advertisement