Terrain LOD Grid?

I’ve been working on a blocky terrain system off and on for quite a while now. I’ve been using parts for the blocks originally. For the given area, it would take about 42-46 seconds to generate every visible block (a block that would be touching an “air” block). Today I had the idea of switching to Roblox’s voxel terrain. With some optimization, the same amount of terrain is generated within around 8 seconds, which is roughly 5-6x faster. It’s also actually generating more blocks as it also generates blocks that aren’t visible, seeing as Roblox’s terrain is automatically optimized to not render blocks that aren’t visible.

This is really good, however I have come across two core issues. My blocks were originally 3 studs in size, but Roblox’s terrain appears to only work with 4 studs with the cube shaped materials. But my real issue is the LOD rendering.

Here I’ve got two images. The first is from further back:

Ignoring the mountain in front and that everything is just brick (I was using colored parts before, but now I need to use material variants and I haven’t done that yet), the terrain further back is very chunky. But if you move closer to that area, the terrain actually looks like this:

This is clearly the automatic terrain LOD system that’s rendering the voxels at a lower resolution from a distance. What I’m wondering is if there’s a way to deal with this. I’m thinking that maybe I don’t have the voxels aligned on the voxel grid correctly? Or is there some way to modify how the LOD works, or perhaps how close or far the LOD activates? While Roblox’s terrain is certainly way faster, this visual sacrifice is actually quite extreme. Imagine looking from on top of a mountain to see what you’ve made, but everything is all chunky and messed up. I’m perfectly fine with terrain LOD doing this, but I wish it did this at a much further distance.

To explain how short of a distance this even requires, here’s basic flat terrain:

Reminder that this image is showing what’s supposed to be completely flat. This is 4000x4x4000 in studs, or 1000x1x1000 in Roblox’s terrain voxels. There are even multiple levels of LOD. This LOD is alright, but my issue is how quickly the LOD switches from the first level to the second. The third level of LOD is also way worse. What I’d personally like is for the second level of LOD to start where the third starts, and then have the third start further away. I wish there were a way to control this for my own project.

But the reason I’m posting here is that I realized that if you move the terrain up 4 studs (or what I assume is 1 voxel), the LOD now occurs under instead of over, which can be seen in this image:

The far distance LOD is still there of course, but at least the middle ranged LOD is “gone”. Now this is nice and all, but this is only a solution for flat terrain. So what I’m wondering is how I should go about this to work with the LOD. It feels like there’s some grid I should try to match in order to resolve this LOD issue. I should probably mention that I’m using Terrain:FillBlock().

TL;DR:
I’m wondering if there’s either a way to modify the LOD rendering system, or if there’s a way to align my voxels to this LOD voxel grid in a way that “hides” the chunkiness of the mid range LOD (as shown in the last 2 images)?

Also, if anyone was wondering, this is what the terrain looked like before with just part blocks:


I've also noticed this post from back in 2016, but it seems that nothing has come from it?

No, there wouldn’t be any workaround for the LOD no matter how you align it as roblox is lowering the detail of the terrain

Since your game is voxel based, you could look at using EditableMesh (Studio Beta) which would allow you to cull faces that wouldn’t be visible and would avoid this LOD issue

Though since it would be a MeshPart, you would probably hit a roadblock with CollisionFidelity

However if you want to return back to parts, you could not generate the parts that arent visible inside the voxel terrain but instead store those. When that block needs to become visible, you could create it then. I see you already do this method

Do you do greedy meshing on your parts? (Combining two identical parts together)

1 Like

Would that generate faster? Normally I would want something like that to run on the gpu, but Roblox’s Lua runs on the CPU. If that’s still the case, wouldn’t it be faster to generate parts than to calculate and generate all of those triangles and vertices? The collision wouldn’t be an issue if there were a way to generate invisible terrain, but I’m not sure if that’s possible even with material variants (though I can’t say I’ve tried that yet)?

This is already how the terrain generates:

Terrain Visibility Check

(I was having issues uploading the original gif, so I’m just going to use Discord as a file host for it. Also I don’t know how to embed it.)

(Okay I just resized it down to 19%)

1 Like

Another issue I’ve just realized, and is pretty critical, is that there can only be one material variant for any given material it seems. The only solution I can think of is using each material available, but that’s only 32 different block types that I can have then. Is there any way around this?

1 Like

You should be able to put multiple material variants under one material

1 Like

I can have multiple material variants that use the same material, but I don’t see how I can use the same material with multiple variants. When I look at the MaterialService properties, I can click on “Brick” and change it from “Brick” to a material variant. But I can only select one and not multiple. There doesn’t seem to be a way to allow for multiple, at least that I can see.

1 Like

Oh, yeah you cannot have multiple variants on one part

1 Like

Does this also use greedy meshing?

And for the editable mesh question:
I’m not sure how expensive it would be to rebuild the mesh (also still capped at 20k triangles per editable mesh)

Roblox plans to add batching to the editable mesh api and its highly likely that creating vertices and triangles is less expensive than instancing all the parts.

The only thing that might ruin performance is when roblox goes ahead and regenerates the mesh

1 Like

Yeah, this is what kind of kills the Roblox terrain option for me. I was considering letting the LOD issue slide in hopes Roblox would improve it in the future, but the limited materials just kills that option. I think they mentioned having plans to allow for multiple material variants to be used, like full custom materials. Sadly I haven’t seen anything regarding that anytime recently.

The Roblox terrain version does, but not the block version. I could probably do that, but it’ll require a bit more work. This also isn’t including block textures yet. Roblox’s terrain does all of that much more efficiently. Even then, I’m not sure how much faster it would be to generate that way. I suppose I could at least give it a try though and see.

I looked at the API for it and it looks very confusing to me, tbh. Plus the lack of collision kind of defeats the purpose, unless I layer invisible terrain on top of that (assuming that’s even an option).

Is there not a way to regenerate it manually?

Whenever you edit the mesh, roblox will regenerate it for rendering purposes (this is just how it works)

You can have collisions on the editable mesh by using AssetService:CreateEditableMeshAsync but doubtful the collisions will be nice’

I would look into greedy meshing, probably will help your case a bit

Roblox does also support local raycasting on an editablemesh so you can always create a custom collider

I just tried that because I realized it’s actually nearly the exact same process and now the generation speed for parts are almost the same. Only it’s a bit more laggy. I’m not sure how I can speed this up more without having lag. I do plan to generate only on the server, so the client shouldn’t lag, but I’d ideally like to reduce the lag in general.

It says it takes 8 seconds to do it, but it appears to take a bit longer. When the parts start loading in, it happens somewhat quickly? It’s hard for me to explain the issue.

Cannot help much with the lag issue unless I see the snippet of code that generates it or a microprofiler dump or a place link if the terrain currently generates on the client

It’s more of the creation of the parts that appear to be taking longer. I do have an artificial delay every 2 chunks, but it still feels slow. If I change that delay, it causes script timeouts. I’m not sure if I’ve done parallel Lua correctly, but I believe I’ve done it so that the calculations are done parallel for the entire chunk, then it synchronizes to actually create the parts. Actually, looking at it, the chunk generates in an instant, so it has to be the calculations that are slowing it down? I am running a lot of math to make the terrain much more interesting. I’m taking a similar approach to how modern Minecraft does it.

It always seems like a battle between freezing and putting in delays, but that’s not really fixing the issue probably. I can’t tell if I’m using parallel Lua the best way possible and I can’t find much documentation on it unfortunately. If that’s not the issue, I’m not sure how else I can optimize this without sacrificing all of the calculations I’m wanting to do.

I suppose one method is to sample fewer blocks, but I remember that had inconsistency issues that I could never resolve…

Parallel Lua is a bit iffy in general. Majority of the time, your time savings from parallel is lost in cost of transferring between different vms.

Is this terrain generated on the client, and if yes could you send a place link. I would be able to look at what is causing the freezing

It’s generating on the server. I’m doing that because it prevents the client from lagging from the calculations, but also for security checks, and lastly because I don’t want the code getting leaked like the other clones you see everywhere. I know that it’s possible for anyone to do this, but I want to limit that when things are still so early on.

Most of the math is doing a bunch of noise related things. There’s both 2D and 3D fractal noise, as well as density and some other things. There’s multiple noise calculations for different factors that would affect the outcome of the terrain. I think the main issue is that I’m doing these calculations for every single block. I was originally also doing it for nearby blocks to check for air, but with greedymeshing, it’s actually faster to not do that.

So I guess all that leaves is trying to get sampling to work. Where I’d take samples from fewer points, then use bilinear interpolation to calculate the in between points, which is much cheaper to do. However, last time I did this, I had random holes in my terrain that I could never truly get rid of. I’d fix it in one seed, but then I find a random hole in another seed. I’ve had to take many long breaks from this project due to the headaches it causes me.

I should probably mention that the lag is only during generation.

I just removed the parallel part and the speed is pretty much the same. But I’m not sure if that’s because parallel is bad or if I just did it unoptimally.

I look at Roblox’s example and it looks way faster:

Though their terrain is also only a height map, which is much cheaper than what I’m doing.

I’ll be trying out the sampling method later after I get some sleep (don’t think I’m ready to jump into that without any rest). This seems like the right direction, but I feel like I must be missing some other optimizations that I’m not thinking of…

If you press ctrl + f6, it will open the microprofiler.

Press pause, hover over mode and go to detailed.
It will tell you what is exactly taking up resources but can be difficult to learn how to use as it also contains roblox jobs

Since your code is on the server, you will need to do this in studio to see the server job

Taking off the parallel part likely had no effect as that is not the bottleneck. You will be able to identify the bottleneck with the above reply. Once you learn the microprofiler, you can experiment with parallel on and off etc