As Metric has progressed, I started running into frame rate drops while debugging. Naturally the game is going to run slower when Visual Studio is debugging it and it’s not a problem when the game is running as a Release. But it showed that our Vertices Engine needed some of those long planned optimizations added in.
One among them was Camera Frustum culling, or essentially, only draw what the Camera sees. The GPU already performs Triangular Culling, cutting out any tri’s that aren’t on the screen, but there are large improvements if only 25% of data needs to be sent to the GPU in the first place each frame.
I looked at the implementation that was talked about over here and it was a good starting point, but decided there were some improvements I could make.
We need Boundaries
First thing to do is to find the bounds of each Model. When each vxEntity3D is first initialized, the model data is used to define the models BoundingSphere and model center.
public static BoundingSphere GetModelBoundingSphere(Model model)
{
// Initialize minimum and maximum corners of the bounding box to max and min values
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
// For each mesh of the model
foreach (ModelMesh mesh in model.Meshes)
{
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
// Vertex buffer parameters
int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
int vertexBufferSize = meshPart.NumVertices \* vertexStride;
// Get vertex data as float
float\[\] vertexData = new float\[vertexBufferSize / sizeof(float)\];
meshPart.VertexBuffer.GetData<float>(vertexData);
// Iterate through vertices (possibly) growing bounding box, all calculations are done in world space
for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
{
Vector3 vert = new Vector3(vertexData\[i\], vertexData\[i + 1\], vertexData\[i + 2\]);
min = Vector3.Min(min, vert);
max = Vector3.Max(max, vert);
}
}
}
// The Center will be the average of the Max and Min
Vector3 Center = Vector3.Add(max, min)/2;
// The Radius will be half the difference between the max and min
float Raduis = Vector3.Subtract(max, min).Length() / 2;
// Create and return bounding box
return new BoundingSphere(Center, Raduis);
}
view raw GetModelBoundingSphere.cs hosted with ❤ by GitHub
Then each update call, the center is transformed by the World matrix, which then positions the bounding sphere to the orientation of the Entities Model.
// Reset the Bounding Sphere’s Center Position
BoundingShape.Center = Vector3.Transform(ModelCenter, World);
The result is this:

The green circles are the debug view of the Model’s BoundingSphere.
The Camera’s Point of View
Now that the Entities bounds are defined, next we need to define the Camera Frustum. This turns out not to be too complicated at all. I added a public BoundingFrustum field in the vxCamera3D class which is updated each loop with the view and projection matrices.
_// Set the Bounding Frustum
B_oundingFrustum.Matrix = View * Projection;
Can you See me?
Now with all the bounding shapes set up, the last thing to do is to put it all together. In each vxEntity3D‘s update loop, it checks to see if the Camera Frustum intersects it’s transformed Bounding Sphere. It then sets the boolean IsInCameraViewFrustum field to the value of whether it intersects the view frustum.
// Reset the Bounding Sphere's Center Position
BoundingShape.Center = Vector3.Transform(ModelCenter, World);
// Now Check if this entity is even in view of the camera
IsInCameraViewFrustum = Camera.IsInViewFrustrum(BoundingShape);
[view raw](https://gist.github.com/rtroe/cb3da8add1463452d31bbb4c86f81549/raw/61232e9716fea2cf9f27d5d9a17f3441714ebb8f/Set%20Bounding%20Sphere%20Position.cs) [Set Bounding Sphere Position.cs](https://gist.github.com/rtroe/cb3da8add1463452d31bbb4c86f81549#file-set-bounding-sphere-position-cs) hosted with ❤ by [GitHub](https://github.com)
Where the _**Camera.****IsInViewFrustum**_ function is simply just:
public bool IsInViewFrustrum(BoundingSphere boundingSphere)
{
return BoundingFrustum.Intersects(boundingSphere);
}
view raw IsInViewFrustrum.cs hosted with ❤ by GitHub
Then in the draw calls, the Model is only drawn if the IsInCameraViewFrustum bool is true.
Results?
It was like I plugged in a new GPU. It started running quick and fast at 60 fps only stuttering when the entire scene was in view.
There’s a list of other optimizations I need to implement, mainly to do with the Renderering and ensuring only required info is sent to the GPU each call. But for now, this is a solid first step.