Frustum Culling in Direct3D

Started by
15 comments, last by Razor89 19 years, 4 months ago
I have searched EVERYWHERE for code or detailed information.. ANYTHING. My objective so far has been to implement frustum culling in my Direct3D graphics engine then build a couple of functions to determine if a vector, sphere, or most of all, a box, is in the frustum. But so far out of all my endless amounts of searching (via Google and AltaVista) and experamentation, no luck. So maybe somebody could help me out? I am using Visual Basic .NET (thus Managed DirectX) but if any code or langauge specific things are brought up, C# will do as well. I did try to convert the code from "cull" example in the C++ DX9 SDK, but it didn't work. I want to use it to implement a octree and/or quadtree for various purposes, e.g. Terrain engine, Wolf3D type environment (one from the early 90's), etc.. If you can help or point me somewhere THANK YOU SO MUCH!
"You and I are friends; when you cry, I cry. When you laugh, I laugh. When you hurt, I hurt. When you jump off a bridge....... I am sure going to miss you!"
Advertisement
how about this flipcode article here http://www.flipcode.com/articles/article_frustumculling.shtml its pretty good, i used this to implement frustum culling for my engine. [google] link http://www.google.com.au/search?hl=en&q=frustum%2Bculling&btnG=Search&meta= returns heaps of information! if you want an octree example then here is the best i've seen http://www.gametutorials.com/Tutorials/OpenGL/OpenGL_Pg5.htm
This explains how to extract the frustum planes from the view-projection matrix. Then you can take a look at frustum-AABB intersection routines, like those mentioned here. This also looks interesting.

Call me stupid, but I've looked at the plane extraction document from RavenSoft,
but not quite sure what to make of it. As for everything else,
its all "in OpenGL", and since I don't know
OpenGL, so I can't make anything out too well of that either :(
"You and I are friends; when you cry, I cry. When you laugh, I laugh. When you hurt, I hurt. When you jump off a bridge....... I am sure going to miss you!"
Although... I just found some sample code in that document, that for some reason
I never noticed before. Hopefully this will answer my question.

Now do I feel stupid. lol
"You and I are friends; when you cry, I cry. When you laugh, I laugh. When you hurt, I hurt. When you jump off a bridge....... I am sure going to miss you!"
Just one last thing. Here is the sample code from
the plane extraction pdf:

struct Matrix4x4{// The elements of the 4x4 matrix are stored in// row-major order.float _11, _12, _13, _14;float _21, _22, _23, _24;float _31, _32, _33, _34;float _41, _42, _43, _44;};void ExtractPlanesD3D(Plane * p_planes,const Matrix4x4 & comboMatrix,bool normalize){// Left clipping planep_planes[0].a = comboMatrix._14 + comboMatrix._11;p_planes[0].b = comboMatrix._24 + comboMatrix._21;p_planes[0].c = comboMatrix._34 + comboMatrix._31;p_planes[0].d = comboMatrix._44 + comboMatrix._41;// Right clipping planep_planes[1].a = comboMatrix._14 - comboMatrix._11;p_planes[1].b = comboMatrix._24 - comboMatrix._21;p_planes[1].c = comboMatrix._34 - comboMatrix._31;p_planes[1].d = comboMatrix._44 - comboMatrix._41;// Top clipping planep_planes[2].a = comboMatrix._14 - comboMatrix._12;p_planes[2].b = comboMatrix._24 - comboMatrix._22;p_planes[2].c = comboMatrix._34 - comboMatrix._32;p_planes[2].d = comboMatrix._44 - comboMatrix._42;// Bottom clipping planep_planes[3].a = comboMatrix._14 + comboMatrix._12;p_planes[3].b = comboMatrix._24 + comboMatrix._22;p_planes[3].c = comboMatrix._34 + comboMatrix._32;p_planes[3].d = comboMatrix._44 + comboMatrix._42;// Near clipping planep_planes[4].a = comboMatrix._13;p_planes[4].b = comboMatrix._23;p_planes[4].c = comboMatrix._33;p_planes[4].d = comboMatrix._43;// Far clipping planep_planes[5].a = comboMatrix._14 - comboMatrix._13;p_planes[5].b = comboMatrix._24 - comboMatrix._23;p_planes[5].c = comboMatrix._34 - comboMatrix._33;p_planes[5].d = comboMatrix._44 - comboMatrix._43;// Normalize the plane equations, if requestedif (normalize == true){NormalizePlane(p_planes[0]);NormalizePlane(p_planes[1]);NormalizePlane(p_planes[2]);NormalizePlane(p_planes[3]);NormalizePlane(p_planes[4]);NormalizePlane(p_planes[5]);}}


What goes in parameter 'comboMatrix'? The projection, world, view, matrix?

[Edited by - Coder on December 15, 2004 2:16:03 AM]
"You and I are friends; when you cry, I cry. When you laugh, I laugh. When you hurt, I hurt. When you jump off a bridge....... I am sure going to miss you!"
View * Projection

This is a post by Razor98 from a duplicate, now closed, thread:

Could somebody explain to me why this doesn't work?

Here is my plane extraction code (VB.NET):
        Public Sub ExtractFrustumPlanes(Optional ByVal Normalize As Boolean = True)            Dim comboMatrix As Matrix = Matrix.Multiply(ccCore.Device.Transform.View, ccCore.Device.Transform.Projection)            'Left clipping plane            ccFrustum(0).A = comboMatrix.M14+ comboMatrix.M11            ccFrustum(0).B = -(comboMatrix.M24+ comboMatrix.M21)            ccFrustum(0).C = -(comboMatrix.M34+ comboMatrix.M31)            ccFrustum(0).D = -(comboMatrix.M44+ comboMatrix.M41)            'Right clipping plane            ccFrustum(1).A = -(comboMatrix.M14- comboMatrix.M11)            ccFrustum(1).B = -(comboMatrix.M24- comboMatrix.M21)            ccFrustum(1).C = -(comboMatrix.M34- comboMatrix.M31)            ccFrustum(1).D = -(comboMatrix.M44- comboMatrix.M41)            'Top clipping plane            ccFrustum(2).A = -(comboMatrix.M14- comboMatrix.M12)            ccFrustum(2).B = -(comboMatrix.M24- comboMatrix.M22)            ccFrustum(2).C = -(comboMatrix.M34- comboMatrix.M32)            ccFrustum(2).D = -(comboMatrix.M44- comboMatrix.M42)            'Bottom clipping plane            ccFrustum(3).A = -(comboMatrix.M14+ comboMatrix.M12)            ccFrustum(3).B = -(comboMatrix.M24+ comboMatrix.M22)            ccFrustum(3).C = -(comboMatrix.M34+ comboMatrix.M32)            ccFrustum(3).D = -(comboMatrix.M44+ comboMatrix.M42)            'Near clipping plane            ccFrustum(4).A = -(comboMatrix.M14+ comboMatrix.M13)            ccFrustum(4).B = -(comboMatrix.M24+ comboMatrix.M23)            ccFrustum(4).C = -(comboMatrix.M34+ comboMatrix.M33)            ccFrustum(4).D = -(comboMatrix.M44+ comboMatrix.M43)            'Far clipping plane            ccFrustum(5).A = -(comboMatrix.M14- comboMatrix.M13)            ccFrustum(5).B = -(comboMatrix.M24- comboMatrix.M23)            ccFrustum(5).C = -(comboMatrix.M34- comboMatrix.M33)            ccFrustum(5).D = -(comboMatrix.M44- comboMatrix.M43)            If Normalize Then                For I As Integer = 0 To 5                     ccFrustum(I).Normalize()                    'NormalizePlane(ccFrustum(I))                Next            End If        End Sub


And my sphere testing code (of course, also VB.NET):

        Public Function FrustumTestSphere(ByVal vCenter As m3dVector3D, ByVal Radius As Single) As Boolean            Dim Distance As Single            Dim tCenter As Vector3            tCenter = vCenter.ToVector3            tCenter.TransformCoordinate(ccCore.Device.Transform.World)            For I As Integer = 0 To 5                 Distance = Plane.DotNormal(ccFrustum(I), tCenter)                Debug.WriteLine(Distance)                If Distance < -Radius Then                    Return False                End If            Next            Return True        End Function

Thanks!

The code could not work because MDX uses a left-handed coordinate system, which means that the matrix is not row-major.
To avoid that you will have to create the view matrix using the LookAtRH() method instead of LookAtLH().
Note that you will have to convert your Z-values in that case, too because the axis will be inversed.

Good luck,
Pat.
Hi, here is some code straight from a Direct3D app I have written that calcs the view frustum the AABB a sphere and a cone:

void CFrustum::Calculate(const D3DXMATRIX *matView,const D3DXMATRIX *matProj,		const D3DXVECTOR3 &position,const D3DXVECTOR3 &look,float fov,unsigned int screenWidth,unsigned int screenHeight)	{		// Get combined matrix		D3DXMATRIXA16 matComb;		D3DXMatrixMultiply(&matComb, matView, matProj);			// Left clipping plane			m_frustumPlanes[0].m_normal.x = matComb._14 + matComb._11; 		m_frustumPlanes[0].m_normal.y = matComb._24 + matComb._21; 		m_frustumPlanes[0].m_normal.z = matComb._34 + matComb._31; 		m_frustumPlanes[0].m_distance = matComb._44 + matComb._41;		// Right clipping plane 		m_frustumPlanes[1].m_normal.x = matComb._14 - matComb._11; 		m_frustumPlanes[1].m_normal.y = matComb._24 - matComb._21; 		m_frustumPlanes[1].m_normal.z = matComb._34 - matComb._31; 		m_frustumPlanes[1].m_distance = matComb._44 - matComb._41;		// Top clipping plane 		m_frustumPlanes[2].m_normal.x = matComb._14 - matComb._12; 		m_frustumPlanes[2].m_normal.y = matComb._24 - matComb._22; 		m_frustumPlanes[2].m_normal.z = matComb._34 - matComb._32; 		m_frustumPlanes[2].m_distance = matComb._44 - matComb._42;		// Bottom clipping plane 		m_frustumPlanes[3].m_normal.x = matComb._14 + matComb._12; 		m_frustumPlanes[3].m_normal.y = matComb._24 + matComb._22; 		m_frustumPlanes[3].m_normal.z = matComb._34 + matComb._32; 		m_frustumPlanes[3].m_distance = matComb._44 + matComb._42;		// Near clipping plane 		m_frustumPlanes[4].m_normal.x = matComb._13; 		m_frustumPlanes[4].m_normal.y = matComb._23; 		m_frustumPlanes[4].m_normal.z = matComb._33; 		m_frustumPlanes[4].m_distance = matComb._43;		// Far clipping plane 		m_frustumPlanes[5].m_normal.x = matComb._14 - matComb._13; 		m_frustumPlanes[5].m_normal.y = matComb._24 - matComb._23; 		m_frustumPlanes[5].m_normal.z = matComb._34 - matComb._33; 		m_frustumPlanes[5].m_distance = matComb._44 - matComb._43; 		// Normalise them - only needed if later calcs require an accurate distance		for (int i=0;i<6;i++)			m_frustumPlanes.Normalise();			// Calc frustum AABB		// Create some points relative in clip space then transform them on to the far plane		D3DXVECTOR3 p[8];		p[0]=D3DXVECTOR3(-1.0f,1.0f,1.0f);		p[1]=D3DXVECTOR3(-1.0f,-1.0f,1.0f);		p[2]=D3DXVECTOR3(1.0f,-1.0f,1.0f);		p[3]=D3DXVECTOR3(1.0f,1.0f,1.0f);		p[4]=D3DXVECTOR3(-1.0f,1.0f,0.0f);		p[5]=D3DXVECTOR3(-1.0f,-1.0f,0.0f);		p[6]=D3DXVECTOR3(1.0f,-1.0f,0.0f);		p[7]=D3DXVECTOR3(1.0f,1.0f,0.0f);		D3DXMATRIX cameraWorldMatrix;		CMaths::MakeMatrixFor3d(&cameraWorldMatrix,position,D3DXVECTOR3(0,0,0));	   		// Transform to far plane using the inverse combined matrix of proj, view and world		D3DXMATRIXA16 projView;		D3DXMatrixMultiply(&projView, matView, matProj);		D3DXMATRIXA16 projViewWorld;		D3DXMatrixMultiply(&projViewWorld, &projView, &cameraWorldMatrix);						D3DXMATRIXA16 invProjViewWorld;		D3DXMatrixInverse(&invProjViewWorld,NULL,&invProjViewWorld);		D3DXMATRIXA16 invProjView;		D3DXMatrixInverse(&invProjView,NULL,&projView);		D3DXMATRIXA16 final=invProjView;		D3DXVECTOR3 planePnts[8];		for (i=0;i<8;i++)			D3DXVec3TransformCoord(&planePnts, &p, &final);		D3DXVECTOR3 min=position; // defaults		D3DXVECTOR3 max=position;		for (i=0;i<8;i++)		{			min.x=min(min.x,planePnts.x);			min.y=min(min.y,planePnts.y);			min.z=min(min.z,planePnts.z);			max.x=max(max.x,planePnts.x);			max.y=max(max.y,planePnts.y);			max.z=max(max.z,planePnts.z);		}		m_frustumAABB->SetMinimum(min);		m_frustumAABB->SetMaximum(max);		// Calculate bounding sphere - needs to be in centre of frustum with radius that goes to the far corner		// on the far plane		// Centre of sphere is half way between near and far clipping planes along the view vector of the camera		// starting at the camera position		// Calculate the radius of the frustum sphere		float frustumLength=m_frustumPlanes[FAR_CP].m_distance-m_frustumPlanes[NEAR_CP].m_distance;		// Calculate the height of the frustum at that distance, use some trig		// Its a half angle of course		float frustumFarHeight=frustumLength*tan(fov*0.5f);		float frustumFarWidth=frustumFarHeight; // correct when aspect ratio is 1		// Centre point in frustum is half way from near plane along length		D3DXVECTOR3 centre(0.0f,0.0f,m_frustumPlanes[NEAR_CP].m_distance+frustumLength*0.5f);		// Far corner point (top right)		D3DXVECTOR3 farCorner(frustumFarWidth,frustumFarHeight,frustumLength);		// Vector between the far corner and the centre:		D3DXVECTOR3 v=centre-farCorner;		// Radius is length of this vector		float radius=D3DXVec3Length(&v);		// Now get centre of sphere in world space		D3DXVECTOR3 sphereCentre=position+look* ((frustumLength*0.5f)+m_frustumPlanes[NEAR_CP].m_distance);		//_frusSphere.Center() = m_vCameraPosition + (vLookVector * (fViewLen * 0.5f) + m_fNearPlane);		m_frustumSphere->SetCentre(sphereCentre);		m_frustumSphere->SetRadius(radius);		// Calculate the bounding cone		// Its position is simply the position of the camera and its direction is the look		m_frustumCone->SetPosition(position);		m_frustumCone->SetFacing(look);		// The angle is a bit more tricky, if we set it to the same as FOV then the cone will be inside the frustum		// Instead we need it to encompass the corners of the frustum and not just the sides, use trig		// We use the screen sizes to get the angle between the centre of the viewport to the corner of it						float halfScreenHeight=(0.5f*screenHeight);		float halfScreenWidth=(0.5f*screenWidth);		// calculate the length of the fov triangle		float depth  = halfScreenHeight / tan(fov * 0.5f);// calculate the corner of the screen		float corner = sqrt(halfScreenWidth * halfScreenWidth + halfScreenHeight * halfScreenHeight);// now calculate the new fov		float coneFov = atan(corner / depth);		m_frustumCone->SetSpreadAngle(coneFov);	}


hope that helps
------------------------See my games programming site at: www.toymaker.info

This topic is closed to new replies.

Advertisement