Download

[WIP] Procedural Voxel Generation In UE4

Hey everyone!

I just wanted to show off my progress working on procedural voxel generation in UE4. Ive only spent 4 or 5 days on this but Ive made some pretty good progress on it, but it still isnt much. The voxels are 50^3 UUs each and uses 2D Perlin noise with bilinear interpolation for the world generation, it takes in a seed, X, and Y coordinate then pops out a Z value to use. The code then takes that position and checks the positions of the surrounding voxels and adds the visible vertex positions relative to that position to an array of triangles. It then loops that for each block in the chunk (32x32x4), and when it is done with that chunk it renders the stored triangles. The process then starts all over for the next chunk. Originally I was using Instanced Static Meshes for the chunks but that took too much RAM so I changed to dynamically generated meshes, which cut back on the RAM usage tenfold. The map can generate infinitely but I dont have chunk streaming (or whatever I should call it) in yet, so I have to specify a static map size. Eventually Ill also get around to adding in a third dimension for the noise generation as density to make cool overhangs and caves, but right now Im working on fixing a few bugs in it and optimizing the whole process. So far on the optimization front Ive finished removing the unneeded polys and verts, the ones that were between other voxels, effectively tripling the world generation time (~.3 - ~.5 seconds per chunk now down to ~.1 - ~.2), tripling the FPS and cutting down the RAM usage by about 2/3rds (~2.5gb down to 800kb for a 512x512 map). In the coming days I should have that all fixed on top of chunk streaming based on the camera’s distance to the border of the playable chunks and report back here to show my findings :slight_smile:

If you have any questions on how I did it (or how I will do the future features I have planned), feel free to ask away. I didnt know a thing about perlin noise or dynamic mesh generation going into it, I spent a lot of time crawling the net to learn about perlin noise, and crawling the docs and forums for how to implement procedural meshes in UE4. Id also like to give a big thanks to any people from the community who posted on the forums and wiki about dynamic mesh generation!

Here are a few screenshots with various world generation settings that I just whipped up on the spot. As I said before, Ill add in 3D Perlin noise later, although the 2D right now is still pretty cool with the right settings. I have no clue how these specific settings will look but here they are anyway (All are on 512x512 block maps):

Smooth Map:
Seed 111111, 3 Octaves, 4000x zoom, .5 roughness, 10 intensity
771c38cf5c79c0881933b4e36e35764af4be2f99.jpeg
c204e4e4fe861bb52f667894bdef634c84aeb553.jpeg

Rough Map:
Seed 111111, 5 Octaves, 1000x zoom, .5 roughness, 10 intensity
0115b3fd0be9293813ed066587020958af2c9b98.jpeg
d7605d98fabb93dcb5c1ef5293ff36158959bdc9.jpeg
9020ebf9297d11057c4c7a83745011d49a9e8937.jpeg

Hilly Map:
Seed 206434, 3 Octaves, 4000x zoom, .5 roughness, 30 intensity
83306e6691b4cedb69bb8e1eb3f29ac2e009cae5.jpeg
(Sorry about the grid in this next one, I forgot to turn on Game View)
decfe70f3cf2898807410554da76949c95994d6f.jpeg
7634de64f7805ce3167953a1259cd003e2d5c074.jpeg

UPDATE:
This is the result of the optimization I did today, because of it I was able to extend the visible map by quite a bit and retain good framerate and memory usage. On top of that I also played around with the terrain generator some more, adding a few more options to it for a more playable landscape :stuck_out_tongue: . This will probably be the view distance I aim for when working on infinite terrain. Also I was mistaken, the 900mb RAM was for a 512x512 map, this was taking about 1.75gigs of RAM during PIE which is still pretty good for the size of the area displayed at once.

Thanks for taking a look at my procedural voxel terrain! Ill be working on new features for it soon! :smiley:
~Adam

Also Id like to thank to vblanco for helping me out with this! Hes taught me quite a bit about this sort of stuff :smiley:

wow this is amazing considering that you started with no background experience, sounds like you can do anything you set your will to!

Rama

Well Ive done programming in UE4 for a few months now, and Ive done things in UDK and Java for a few years now. I just havent done anything with procedurally generated meshes or perlin noise at all, so I have no experience with that :p.

I have been planning to do something like this too and I am wondering how difficult it is to create a plugin that allows you to edit the voxels in the unreal editor.
Are you going to make such an editor plugin?

Have you used blueprint a lot? Or It’s mostly C++ coding?

Ill probably release an easy to understand tutorial of some form in the future when Im finished with it. Maybe Ill release a plugin, who knows?

Its 100% C++, I have no clue if you could do dynamically generated meshes in Blueprint. I dont use Blueprint at all.

Looks pretty cool.

This is really cool. If you release a tutorial or a plugin, it would be really nice. Am sure the C++ community will benefit from it.

Looks great, at least all the Minecraft rip-off games (which there are far too many of) will look pretty now!

Awesome stuff

Thanks for sharing, I’ll be following in your footsteps over the next few days as I learn to do it myself.

Thanks for all the positive support guys :smiley:

Hey not all voxel games are Minecraft rip offs! :stuck_out_tongue: Take a look at Cube World for example! Minecraft is a far overrated game anyway, and youre right, too many rip offs :stuck_out_tongue:

Nice stuff! Looks like you have a lot in common with AndrewJSch and his BrickGame. Not sure if he does procedural generation tho, or just building.

Decided to give him a hand, and i got this

The voxel generation lags BRUTALLY when you enter the game, as it generates it when you enter. Some kind of multithreading or letting it work over several frames will help a bit. Interesting that it worked with collision at the first try.

I just finished up some new optimization stuff that made a massive impact. I removed all the faces of the voxels that were facing into another voxel by running the surrounding positions through my noise generator, then telling the dynamic mesh generator that those vertices for whatever face was next to another voxel didnt need to be added to the array. This nearly tripled the effectiveness of my code, world generation went down from ~.3 - ~.5 to ~.1 - ~.2 seconds per chunk, the FPS almost tripled, and the RAM usage got cut down by a little over 3 times, going from ~2.5gb for a 512x512 map to about 800kb.
This also allows me to go down vertically as much as I want. My chunks are now 32x32x(64+HeightOverZ) without any loss of performance!
Im very happy :smiley:

I made a video of the results of the optimization I did today, because of it I was able to extend the visible map by quite a bit and retain good framerate and memory usage. On top of that I also played around with the terrain generator some more, adding a few more options to it for a more playable landscape :stuck_out_tongue: . This will probably be the view distance I aim for when working on infinite terrain. Also I was mistaken, the 900mb RAM was for a 512x512 map, this was taking about 1.75gigs of RAM during PIE which is still pretty good for the size of the area displayed at once.

That looks amazing!

Great work!

Great framerates!

congratulations!

:wink:

Rama

What would be really awesome is if you could add something like Transvoxel to handle generating a “smooth” terrain mesh around the voxels.

Good work!

Maybe you’ve done some of this stuff already, but here are some tips for performance/memory:

  • Use uint8 for your vertex coordinates.

  • You can avoid storing TangentX/TangentZ for each vertex by drawing each face direction in a separate draw call, and then using a single-element vertex buffer with a stride of 0.

  • Drawing face directions in separate calls also lets you completely avoid drawing backfaces in chunks the viewer is outside the bounds of, though I don’t do this in BrickGrid yet.

  • You can avoid storing UVs for each vertex, and derive UVs from world position and normal in the pixel shader. In BrickGrid I do the even cheaper trick of just applying a global planar mapping that is 45 degrees off on all axes.

  • That means each vertex is only position, so you can share vertices between different faces (I don’t do this in BrickGrid yet)

  • Once you have a lot of draw calls, you can improve rendering thread performance by using DrawStaticElements instead of DrawDynamicElements. DrawStaticElements lets the scene management cache the elements and do things like reorder them to reduce rendering state changes. The BrickGrid code does this, but it’s a bit more complicated than it needs to be; you just need to return a FPrimitiveViewRelevance from FPrimitiveSceneProxy::GetViewRelevance with bStaticRelevance=true, and then implement DrawStaticElements instead of DrawDynamicElements.

And definitely learn from the BrickGrid code for my BrickGame project! It’s all available on GitHub under a BSD license:

The rendering code specifically is here: BrickGame/BrickRenderComponent.cpp at master · AndrewScheidecker/BrickGame · GitHub

Nice work, you’ll definitely have to move the generation into a separate thread for run time performance though.

I’ve also been playing around with Voxel implementation but by writing a plugin for PolyVox since I am a fan of open source projects and it supports Cube Voxels, Marching Cubes (smooth terrain), and soon Dual Contoured Poly Mesh. Its been great to see the 4 or 5 other people working on similar things around the forums and on the Wiki with their own libraries and solutions.

this is great work! I’ve done something similar using MS’s C++ AMP libraries to do most of the math on the GPU (including vertex and UV generation), memory use is a concern to me, but maybe that’s because I’m coming from mobile development. Another concern is the collision/physics generation which happens all at once.

bnh