VelocityRaptor Posted 12 hours ago Posted 12 hours ago I've been working with the Terrain object in C++ in my game using procgen, and while troubleshooting bugs and performance issues, found a few instances where more control over the terrain itself would be immensely helpful. 1. Bulk-update the height data for a terrain If we could have a way to bulk-update the height data for a terrain object, it can greatly help performance. To give an example of how this can help, I'm currently calling SetHeight per vertex (~66k calls for a 257×257 terrain), which is causing about a 100ms hitch when the terrain loads in. If we could get access to an in-memory path like SetHeightmap(shared_ptr<Pixmap>) or LoadHeightmap(shared_ptr<Stream>), it would let us do a bulk upload without writing an .r16 file to disk first. 2. A way to defer rebuilding terrain When we update heights incrementally across multiple frames (time-budgeted), we see visible striping artifacts during the transition. If we apply the same update in one batch, the artifacts don’t occur. Something like SuspendTerrainRebuild() / ResumeTerrainRebuild() would let us apply many height changes while rebuild is suspended with a single rebuild step, avoiding partial intermediate states that cause visual artifacts. Alternatively, exposing a public “finalize dirty region” API like FinalizeHeightChanges(rect) / RebuildNormals(rect) (or similar) would let us control exactly when derived data is rebuilt. 3. Async rebuild support Even if terrain updates must remain on the main thread, an engine-supported async path could help a lot: accept a bulk height update, rebuild internal patch meshes / derived textures asynchronously , then publish (swap) render resources at a safe frame boundary. That would avoid long main-thread stalls and avoid intermediate partially-updated render states. 1 Quote
Josh Posted 12 hours ago Posted 12 hours ago Thanks for the suggestions. Would love to see how you are using the terrain. It sounds like you are doing some very interesting stuff. Quote Let's build cool stuff and have fun.
VelocityRaptor Posted 11 hours ago Author Posted 11 hours ago Sure. I'm kinda taking a page out of Dwarf Fortress's book and making a game where you generate the world first and then the characters you create live in that world. World gen is handled by layering a bunch of different fields on each other, each representing different. First is a land/water field where anything below a certain value is water. Then we layer on a height field, influence it by a separate ridge field to not only give us mountains, but to also have them appear in ranges. From there, a hydrology pass is made to determine rivers and lakes, along with other stuff. All of this is derived by the seed, with the world gen saving only the macro-world data, such as the biome, if there's any water, the min and max height for that cell, if there are any resources. etc. Various properties about the macro-cell are derived based on how that data mixes, such as deserts appearing not because a height map said so, but because the water value was low, and it was close to the equator. Rendering the world is purely deterministic at that point, since the macro world data encompasses cells that are 32x32km each. So when it gets to rendering the area where the player is at, it samples the height data from the derived functions and generates the terrain from that. I found an Leadwerks blog post talking about handling large terrain areas with what is effectively a sliding window, referencing new height values and rebuilding the terrain. This ended up being a much more performant route than trying to generate new terrain chunks. It was much more reliable too, since now I didn't have to worry about seams or stitching, since it was always sampling the same window. This part of the terrain gen is where the suggestions are coming from, I was able to knock out almost all of the performance issues, except for the last bit. Doing some diagnostics, showed that the per-vertex write to the terrain object was about 100ms. When I tried to do it in a worker-thread and write it to a back-terrain object using a time budget method, I was actually able to have the terrain generate with no noticeable hitching, the resulting terrain ended up having stripes from having the terrain built in sections. The striping went away when I did the rebuild all in a single tick. Below are screenshots from a MacroWorldVisualizer tool I wrote so I could spot check the world gen to make sure everything was working properly. Note that the world is a cylinder, so it wraps left/right, but is clamped up/down. 2 Quote
Recommended Posts
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.