Jump to content

Voxel rendering without too many draw calls


fenomas
 Share

Recommended Posts

I am rendering Minecraft-style terrain, but I can't find a way to make it scale well in BJS. Basically the terrain has two important features:

 

1. Terrain must be split into chunks (so that pieces of terrain can be added/removed/changed quickly)

2. Each chunk of terrain contains a variety of textures

 

I built this the straightforward way - one parent mesh for each chunk, and one child mesh for each texture in that chunk. The problem is that if there are N chunks of terrain visible, and M different textures in each chunk, then this requires N*M draw calls to render. For even a minimal game N might be several hundred and M a few dozen, so N*M can quickly reach 10K draw calls.

 

Is there any better way to make the BJS meshes or materials, to reduce the draw calls?

 
(Notes: I'm not using instancing because each voxel face can look different due to AO and lighting. I have not tried things like mesh simplification because here the number of vertexes is not necessarily high - it's the number of draw calls that spirals out of control.)
Link to comment
Share on other sites

@fenomas, I wrote a library for this, though it only supports colored voxels (no textures, feel free to implement. :3) and no ambient occlusion, it does have greedy meshing which greatly helps performance. It uses one draw call per-chunk (two if using transparent voxels, which uses an additional mesh and is rather hacky), and chunks can have any size/dimensions.

 

Repo: https://github.com/TriBlade9/CEWBS

Examples: (Unfinished) http://triblade9.github.io/CEWBS/example/examples/animation/index.html : http://triblade9.wc.lt/CEWBS/

Forum thread: http://www.html5gamedevs.com/topic/10688-library-cewbs-voxel-mesher-and-helper-utilities/

Link to comment
Share on other sites

Thanks Stephen, I saw your very fine library before I started. You're welcome to plunder my code for AO and textures if you like, though I'm not sure it's worth it if there is some crazy new voxel support coming soon..

http://andyhall.github.io/noa-hello-world/

Incidentally I profiled your lib at some point and I recall that having bjs calculate the normals was taking a really big chunk of time. I think it would be way faster to make a normals array by hand (if you're still working with it).

Link to comment
Share on other sites

Wow fenomas, I greatly like your approach to a voxel game. The performance is quite good on my machine, almost twice as fast as my demos, which is quite remarkable. It seems like you're going in a minecraft-like direction, sort of like voxel.js. Your picking code in particular is far more efficient and sensible than mine, although I don't know if it works with rotated chunks.  If you happen to add non-grid-locked and non-dimension-locked voxel meshes, I will probably prefer your library over mine. x]

 

I may look into the normals issue, I noticed that as well. The demo also appears to run a lot slower in Chrome 36(8?)+ than in Chrome 35, which is a bit of a dissapointment. However I am no longer actively developing it due to some real-life constraints. (Though I check these forums every day)

 

Keep up the good work!

Link to comment
Share on other sites

Thanks Stephen. I'm not trying to recreate minecraft particularly, just round out the basic features that would be required to do so. To answer your comments, nothing in my mesher or renderer knows that all the chunks are unscaled and unrotated, I just haven't added non-terrain items yet. However the pick function is fast because it's testing against the world's voxel data; it has no idea there's meshing involved. (I didn't write it incidentally, I'm using 'voxel-raycast' from voxel.js). Picking against a scaled/rotated mesh could be done the same way if the picking vector was put into the mesh's local coords, but to apply it throughout a scene you'd need a broadphase test to know which meshes to test against. (I imagine BJS probably has a way to do that?)

 

The physics also works the same way - testing against a canonical 3D array of world voxels, not meshes. There again I'm using a library from voxel.js, though in that case it's one of mine.

 

About performance, yeah, I seem to recall that the builtin normal calculation was more than half the running time of your library, and since you have normals for free when meshing I'd think that would double your performance right there, if you ever feel like hacking on it. :)

Link to comment
Share on other sites

Meulta and deltakosh have been working on tweaking Babylon.js for a Minecraft like rendering. This has been presented during mstechdays at Paris. They have done a lot of work and gone far from our core engine. Etienne (Meulta) will soon share the code and approach.

 

Reminder - it would be great if someone could post some details about this. I have no idea whether the voxel work I'm doing overlaps with what you've done.

Link to comment
Share on other sites

Hello Guys,

 

I am sorry for the late anwser, I have had few spare time these last days. :)

 

Deltakosh and I wanted to create a perfomance technical demo for a big event we have in France. We thought trying to create a minecraft like game was a big challenge on the performance part so we gave it a try.

 

We have gone through a lot of different implementations and the one we are in right now is one where we have created a new type of mesh (BoxMesh) who is responsible for drawing 0 to X boxes. It is a dynamic one with a starting size where we preset a list of unpositioned boxes (with related normals and uvs). As we do not give positions, nothing is rendered. When we want to "display" a box we just edit the AGP array corresponding to indices and positions and we ask the mesh to refresh.

 

The advantage in this is that everything in the mesh is already set. All we have to do is to set the position and BAM, it is displayed. This is the fastest way to display a lot of boxes right now (but we never know, there might be a faster way :)).

 

At first we did not use chunks but the compute time to choose which box to display and hide depending on the player position was to much CPU costly. The current version uses chunks as a data store for the whole world data and chunk displayers to display them around the player. A chunk displayer contains one BoxMesh per material and has the capacity to display a chunk "data" object.

 

Our next step is to use a global atlas for textures to avoid having one BoxMesh per material and reduce it to one boxmesh per chunk.

 

I am currently writing a blog post about this and will publish the code as soon as possible. I would love to get your feedback once it is done ! :)

 

Meulta 

Link to comment
Share on other sites

Hi Meulta,

 

Thanks for the writeup, sounds interesting!

 

If I understand you correctly, it sounds like your project takes a very different approach to meshing than mine but they should be basically equivalent in the steady state (when no chunks are being created or re-meshed). If you want to compare performance mine is here - basically I implemented greedy meshing similar to what's done in voxel.js.

 

It will be great to see what you've made, and looking forward to seeing what you come up with regarding atlases!

Link to comment
Share on other sites

  • 3 weeks later...
  • 2 weeks later...

Our next step is to use a global atlas for textures to avoid having one BoxMesh per material and reduce it to one boxmesh per chunk.

 

I am currently writing a blog post about this and will publish the code as soon as possible. I would love to get your feedback once it is done ! :)

 

Hi,

 

Just a friendly reminder that it would be great to see what you guys were working on!

Link to comment
Share on other sites

Hey guys,

 

I wanted for everything to be ready before publishing (like the blog article which would come later... :))

 

I published a v0.1 here : https://github.com/BabylonJS/Samples/tree/master/Scenes/BoxMonger

 

Do not look too much at the code in the index.html file ;-)

Everything is happening in the .ts files.

 

There is a readme.

 

Any feedbacks will be appreciated !

 

Have fun,

 

Meulta

Link to comment
Share on other sites

Thanks Muelta! I'll have a look.

 

Initial thoughts:

 

1. Are you doing any culling of invisible faces? It looks like you're drawing all the unreachable faces between adjacent solid blocks - or am I missing something?

 

2. In the readme you mention doing collisions/gravity next - might want to check this.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...