Skip to main content
gamedev.net
🔒 Locked

Picking Function

Started by JohnDev 9 replies 1.8k views
Original Post
JohnDev
JohnDev
Hi guys ! I have a problem with my picking function. I use the following code:

tbResult DrawSelection(void)
{
	if(m_bPicking)
	{
		Pick();
		tbDirect3D& D3D = tbDirect3D::Instance();
		// If a triangle is picked, draw it
		if(m_dwNumIntersections > 0)
		{
			for(UINT uPass = 0; uPass < 20; ++uPass)
			{
				D3D.SetFVF(D3DFVF_NORMAL);
				D3D->SetStreamSource(0, m_pVertexBuffer->GetVB(), 0, sizeof(tbVertex));
				D3D->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_dwNumIntersections );
			}
			D3D.SetRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME );
			D3D.SetRS( D3DRS_LIGHTING, FALSE );
		}
		if(!tbDirect3D::Instance().GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST, 0, m_dwNumIntersections))
		{
			TB_WARNING("Fehler beim Zeichnen der Auswahl!");
			return TB_ERROR;
		}
		D3D.SetRS( D3DRS_LIGHTING, TRUE);
	}
	return TB_OK;
}

tbResult Pick()
{
	if(m_bPicking)
	{
		tbVector3 vPickRayDir;
		tbVector3 vPickRayOrig;
		tbDirect3D& D3D = tbDirect3D::Instance();
		
		m_dwNumIntersections = 0L;

		tbMatrix mProj = D3D.GetTransform(D3DTS_PROJECTION);

		tbVector3 v;
		v.x =  ( ( ( 2.0f * m_ptMousePick.x ) / m_pCurrentChain->GetWidth()) - 1 ) / mProj.m11;
		v.y = -( ( ( 2.0f * m_ptMousePick.y ) / m_pCurrentChain->GetHeight()) - 1 ) / mProj.m22;
		v.z =  1.0f;
	
		const tbMatrix	matView		= D3D.GetTransform(D3DTS_VIEW);
		const tbMatrix	matWorld	= D3D.GetTransform(D3DTS_WORLD);
		tbMatrix		mWorldView	= matWorld * matView;
		tbMatrix		m;
		D3DXMatrixInverse((D3DXMATRIX*)(&m), NULL, (D3DXMATRIX*)(&mWorldView));

		vPickRayDir.x  = v.x*m.m11 + v.y*m.m21 + v.z*m.m31;
		vPickRayDir.y  = v.x*m.m12 + v.y*m.m22 + v.z*m.m32;
		vPickRayDir.z  = v.x*m.m13 + v.y*m.m23 + v.z*m.m33;
		vPickRayOrig.x = m.m41;
		vPickRayOrig.y = m.m42;
		vPickRayOrig.z = m.m43;

		tbModel*		pModel;
		pModel			= m_pModel;
		tbVertexBuffer*	pVertexBuffer;
		tbIndexBuffer*	pIndexBuffer;

		pVertexBuffer	= pModel->GetVertexBuffer();
		pIndexBuffer	= pModel->GetIndexBuffer();

		if(!pVertexBuffer)
		{
			TB_WARNING("Der Vertex-Buffer Pointer zeigt ins Nirvana!");
			return TB_ERROR;
		}
		else if(!pIndexBuffer)
		{
			TB_WARNING("Der Index-Buffer Pointer zeigt ins Nirvana!");
			return TB_ERROR;
		}
		else
		{
			WORD*		pIndices;
			tbVertex*	pVertices;

			pIndexBuffer->GetIB()->Lock( 0, 0, (void**)&pIndices, 0 );
			pVertexBuffer->GetVB()->Lock( 0, 0, (void**)&pVertices, 0 );

			DWORD dwNumFaces = pModel->GetNumVertices();
			float fBary1, fBary2;
			float fDist;
	            
			for(DWORD i=0; i<dwNumFaces; i++)
			{
				tbVector3 v0 = pVertices[pIndices[3*i+0]].p;
				tbVector3 v1 = pVertices[pIndices[3*i+1]].p;
				tbVector3 v2 = pVertices[pIndices[3*i+2]].p;

				if(IntersectTriangle(vPickRayOrig, vPickRayDir, v0, v1, v2, &fDist, &fBary1, &fBary2))
				{
					if( m_dwNumIntersections == 0 || fDist < m_IntersectionArray[0].fDist )
					{
	m_dwNumIntersections = 0;
						m_IntersectionArray[m_dwNumIntersections].dwFace	= i;
						m_IntersectionArray[m_dwNumIntersections].fBary1	= fBary1;
						m_IntersectionArray[m_dwNumIntersections].fBary2	= fBary2;
						m_IntersectionArray[m_dwNumIntersections].fDist		= fDist;
						m_dwNumIntersections++;
	                        
						if(m_dwNumIntersections == MAX_INTERSECTIONS )
							break;
					}
				}
			}

			if(m_dwNumIntersections > 0)
			{
				tbVertex*		v;
				tbVertex*		vThisTri;
				WORD*			wThisTri;
				tbVertex		v1, v2, v3;
				tbIntersection* pIntersection;

				m_pVertexBuffer->GetVB()->Lock( 0, 0, (void**)&v, 0 );

				for( DWORD dwIntersection = 0; dwIntersection < m_dwNumIntersections; dwIntersection++ )
				{
					pIntersection = &m_IntersectionArray[dwIntersection];

					vThisTri = &v[dwIntersection * 3];
					wThisTri = &pIndices[3*pIntersection->dwFace];
					// get vertices hit
					vThisTri[0] = pVertices[wThisTri[0]];
					vThisTri[1] = pVertices[wThisTri[1]];
					vThisTri[2] = pVertices[wThisTri[2]];

					float dtu1 = vThisTri[1].tu - vThisTri[0].tu;
					float dtu2 = vThisTri[2].tu - vThisTri[0].tu;
					float dtv1 = vThisTri[1].tv - vThisTri[0].tv;
					float dtv2 = vThisTri[2].tv - vThisTri[0].tv;
					pIntersection->tu = vThisTri[0].tu + pIntersection->fBary1 * dtu1 + pIntersection->fBary2 * dtu2;
					pIntersection->tv = vThisTri[0].tv + pIntersection->fBary1 * dtv1 + pIntersection->fBary2 * dtv2;
				}

				m_pVertexBuffer->GetVB()->Unlock();
			}
			pVertexBuffer->GetVB()->Unlock();
			pIndexBuffer->GetIB()->Unlock();
		}
	}
	return TB_OK;
}
}

tbResult IntersectTriangle( const tbVector3& orig, const tbVector3& dir, tbVector3& v0, tbVector3& v1, tbVector3& v2, float* t, float* u, float* v )
{
    tbVector3 edge1 = v1 - v0;
    tbVector3 edge2 = v2 - v0;

    tbVector3 pvec;
    pvec = tbVector3Cross(dir, edge2);

     float det = tbVector3Dot(edge1, pvec);

    tbVector3 tvec;
    
	if(det > 0)
        tvec	= orig - v0;
    else
    {
        tvec	= v0 - orig;
        det		= -det;
    }

    if( det < 0.0001f )
        return TB_ERROR;

    *u = tbVector3Dot(tvec, pvec);
    
	if( *u < 0.0f || *u > det )
        return TB_ERROR;

	tbVector3 qvec;
	qvec = tbVector3Cross(tvec, edge1 );

    *v = tbVector3Dot(dir, qvec);
    if( *v < 0.0f || *u + *v > det )
        return TB_ERROR;

    *t = tbVector3Dot(edge2, qvec);
	float fInvDet = 1.0f / det;
	*t *= fInvDet;
	*u *= fInvDet;
	*v *= fInvDet;

    return TB_OK;
}
But when I set the value of m_bPicking to "TRUE", the renderer get slower and the lighting is disable ... So, I have logt the prozedure and recognized, that the DrawPrimitives(...) function wasn't successful. Best Wishes JohnDev [Edited by - JohnDev on February 12, 2006 4:56:43 AM]
JohnDev
JohnDev
Does somebody have an idea?

Thank you.
JohnDev
sirob
sirob
The code you posted isn't really readable the way it's posted.

Try placing [ source ] tags around it, so it get's formatted nicely.

Also, it's far too much code, and you barely specified what the problem with it is, so even attempting to look for the problem is nearly impossible.

Could you provide some more information? What you are trying to do, what is working, and what isn't working? and what is happening that makes it "not work"?

Also, you're talking about picking, and posting picking code, but suddenly you mention lighting failing to work, and DrawPrimitive failing? I'm really not following that part.
Sirob Yes.» - status: Work-O-Rama.
JohnDev
JohnDev
Sorry, but I thought it's ok for understanding. The path in the code I meant is the following:

tbResult DrawSelection(void){	if(m_bPicking)	{		Pick();		tbDirect3D& D3D = tbDirect3D::Instance();		// If a triangle is picked, draw it		if(m_dwNumIntersections > 0)		{			for(UINT uPass = 0; uPass < 20; ++uPass)			{				D3D.SetFVF(D3DFVF_NORMAL);				D3D->SetStreamSource(0, m_pVertexBuffer->GetVB(), 0, sizeof(tbVertex));				D3D->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_dwNumIntersections );			}			D3D.SetRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME );			D3D.SetRS( D3DRS_LIGHTING, FALSE );		}		if(!tbDirect3D::Instance().GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST, 0, m_dwNumIntersections))		{			TB_WARNING("Fehler beim Zeichnen der Auswahl!");			return TB_ERROR;		}		D3D.SetRS( D3DRS_LIGHTING, TRUE);	}	return TB_OK;}



tbResult Pick(){	if(m_bPicking)	{		tbVector3 vPickRayDir;		tbVector3 vPickRayOrig;		tbDirect3D& D3D = tbDirect3D::Instance();				m_dwNumIntersections = 0L;		tbMatrix mProj = D3D.GetTransform(D3DTS_PROJECTION);		tbVector3 v;		v.x =  ( ( ( 2.0f * m_ptMousePick.x ) / m_pCurrentChain->GetWidth()) - 1 ) / mProj.m11;		v.y = -( ( ( 2.0f * m_ptMousePick.y ) / m_pCurrentChain->GetHeight()) - 1 ) / mProj.m22;		v.z =  1.0f;			const tbMatrix	matView		= D3D.GetTransform(D3DTS_VIEW);		const tbMatrix	matWorld	= D3D.GetTransform(D3DTS_WORLD);		tbMatrix		mWorldView	= matWorld * matView;		tbMatrix		m;		D3DXMatrixInverse((D3DXMATRIX*)(&m), NULL, (D3DXMATRIX*)(&mWorldView));		vPickRayDir.x  = v.x*m.m11 + v.y*m.m21 + v.z*m.m31;		vPickRayDir.y  = v.x*m.m12 + v.y*m.m22 + v.z*m.m32;		vPickRayDir.z  = v.x*m.m13 + v.y*m.m23 + v.z*m.m33;		vPickRayOrig.x = m.m41;		vPickRayOrig.y = m.m42;		vPickRayOrig.z = m.m43;		tbModel*		pModel;		pModel			= m_pModel;		tbVertexBuffer*	pVertexBuffer;		tbIndexBuffer*	pIndexBuffer;		pVertexBuffer	= pModel->GetVertexBuffer();		pIndexBuffer	= pModel->GetIndexBuffer();		if(!pVertexBuffer)		{			TB_WARNING("Der Vertex-Buffer Pointer zeigt ins Nirvana!");			return TB_ERROR;		}		else if(!pIndexBuffer)		{			TB_WARNING("Der Index-Buffer Pointer zeigt ins Nirvana!");			return TB_ERROR;		}		else		{			WORD*		pIndices;			tbVertex*	pVertices;			pIndexBuffer->GetIB()->Lock( 0, 0, (void**)&pIndices, 0 );			pVertexBuffer->GetVB()->Lock( 0, 0, (void**)&pVertices, 0 );			DWORD dwNumFaces = pModel->GetNumVertices();			float fBary1, fBary2;			float fDist;	            			for(DWORD i=0; i<dwNumFaces; i++)			{				tbVector3 v0 = pVertices[pIndices[3*i+0]].p;				tbVector3 v1 = pVertices[pIndices[3*i+1]].p;				tbVector3 v2 = pVertices[pIndices[3*i+2]].p;				if(IntersectTriangle(vPickRayOrig, vPickRayDir, v0, v1, v2, &fDist, &fBary1, &fBary2))				{					if( m_dwNumIntersections == 0 || fDist < m_IntersectionArray[0].fDist )					{	m_dwNumIntersections = 0;						m_IntersectionArray[m_dwNumIntersections].dwFace	= i;						m_IntersectionArray[m_dwNumIntersections].fBary1	= fBary1;						m_IntersectionArray[m_dwNumIntersections].fBary2	= fBary2;						m_IntersectionArray[m_dwNumIntersections].fDist		= fDist;						m_dwNumIntersections++;	                        						if(m_dwNumIntersections == MAX_INTERSECTIONS )							break;					}				}			}			if(m_dwNumIntersections > 0)			{				tbVertex*		v;				tbVertex*		vThisTri;				WORD*			wThisTri;				tbVertex		v1, v2, v3;				tbIntersection* pIntersection;				m_pVertexBuffer->GetVB()->Lock( 0, 0, (void**)&v, 0 );				for( DWORD dwIntersection = 0; dwIntersection < m_dwNumIntersections; dwIntersection++ )				{					pIntersection = &m_IntersectionArray[dwIntersection];					vThisTri = &v[dwIntersection * 3];					wThisTri = &pIndices[3*pIntersection->dwFace];					// get vertices hit					vThisTri[0] = pVertices[wThisTri[0]];					vThisTri[1] = pVertices[wThisTri[1]];					vThisTri[2] = pVertices[wThisTri[2]];					float dtu1 = vThisTri[1].tu - vThisTri[0].tu;					float dtu2 = vThisTri[2].tu - vThisTri[0].tu;					float dtv1 = vThisTri[1].tv - vThisTri[0].tv;					float dtv2 = vThisTri[2].tv - vThisTri[0].tv;					pIntersection->tu = vThisTri[0].tu + pIntersection->fBary1 * dtu1 + pIntersection->fBary2 * dtu2;					pIntersection->tv = vThisTri[0].tv + pIntersection->fBary1 * dtv1 + pIntersection->fBary2 * dtv2;				}				m_pVertexBuffer->GetVB()->Unlock();			}			pVertexBuffer->GetVB()->Unlock();			pIndexBuffer->GetIB()->Unlock();		}	}	return TB_OK;}}


tbResult IntersectTriangle( const tbVector3& orig, const tbVector3& dir, tbVector3& v0, tbVector3& v1, tbVector3& v2, float* t, float* u, float* v ){    tbVector3 edge1 = v1 - v0;    tbVector3 edge2 = v2 - v0;    tbVector3 pvec;    pvec = tbVector3Cross(dir, edge2);     float det = tbVector3Dot(edge1, pvec);    tbVector3 tvec;    	if(det > 0)        tvec	= orig - v0;    else    {        tvec	= v0 - orig;        det		= -det;    }    if( det < 0.0001f )        return TB_ERROR;    *u = tbVector3Dot(tvec, pvec);    	if( *u < 0.0f || *u > det )        return TB_ERROR;	tbVector3 qvec;	qvec = tbVector3Cross(tvec, edge1 );    *v = tbVector3Dot(dir, qvec);    if( *v < 0.0f || *u + *v > det )        return TB_ERROR;    *t = tbVector3Dot(edge2, qvec);	float fInvDet = 1.0f / det;	*t *= fInvDet;	*u *= fInvDet;	*v *= fInvDet;    return TB_OK;}



I meant that the variables, which contains the picked triangle contain no values..
So the drawprimitive(..) function failed !

I hope you do understand now.

Thank you.
JohnDev
jamesw
jamesw
Too bad there isn't a compiler or a debugger in this forum or I might be able to help.
JohnDev
JohnDev
The compiling process works successfully and the debugger gives no attention.
But if the Picking Function is activated, the render progress is really slow and the selection is not drawed...

Greatings
JohnDev
ms291052
ms291052
I've noticed some problems in your code that may or may not be related, but I can see how they might slow down your rendering.

//First, is D3D now a LPDIRECT3D9 or a LPDIRECT3DDEVICE9?
tbDirect3D& D3D = tbDirect3D::Instance();

later you use

//SetFVF is a DEVICE member function, implying that this is a device
D3D.SetFVF(D3DFVF_NORMAL);

//Notice the -> instead of .
D3D->SetStreamSource(...);

Already we have conflicting pointer/non-pointer function calls. Which should it be (what's the variable type of tbDirect3D)?

Also, later, you use tbDirect3D::Instance.GetDevice()->DrawPrimitive, implying a totally different code structure (maybe some sort of very odd wrapper?)

I'm thinking that maybe you've actually taken the time to wrap all these member functions, and that tbDirect3D::Instance() actually gets you the real device? If so, why didn't you wrap the few functions you need that for too?
JohnDev
JohnDev
I don't know whether you know what a singleton is? Than you maybe know why there's the Instance()-function ...
Because the DrawPrimitive Function isn't a part of this class, I recieve the device with GetDevice() and call the DrawPrimitve-function ....
And i know that that's not the function witch causes the slow rendering progress
cause I use this kind of code in some similar problems and there everything was okay.
cotoole
cotoole
My best guess is it has something to do with you locking the vertex and index buffers. I don't know what flags you're using to create those buffers, but you should definately be locking with the READONLY flag, and perhaps the NOSYSLOCK flags (I forget the exact name).

Of course, if you're DrawPrimitive() was failing you wouldn't be rendering anything, so I don't quite get that.

Hope that helps.
JohnDev
JohnDev
Look at the following:

m_pVertexBuffer = new tbVertexBuffer;	if(!m_pVertexBuffer) 		TB_ERROR_OUT_OF_MEMORY(TB_ERROR);	m_pVertexBuffer->Init(3*MAX_INTERSECTIONS*sizeof(tbVertex), sizeof(tbVertex), D3DFVF_NORMAL, D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED);	m_pVertexBuffer->SetFirstVertex(0);	m_pVertexBuffer->SetLastVertex(3*MAX_INTERSECTIONS - 1);				if(m_pVertexBuffer->Update()) 		TB_ERROR("Fehler beim Aktualisieren des Vertex-Buffers!", TB_ERROR);
cotoole
cotoole
From the DirectX SDK:

The presence of the D3DUSAGE_WRITEONLY flag in Usage indicates that the vertex buffer memory is used only for write operations. This frees the driver to place the vertex data in the best memory location to enable fast processing and rendering. If the D3DUSAGE_WRITEONLY flag is not used, the driver is less likely to put the data in a location that is inefficient for read operations.

So that explains your slowdown. D3D has put the VB into video memory which is very slow to read from.

Topic Locked

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

Sign in to reply to this topic.