Frustum Culling and Instancing

Feb 14, 2012 at 1:30 PM

I've read that Sunburn does automatic frustum culling based on the viewport, but I don't see evidence of that when using a free floating camera in my 'cube world' made from lots of cube instances. I would expect FPS to go up quite a bit when changing the camera to look up at the 'sky' when no cubes are rendedered, but I don't see any change in frame rate no matter where I am looking or how many cubes are actually being rendered based on the camera position.

Is there an obvious setting on the camera or on the scene that I may be missing that would be preventing sunburn from culling? Does the culling work differently for the instancing? To be honest, I follow what the code is doing with instancing, but I don't fundamentally understand what is happening under the hood. Can instances even be culled automatically by the engine since, as I understand it, they are rendered on the hardware?

Feb 14, 2012 at 8:06 PM

I was wondering about that as well. I created 16384 cubes using IGF InstancingFactory and I get a framerate around 40.
And it doesn't change even if I move the camera where there isn't any cubes at all. Am I missing something? 

Basically I'm doing something like this:

            var instanceEffect = new DeferredObjectEffect(Application.Graphics.GraphicsDevice)
            {
                Skinned = true,
                DiffuseMapTexture = manager.Load<Texture2D>("Models/asteroid_diffuse")
            };

            var instancedBlock = new InstanceModel(model);
            var instancingManager = Application.SunBurn.GetManager<IInstancingManager>(true);
            var instanceFactory = instancingManager.CreateInstanceFactory(instancedBlock, instanceEffect);

            for (var x = 0; x < 128; x++)
                for (var y = 0; y < 128; y++)
                    instanceFactory.CreateInstance("Instance" + x + y, Matrix.CreateScale(5) * Matrix.CreateTranslation(new Vector3(10 * x, 0, 10 * y)));
 

Coordinator
Feb 14, 2012 at 8:44 PM

Hi guys,

There is still a lot of room for improvements in the Instancing feature.

The current implementation solely mimics the SunBurn sample but places the result in an InstanceEntity that you can then manipulate its World matrix independently.
However, because of a lack of time (and to be honest, because I didn't need this feature for my personal game), I didn't move further.

Right now, InstanceEntity instances are created and associated to a SceneObject which isn't culled at all because there are no generic ways to cull InstancedGeometry. I need to investigate the different options and then make a good class design to let you play indefinitivelly with it.

I'd still like to be sure of something:

Both of you are using cubes but I hope you're not trying to replicate a MineCraft like based game because Instancing isn't a good option for that. You may not be looking at it this way and therefore, you can forget this paragraph but I rather ask the question than seeing you spending a lot of time on a feature that wouldn't ever meet such requirements.

Instancing is really made for repeated elements in a scene such as Trees that only change on scale, rotation and position for instance. It can also be used for rocks or any other similar element.
Bamyazi has been working on a Skinned Instancing feature improvement for IGF to have tons of animated spiders in the scene for a lower cost but it is not ready yet.

Feb 14, 2012 at 9:17 PM
Edited Feb 14, 2012 at 9:44 PM


Hi!

Now that you mention it I need something similar to minecraft, but I'm actually making a tile-based strategy game that has 3D-blocks instead of 2D/Isometric tiles.

I actually need to make the terrain in blocks and I can't figure out how to draw more than 1000 blocks without losing a lot of performance.

I tried making 128x128 blocks terrain but I can't get it to work either with static objects or instancing without sinking my FPS too much.
The problem is that I have no idea how to go about this problem with drawing lots of cubes.

Got any suggestions on how I should go about making it?

Cheers.

EDIT: I need to be able to render at least 1500 cubes without any performance drop, since that's how many that will be visible on the screen at once.

Feb 14, 2012 at 9:22 PM

Ha, I am indeed trying to replicate a Minecraft game. Why do you say instancing isn't good for that? It seems to be working fairly well. When you consider all the leaves, repeated grass, repeated dirt, etc., instancing seems ideal. I was considering switching my internal storage to use a stack of quadtrees or an octree to improve culling.

I am caching an 'IsSurrounded' item for each block position that I use to immediately cull any blocks that shouldn't be rendered as a start.

Coordinator
Feb 15, 2012 at 8:02 AM

Geometry isn't a good option because it'll end up having a lot of non rendered vertices being sent to the GPU therefore putting some stress on the CPU => GPU memory exchange + bandwidth which therefore limits the frame rate. When you use instancing, all cubes will be sent to the graphics card even if they are occluded by others.

What you should look for is Voxel graphics. Techcraft that can be found here in Codeplex is a pretty good solution (http://techcraft.codeplex.com/). I don't know if this is on his plans but Bamyazi worked on it and it could potentially give you some tips on how to integrate this with SunBurn to make use of their lighting system.

Voxel should be the way to go for anything like MineCraft based rendering and culling.

Feb 15, 2012 at 2:01 PM

That assumes you aren't pre-culling your instances, right? I actually started out by looking at infiniminer and techcraft. Techcraft might warrant a second look for rendering, but my initial investigation left me wanting due to the procedural nature of the code that made it hard for me to glean the technique.

When you say 'Voxel' graphics, what does techcraft do that makes it truer 'Voxel' graphics than rendinger cubes? It's all about getting the cubes on the screen as effectively and efficiently as possible, right, so if you can pre-cull instances, seems like instancing would be pretty efficient at getting the cubes on the screen.

My thoughts include adding an abstraction on top of the instance storage to make it into a 64 cube block so it could map easily to an octree that would be a unit in a larger octree that could be used to cull.

"Voxel should be the way to go for anything like MineCraft based rendering and culling"

How are 'Voxel' and 'using hardware instancing to render cubes' mutually exclusive? When you say "Geometry isn't a good option", is that as opposed to 'Voxel'? I feel like I am missing something fundamental.

Feb 15, 2012 at 2:28 PM

I'm reading a good book on this topic:

http://books.google.com/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game%20engine%20gems&pg=PA39#v=onepage&q&f=false

I'm finding that much of my understanding of both efficient and effective internal representations and rendering is extremely naive (but hopefully becoming less so). :)

Feb 15, 2012 at 3:22 PM

I really have no idea what makes a voxel, what exactly is the difference between a voxel and a geometry cube?

http://www.youtube.com/watch?v=n_M9JI8htJ4

This clip is made by Bamyazi and looks incredible, must be thousands of blocks/voxels. I did take a look at TechCraft, but the code is really messy and I can't really get much out of it. There's too much code that doesn't have anything to do with the actual engine.

The above clip is working side to side with the SunBurn engine. It would be really cool if Bamyazi could make a plugin or something for SunBurn to make voxel graphics easier. But I have no idea how to contact him unfortunately.

Maybe someone else who's interested could ask him if he's interested in releasing a plugin or library of some sort. 

Coordinator
Feb 15, 2012 at 4:27 PM
KosmoKeLi wrote:

I really have no idea what makes a voxel, what exactly is the difference between a voxel and a geometry cube?

http://www.youtube.com/watch?v=n_M9JI8htJ4

This clip is made by Bamyazi and looks incredible, must be thousands of blocks/voxels. I did take a look at TechCraft, but the code is really messy and I can't really get much out of it. There's too much code that doesn't have anything to do with the actual engine.

The above clip is working side to side with the SunBurn engine. It would be really cool if Bamyazi could make a plugin or something for SunBurn to make voxel graphics easier. But I have no idea how to contact him unfortunately.

Maybe someone else who's interested could ask him if he's interested in releasing a plugin or library of some sort. 

You might be interested looking at the book reference SPponsJTD is currently reading. It'll explain you the differences.

Voxels are just a way to represent a volume just like pixels represent a point in a 2D plane. It's not the rendering side but what it actually is.

For instance, a pixel could be defined as a class containing a X and Y property (using int) and a R, G and B properties (using float). This could then be used to render a picture on screen in a process which would compute an entire 2D world.

SpoonsJTD wrote:

I'm reading a good book on this topic:

http://books.google.com/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game%20engine%20gems&pg=PA39#v=onepage&q&f=false

I'm finding that much of my understanding of both efficient and effective internal representations and rendering is extremely naive (but hopefully becoming less so). :)


Glad you found this book. That would become my next reference to achieve what you want to do ;)

Feb 16, 2012 at 3:53 PM
Edited Feb 16, 2012 at 4:12 PM

Thought i might chip in on this thread since my name came up.

The techcraft engine doesn't use instancing and was originally based on the infiniminer source.

Basically what it does is break the world up into chunks of 16x16x128 blocks. It then builds a mesh for each chunk - at its simplest this is done by looping through each block in the chunk and identifying which (if any) of its faces are visible. If a face is visible then add the vertices for the quad to draw the face to a list. When you're done convert the list to a vertexbuffer/renderablemesh/sceneobject - You can then cull blocks at the chunk level.

        private void BuildBlocks()
        {
            _vertexList.Clear();
            _indexList.Clear();
            _vertexCount = 0;

            for (int x = 0; x < SIZEX; x++)
            {
                for (int z = 0; z < SIZEZ; z++)
                {
                    //Debug.WriteLine(string.Format("{0},{1}", x, z));

                    Block thisBlock = _map.BlockAt(x + _xOffset, z + _zOffset);

                    Block blockXIncreasing = _map.BlockAt(x + _xOffset + 1, z + _zOffset);
                    Block blockXDecreasing = _map.BlockAt(x + _xOffset - 1, z + _zOffset);
                    Block blockZIncreasing = _map.BlockAt(x + _xOffset, z + _zOffset + 1);
                    Block blockZDecreasing = _map.BlockAt(x + _xOffset, z + _zOffset - 1);

                    BlockInfo thisInfo = _map.BlockLibrary[thisBlock.BlockType.ToString()];

                    BlockInfo xIncreasingInfo = _map.BlockLibrary[blockXIncreasing.BlockType.ToString()];
                    BlockInfo xDecreasingInfo = _map.BlockLibrary[blockXDecreasing.BlockType.ToString()];
                    BlockInfo zIncreasingInfo = _map.BlockLibrary[blockZIncreasing.BlockType.ToString()];
                    BlockInfo zDecreasingInfo = _map.BlockLibrary[blockZDecreasing.BlockType.ToString()];

                    if (thisInfo.Solid)
                    {
                        // Solid blocks only need the top face
                        BuildFace(FaceDirection.YIncreasing, thisBlock, thisInfo, x, z);
                    }
                    else
                    {
                        // Empty blocks 
                        // Bottom face
                        BuildFace(FaceDirection.YDecreasing, thisBlock, thisInfo, x, z);
                        if (xDecreasingInfo.Solid) BuildFace(FaceDirection.XDecreasing, thisBlock, thisInfo, x, z);
                        if (xIncreasingInfo.Solid) BuildFace(FaceDirection.XIncreasing, thisBlock, thisInfo, x, z);
                        if (zDecreasingInfo.Solid) BuildFace(FaceDirection.ZDecreasing, thisBlock, thisInfo, x, z);
                        if (zIncreasingInfo.Solid) BuildFace(FaceDirection.ZIncreasing, thisBlock, thisInfo, x, z);
                    }
                }
            }
        }
The above code is from my current project rather than techcraft but illustrates the point of generating a mesh for a chunk - In this case it just happens to be almost a tile based strategy game which uses 3d blocks :) The map is 200x200 broken up into 20x20 chunks. 

The video of the wizard shooting skeletons uses several techniques to cheat so it looks like a voxel engine but it isn't under the hood.

The static elements (trees/flowers etc) use exactly the same technique as the techcraft engine. The camera is simply positioned further away so the blocks look smaller.

The models are built in an editor called cubekingdom

http://translate.google.co.uk/translate?hl=en&sl=ja&u=http://cubekingdom.web.fc2.com/&ei=nfZxSrfAEZG5jAff15mqDA&sa=X&oi=translate&resnum=1&ct=result&prev=/search%3Fq%3Dhttp://cubekingdom.web.fc2.com/index.html%26hl%3Den

I built a custom pipeline importer which creates a model from the cubekingdom files. Animation is frame based (ie there are multiple meshes per model one per frame and they are shown/hidden as required)

The explosions actually do use instancing so i have control of the individual blocks seperately.

If you are interested in REAL voxel engines then this is a good starting point

http://advsys.net/ken/voxlap.htm,

If you're going to play with techcraft i'd suggest using the code from this changeset rather than the latest one

http://techcraft.codeplex.com/SourceControl/changeset/changes/74a56b60efed

Since it's a far simpler version and doesn't have all the AO and smooth lighting which make the mesh generation code far more complex. If you have any questions feel free to ask and i'll do what i can to help.

Alternatively go back to the source and get hold of the infiniminer code.

 

 

 

Feb 16, 2012 at 7:34 PM
Edited Feb 16, 2012 at 7:41 PM

I ended up doing exactly what you just said, creating a mesh for each chunk. :P
I guess I'm not as stupid as I thought I was. :)

Do you handle removal of blocks in your code as well? If that is the case, doesn't that mean you have to rebuild that whole chunk, taking vertexbuffer data, modify it and then setting it back and create a sceneobject from it?

Thank you so much for the information and for the links, I really appreciate it. 

EDIT:
Also, how would you handle collisions against a "block" if it's a single mesh? 

Feb 17, 2012 at 7:42 AM

If a block is removed then yes you have to rebuild the mesh for the whole chunk. If you're using Sunburn's lighting rather than the block based lighting you can probably get away with running the chunk generation on your main thread since 

rebuilding a chunk should be pretty fast. If you find that you're getting drops in framerate due to the chunk building the link someone else posted above has some good information about how you could move this process off the main thread so that chunk generation is done in the background. http://books.google.com/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game%20engine%20gems&pg=PA39#v=onepage&q&f=false

As for collision you can do all the checking against the map data that you use to build the mesh rather than the mesh itself so for player movement you're just checking if

map.blockAt(playerPosition + smallOffsetInMovementDirection).IsSolid or something similar. For identifying where to dig/build in a minecraft style game you project a ray in the direction the player is looking and step along it in small increments until you hit a block again though using the map data rather than the mesh. If you can find the player movement code in the techcraft link i posted it should be pretty clear.

Feb 17, 2012 at 7:58 AM

It is as I suspected. Thanks a lot for your help Bamyazi! :)

Feb 17, 2012 at 6:15 PM

bamyazi, thanks for the insight!

I think I've figured out that my thinking was flawed in terms of scale. Trying to generate a terrain on the scale of a minecraft-ish game doesn't work at the cube level, even with instancing, obviously. I think I was assuming incorrectly that the underlying engine was doing some kind of mesh simplification for me.

 

Feb 18, 2012 at 8:27 AM

I managed to create 1024 chunks 16x16x64 and it runs at 60 fps even when removing block, moved chunk rebuild to another thread. I can finally create my strategy game. :)

Mar 12, 2012 at 5:27 PM

On a bit of a tangent to the thread - it looks like the new block game on XBLIG miner4ever uses the core techcraft engine (a slightly brave choice imho given all the bugs still in there as can be seen by the various lighting and chunk loading issues it has). A slightly double edged sword as on the one hand i'm pleased that the code is being used and on the other slightly jealous since i've still not got around to finishing my own game :) Thems the breaks i guess though i open sourced it because i wasn't doing anything with it personally and believe in sharing - if the developer goes on to FortressCraft levels of success i'll be seriously envious though - just wish the he had mentioned the engine in the credits would have been nice to see the project come to life again on codeplex to see what people could add to it.

Coordinator
Mar 13, 2012 at 9:17 AM

I agree, they should at least submit back their changes and improvements (as well as any bug fixing) to the project.

And if I was them, and would make any real money out of Techcraft usage, I would definitively contact you to donate to the project...

Such non compliant behavior is lame from my perspective and could harm a lot open source initiatives.

Mar 15, 2012 at 7:29 PM

Heading totally off topic right now... we're using the TechCraft engine on GunCraft (http://www.kickstarter.com/projects/630555339/guncraft-voxel-based-first-person-shooter)... As you know I'm a big believer in feeding bug fixes back into open source (we put 99% of our updates and fixes back onto Mercury for example) but techcraft simply didn't lend itself well to that. 

For us to get the code to work within our game we were unable to use it as a standalone project - so we ended up spidering the source into our own. This means its impossible for us to pull individual fixes. We've also pulled a lot of the code that 'almost' works like the multthreaded renderer. We also don't need the landscapes generation (all our levels are hand crafted) or the dynamic load/save of chunks (too slow for what we need) so we have a gutted/modified version.

There's still several  the original lighting bugs in there though... one day I will look at those :-)

I promise you will get a credit though! And some beers if I ever meet you...

Coordinator
Mar 16, 2012 at 1:11 AM

Way to go thezman, I'm really eager to put my hands on GunCraft... There are some cool gameplay possibilities there ;)

Be sure to make the game moddable: let people put in their own modes some way, you'll benefit from it gaining visibility and additional sales if you get a couple of mods out afterward ;)

I've done a couple of improvements on Mercury myself and as soon as I get my head out of Ace on Steroids, IGF v0.9.2.0 release and finding a job (I'm really having high difficulties getting one), I'll push them back. Most of it are small bug fixing to support WP7 particles ;)