2

I have a third person camera that contains two matrices: view and projection, and two Vector3's: camPosition and camTarget. I've read up on frustum culling and it makes it seem easy enough for a first person camera, but how would I implement this for a third person camera? I need to take into effect the objects I can see behind me too. How would I implement this into my camera class so it runs at the same time as my update method?

    public void CameraUpdate(Matrix objectToFollow)
    {
        camPosition = objectToFollow.Translation + (objectToFollow.Backward *backward) + (objectToFollow.Up * up);
        camTarget = objectToFollow.Translation;

        view = Matrix.CreateLookAt(camPosition, camTarget, Vector3.Up);
    }

Can I just create another method within the class which creates a bounding sphere with a value from my camera and then uses the culling based on that? And if so, which value am I using to create the bounding sphere from?

After this is implemented, I'm planning on using occlusion culling for the faces of my objects adjacent to other objects. Will using just one or the other make a difference? Or will both of them be better? I'm trying to keep my framerate as high as possible

Andrew Russell
  • 21,268
  • 7
  • 56
  • 103
Christian Frantz
  • 409
  • 3
  • 14

1 Answers1

2

First of all, let's talk about culling as a performance optimisation. All the usual rules of performance optimisation apply: you should measure it! Are you below your performance target? And what's hurting your performance?

Basically: no point in including performance optimisations all willy-nilly.

That being said - maybe you've already measured it and you do have a performance problem. Object culling can help you stay within your batch limit. Occlusion culling individual faces is more likely to hurt performance than to help. For the class of performance problems that this optimisation feels like it should solve, early Z or occlusion queries are, perhaps, the correct optimisations to persue.


Now I've got all that out of the way, I have good news: frustum culling for a third-person camera is exactly the same as for a first-person camera. It's the same for basically any kind of camera.

You take your camera's matrix, which is view * project, and create a BoundingFrustum (MSDN), which you can then use to perform intersection tests for culling.

You're basically creating a cut-off pyramid extending from the camera - this shape:

http://i.msdn.microsoft.com/dynimg/IC47709.gif

And anything that intersects that shape is what will be visible within your camera volume. That shape is the same between both camera types.


The reason this works is because a camera matrix takes vertices in world space, moves them "in front" of the camera with view matrix, and then projects them (with your project matrix) into a region from (-1,-1,0) to (1,1,1) within which the GPU's rasterizer actually performs its rendering.

BoundingFrustum simply reverses that process - taking the corners of the raster space and unprojecting them back out into world space.

Andrew Russell
  • 21,268
  • 7
  • 56
  • 103
  • Well the reason my fps is so low is because I'm trying to draw 10,000 cubes, but all with their own vertex buffer. The reason for this is because I don't know how to store them in a chunk and just draw the chunk. I also don't know how to edit an individual cube within a chunk. So I'm trying out occlusion and frustum culling first to see if it has any difference on a huge size map – Christian Frantz Jun 27 '13 at 05:29
  • Ah I now realize that I can use the frustum in my camera class for picking too. I also need to create bounding boxes for each one of my cubes that are being drawn. So if I have a cube class and a camera class, where am I putting the code that checks for the intersection and removes the unseen cubes? – Christian Frantz Jun 27 '13 at 05:41
  • @ChristianFrantz I think this answer you got before still applies. I'd strongly suggest investing the time in figuring out that approach. One vertex buffer per chunk, only include exposed faces in that buffer. (And then you might frustum-cull entire chunks). Rendering individual cubes is very much the wrong approach. – Andrew Russell Jun 27 '13 at 05:45
  • @ChristianFrantz (In answer to your newer comment) You'd use BoundingBox - have one for each cube - and do the intersection check right before you draw the cube. (Again - not the right approach - but that's how you'd do it.) – Andrew Russell Jun 27 '13 at 05:47
  • Ok so I'm pretty much wasting time trying to use the frustum. Can you give me an example of how to make a chunk of cubes? I would guess to loop through the vertices and change the offset of each one slighty so they have different positions, but that would still create a lot of vertices – Christian Frantz Jun 27 '13 at 05:50
  • @ChristianFrantz Lots of vertices isn't really a big problem. There's a more advanced discussion over here about advanced techniques for reducing vertex count. But the primary one would be what tp1337 answered on your other question - skip inside faces. You wouldn't loop over vertices. You'd loop through the cubes in the chunk and build the vertex buffer appending faces where necessary. (A more advanced approach might allow you to modify the buffer in-place. But a "fresh build each time" approach is an excellent starting point.) – Andrew Russell Jun 27 '13 at 05:56
  • Alright so let me try to break this down...1) Create a vertex buffer for one cube. 2)Store the cubes in a "chunk", in my case, this would be a list that stores the cubes and their positions. 3)Before drawing the cubes, loop through the cubes in the list and decide which faces are touching. 4) Draw the list or "chunk" – Christian Frantz Jun 27 '13 at 06:02
  • Not quite. (1) Whenever a chunk is modified (or first created), loop through all the cubes in that chunk. (2) For each cube, if it has visible faces, append those faces to CPU-side lists of vertices/indices for that chunk. (3) Convert those lists into GPU-side buffers (ie: VertexBuffer, IndexBuffer). (4) Then, at draw time, simply draw the whole chunk from those buffers with a single draw call. (Optionally: check if the chunk intersects the view frustum, and skip drawing it if it does not). – Andrew Russell Jun 27 '13 at 06:10
  • What do you mean by CPU side lists? I've updated my question to include all the code I'm using to create the list of cubes that I draw. Would it work if I added a method to my draw list that checked each side to see if it was touching another, and call that method from the draw method within the CubeList class? – Christian Frantz Jun 27 '13 at 06:19
  • Or would I be better off creating the method within the cube class and calling that method in the constructor of my cube? That makes more sense to me – Christian Frantz Jun 27 '13 at 06:21
  • I've reverted your edit, because it really belongs in a fresh question - leave this one about frustum culling. In fact, this comment chain is already getting very long. By CPU side list I mean any CPU-side data structure you can eventually get into a VertexBuffer. List and then ToArray() would work. But using an array directly would be better - although you must manage its size yourself. – Andrew Russell Jun 27 '13 at 06:52