Sign in to follow this  
BMW

Will empty vertices reduce FPS?

Recommended Posts

In my voxel engine (similar to minecraft), I create a array of vertices. This array is big enough to hold vertices for every block possible in the world, however not every block is present.

 

When I create the vertices, I first zero the vertices array, then create only the required vertices (backface culling). This results in a partially empty array of vertices, because some blocks do not exist and there are many faces culled. If I send this whole array into a vertex buffer, will this reduce performance? Because we will be sending a whole lot of empty vertices. Since the vertices array is fragmented, I cannot easily just send the vertices that exist (or non-zero vertices) without wasting precious CPU time calculating which ones to send.

 

Also, will calling DrawPrimitive for every block or even face reduce performance significantly? This way I can avoid drawing "empty vertices" by checking if the block exists and if the face is visible.

Edited by BMW

Share this post


Link to post
Share on other sites

If I send this whole array into a vertex buffer, will this reduce performance?

Yes, it will have a potential impact on the vertex shader/bandwidth performance, though how much performance depends on a lot of factors.

 

Since the vertices array is fragmented, I cannot easily just send the vertices that exist (or non-zero vertices) without wasting precious CPU time calculating which ones to send.

Just add a cache for blocks (e.g. 16x16x16), pre-generate them in a secondary thread and switch from your standard block rendering to your optimized and cached block rendering, once a block has been optimized. This is a common approach (e.g. texture streaming works similar) which will not introduce processing spikes or heavy CPU usage. For a cache use a simple LRU at first.

Share this post


Link to post
Share on other sites

Just add a cache for blocks (e.g. 16x16x16), pre-generate them in a secondary thread and switch from your standard block rendering to your optimized and cached block rendering, once a block has been optimized. This is a common approach (e.g. texture streaming works similar) which will not introduce processing spikes or heavy CPU usage. For a cache use a simple LRU at first.

 

So you mean have 1 vertex buffer that can hold the vertices for 16x16x16 blocks, then load the vertices into that VB for each 16x16x16 chunk of blocks?

 

I just realized sending empty vertices to the GPU shouldn't be too bad, because I am only updating the vertex buffer when a block is changed, and each 16x256x16 chunk has its own VB, so it shouldn't be too much of a problem should it?

Edited by BMW

Share this post


Link to post
Share on other sites

I just realized sending empty vertices to the GPU shouldn't be too bad, because I am only updating the vertex buffer when a block is changed, and each 16x256x16 chunk has its own VB, so it shouldn't be too much of a problem should it?

Well, the thing get somewhat confusing. You need to differ between uploading the vertices and rendering the vertices. When you change a chunk (e.g. stored in a single VB), you need to upload the new content to the GPU. When doing it in a reasonable way, with not so frequent modifications, then this will not have a notable impact on performance.

 

The other thing is rendering. Rendering an array (simple tri-list) with lot of empty blocks (=degenerated tris which will get culled ?), then the GPU need to process all the empty vertices in the vertex shader stage at least. Modern render engines are often pixel shader bound, but voxels are notorisous memory intensive and if you render a voxel map 1:1, this will eventually have a bad impact on.

Share this post


Link to post
Share on other sites

In my voxel engine (similar to minecraft), I create a array of vertices. This array is big enough to hold vertices for every block possible in the world, however not every block is present.

 

When I create the vertices, I first zero the vertices array, then create only the required vertices (backface culling). This results in a partially empty array of vertices, because some blocks do not exist and there are many faces culled. If I send this whole array into a vertex buffer, will this reduce performance? Because we will be sending a whole lot of empty vertices. Since the vertices array is fragmented, I cannot easily just send the vertices that exist (or non-zero vertices) without wasting precious CPU time calculating which ones to send.

 

Also, will calling DrawPrimitive for every block or even face reduce performance significantly? This way I can avoid drawing "empty vertices" by checking if the block exists and if the face is visible.

If you send all the vertices to the card then they're not really "empty" AFAIK.

What do you initialize the values of the empty vertices to?

 

How I do it is I reserve space the maximum possible number of vertices in a chunk (50% 3D checker),
Traverse and polygonize and then transfer up to the last valid vertex to the VBO for that chunk.

Share this post


Link to post
Share on other sites

I just realized sending empty vertices to the GPU shouldn't be too bad, because I am only updating the vertex buffer when a block is changed, and each 16x256x16 chunk has its own VB, so it shouldn't be too much of a problem should it?

Well, the thing get somewhat confusing. You need to differ between uploading the vertices and rendering the vertices. When you change a chunk (e.g. stored in a single VB), you need to upload the new content to the GPU. When doing it in a reasonable way, with not so frequent modifications, then this will not have a notable impact on performance.

 

The other thing is rendering. Rendering an array (simple tri-list) with lot of empty blocks (=degenerated tris which will get culled ?), then the GPU need to process all the empty vertices in the vertex shader stage at least. Modern render engines are often pixel shader bound, but voxels are notorisous memory intensive and if you render a voxel map 1:1, this will eventually have a bad impact on.

I am using a triangle-strip, and I call the DrawPrimitive function once for every cube face. Therefore I do not call the DrawPrimitive for blocks that don't exist, so I am not rendering empty vertices.

 

The only problem is the uploading of vertices into the GPU.

Share this post


Link to post
Share on other sites

In my voxel engine (similar to minecraft), I create a array of vertices. This array is big enough to hold vertices for every block possible in the world, however not every block is present.

 

When I create the vertices, I first zero the vertices array, then create only the required vertices (backface culling). This results in a partially empty array of vertices, because some blocks do not exist and there are many faces culled. If I send this whole array into a vertex buffer, will this reduce performance? Because we will be sending a whole lot of empty vertices. Since the vertices array is fragmented, I cannot easily just send the vertices that exist (or non-zero vertices) without wasting precious CPU time calculating which ones to send.

 

Also, will calling DrawPrimitive for every block or even face reduce performance significantly? This way I can avoid drawing "empty vertices" by checking if the block exists and if the face is visible.

If you send all the vertices to the card then they're not really "empty" AFAIK.

What do you initialize the values of the empty vertices to?

 

How I do it is I reserve space the maximum possible number of vertices in a chunk (50% 3D checker),
Traverse and polygonize and then transfer up to the last valid vertex to the VBO for that chunk.

I initialize the values of the empty vertices to zero.

Good idea, I might try that.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this