Archived

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

Thanks. Got frustum culling working somewhat. Sphere in frustum?

This topic is 5007 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

Hello there. I hope you can help me out. I had a thread not too long ago, because I needed the code for extracting planes for the frustum culling. I finally got it working. Thanks to those who helped. Now I need to know whether or not a sphere is in the viewing frustum (inside the six planes). This is what I have, and I got it somewhere on the web:
	float fDistance = 0.0f;      // Distance from sphere to plane

	float fTotal    = 0.0f;

	// Check sphere against each side of the frustum

	for (int i = 0; i < MAX_SIDES; i++) 
	{
		// Calculate distance from sphere to plane

		fDistance = ((m_Frustum[i].a * pvPos->x) + (m_Frustum[i].b * pvPos->y) + (m_Frustum[i].c * pvPos->z) + (m_Frustum[i].d));
		fTotal = (D3DXVec3Dot(new D3DXVECTOR3(m_Frustum[i].a, m_Frustum[i].b, m_Frustum[i].c), pvPos) + fDistance);

		if (fTotal < (-radius))     // Check distance

			return false;       // Not inside ''i'' side of the frustum

	}
That may be wrong, but I am not sure. I have it to where it checks a sphere, and displays it in the title bar. It always says "IsSphereVisible(...)" returns false, unless I look off in the distance, away from my terrain. Here''s how I calculate the frustum, in case you need to know:
	D3DXMatrixMultiply(&matClip, matView, matProj);    // Get the clipping plane information

	D3DXMatrixInverse(&matClip, NULL, &matClip);

    m_vecFrustum[0] = D3DXVECTOR3(-1.0f, -1.0f,  0.0f); // xyz

	m_vecFrustum[1] = D3DXVECTOR3( 1.0f, -1.0f,  0.0f); // Xyz

	m_vecFrustum[2] = D3DXVECTOR3(-1.0f,  1.0f,  0.0f); // Xyz

	m_vecFrustum[3] = D3DXVECTOR3( 1.0f,  1.0f,  0.0f); // Xyz

	m_vecFrustum[4] = D3DXVECTOR3(-1.0f, -1.0f,  1.0f); // XyZ

	m_vecFrustum[5] = D3DXVECTOR3( 1.0f, -1.0f,  1.0f); // XyZ

	m_vecFrustum[6] = D3DXVECTOR3(-1.0f,  1.0f,  1.0f); // Xyz

	m_vecFrustum[7] = D3DXVECTOR3( 1.0f,  1.0f,  1.0f); // Xyz


	for (int i = 0; i < 8; i++) 
		D3DXVec3TransformCoord(&m_vecFrustum[i], &m_vecFrustum[i], &matClip);

	// Create the frustum planes from the frustum vector

	D3DXPlaneFromPoints(&m_Frustum[0], &m_vecFrustum[0], &m_vecFrustum[1], &m_vecFrustum[2]);
	D3DXPlaneFromPoints(&m_Frustum[1], &m_vecFrustum[6], &m_vecFrustum[7], &m_vecFrustum[5]);
	D3DXPlaneFromPoints(&m_Frustum[2], &m_vecFrustum[2], &m_vecFrustum[6], &m_vecFrustum[4]);
	D3DXPlaneFromPoints(&m_Frustum[3], &m_vecFrustum[7], &m_vecFrustum[3], &m_vecFrustum[5]);
	D3DXPlaneFromPoints(&m_Frustum[4], &m_vecFrustum[2], &m_vecFrustum[3], &m_vecFrustum[6]);
	D3DXPlaneFromPoints(&m_Frustum[5], &m_vecFrustum[1], &m_vecFrustum[0], &m_vecFrustum[4]);

	for (i = 0; i < 6; i++) 
		D3DXPlaneTransform(&m_Frustum[i], &m_Frustum[i], &matClip);
Do I need to normalize the planes (D3DXPLANE m_Frustum[6])? Thanks in advance.

Share this post


Link to post
Share on other sites
Here is my code for sphere frustum intersection. It is similar to yours but there are important differences that might pinpoint your problem. One thing to note about my code that might be non-standard is that the frustum plane normals point outward.
Intersectable::IntersectionClass Intersectable::Intersects( Sphere const & sphere, Frustum const & frustum )
{
IntersectionClass intersection = ENCLOSED_BY;
for ( int i = 0; i < Frustum::NUM_SIDES; i++ )
{
float const d = Dot( frustum.m_Sides[ i ].m_N, sphere.m_C ) + frustum.m_Sides[ i ].m_D );

if ( d > sphere.m_R )
{
return NO_INTERSECTION;
}
if ( d > -sphere.m_R )
{
intersection = INTERSECTS;
}
}

return intersection;
}
Hope this helps.

One more thing -- your use of new is a not necessary and causing a memory leak.

Share this post


Link to post
Share on other sites
Yeah you do need to normalise the planes. I had a problem with this Untill I did that.

Your plane building''s a bit complicated too. Try this if you want to shorten it

D3DXMATRIX t_mat = *D3DXMatrixIdentity(&t_mat);

//multiply view and projection matrices together to give current
//view frustum
D3DXMatrixMultiply(&t_mat, &t_view, &t_proj);
//D3DXMatrixMultiply(&t_mat, &t_proj, &t_view);

//left side
bc_frustum[0] = D3DXPLANE(t_mat._14 + t_mat._11,
t_mat._24 + t_mat._21,
t_mat._34 + t_mat._31,
t_mat._44 + t_mat._41);
D3DXPlaneNormalize(&bc_frustum[0], &bc_frustum[0]);

//right side
bc_frustum[1] = D3DXPLANE(t_mat._14 - t_mat._11,
t_mat._24 - t_mat._21,
t_mat._34 - t_mat._31,
t_mat._44 - t_mat._41);
D3DXPlaneNormalize(&bc_frustum[1], &bc_frustum[1]);

//bottom
bc_frustum[2] = D3DXPLANE(t_mat._14 + t_mat._12,
t_mat._24 + t_mat._22,
t_mat._34 + t_mat._32,
t_mat._44 + t_mat._42);
D3DXPlaneNormalize(&bc_frustum[2], &bc_frustum[2]);

//top
bc_frustum[3] = D3DXPLANE(t_mat._14 - t_mat._12,
t_mat._24 - t_mat._22,
t_mat._34 - t_mat._32,
t_mat._44 - t_mat._42);
D3DXPlaneNormalize(&bc_frustum[3], &bc_frustum[3]);

//near
bc_frustum[4] = D3DXPLANE(t_mat._13, t_mat._23,
t_mat._33, t_mat._43);
D3DXPlaneNormalize(&bc_frustum[4], &bc_frustum[4]);

//far
bc_frustum[5] = D3DXPLANE(t_mat._14 - t_mat._13,
t_mat._24 - t_mat._23,
t_mat._34 - t_mat._33,
t_mat._44 - t_mat._43);
D3DXPlaneNormalize(&bc_frustum[5], &bc_frustum[5]);

That would be shorter but I''ve formatted it a bit to make it easier to read. All the planes are normalised too.

When you check your sphere to the view frustum, I check two spheres per object.

The first sphere has a radious of the largest distance from the centre of the bounding box to a corner of the bounding box.

If one of the checks against the 6 planes returns OUTSIDE (the sphere has a negative dot cord. and is further away from the plane than the dot coord then the object can''t be visible.

If the checks all return INSIDE then I can quit the function cus the entire object is visible.

If the checks return an INTERSECT with some of the planes I do another sphere-frustum check.

The second sphere has the same centre (the centre of the bounding box) but it''s radous is the shortest distance (from the centre of the box to a side of the box (if the sides are normalised planes then this would be a dot coord).

If this returns INTERSECT as well then there''s a DEFFINETE INTERSECTION otherwise there''s a POSSIBLE INTERSECTION.

This is useful for clipping octree''s to the view frustum. If it''s INSIDE then render the octree segment, OUTSIDE - ignore the segment, DEFFINETE INTERSECTION - check the segment''s children, POSSIBLE INTERSECTION - check the segments corners (bounding box corners) to make sure.

Using twio spheres reduces the work load as once you''ve calculated the dot coords you can compare them to both radiouses because the sphere centres are the same.

Hope this helps

Matt

Share this post


Link to post
Share on other sites
quote:
Original post by Mezz
Just out of interest John, why do you have your frustum plane normals pointing outward?


My frustum is a collision volume, and I want it to work the same as the rest of my collision volumes. Culling isn''t the same as collision, so eventually I might stop using my collison code to do frustum culling. Then I might make the normals point inward.

Share this post


Link to post
Share on other sites