Terrain Component for Editor

Update:

After implementing TerrainShape, the engine’s private API has been changed. Injection of a new type via system.implementations is no longer supported. I have released a patch that resolves this using the standard approach: assigning the shape to the collision component followed by reactivating the rigidbody. Please take note of this update. Thank you for your understanding.

We’ve improved shadow performance for terrain object components. Previously, shadows could disappear due to frustum processing; now, shadows are correctly cached for specific areas until the LOD is redefined. Please note that it’s best to avoid spamming objects in areas where shadow casting can cause such artifacts.

You can also disable fade for switching LODs, this will slightly reduce memory consumption and calculation time. (lodFadeTime = 0)


Demo

Nice improvement!

I’ve finally integrated the system directly into the editor :rocket:
I’m opening the first beta test of the landscape system for subscribed users :sunrise_over_mountains:

Most of the functionality has already been ported :white_check_mark:
I’m currently polishing the remaining details :wrench:

So you can already start using it in your projects :video_game:




1 Like

Most of the editor functionality is already implemented. Heightmaps can be imported either from a texture or from chunks. Chunk support enables progressive terrain loading. For this purpose, a new method was introduced:

public loadFromPoint(localPosition: pc.Vec3, radius: number): void

It is especially useful during project startup when you want to load the terrain incrementally.

Multi-user editing is also supported. Each user is assigned a specific area they can modify, while all changes are synchronized across all participants.

A runtime synchronization system has also been added for the launcher. Heightmap changes are automatically synced a few seconds after you stop editing in the editor.

Compatibility and performance have been improved. Overall, the product is already usable, and more features will be added gradually.

As mentioned earlier, I designed a custom chunk format for loading and unloading data to disk or a server. It supports incremental streaming of chunk data: heightmaps and splat-maps, landscape and grass object positions (note that GPU-resident data is not unloaded). When the game runs, you can stream data progressively from the player’s position outward, and mask loading with mechanics like fading fog or similar techniques. Chunk size is configurable in settings so you can tune it for your needs. A chunk manager automates load/unload operations and is integrated with the application’s AssetRegistry.

HeightMapFactorsFragment.ts => .alhf
SplatMapFragment.ts => .alsf


Also added was zView, which limits the visibility of terrain patches at a distance.

Please note that while the chunks are being updated, the editor will display information about the work being done. If you try to close the window, the system will notify you that not all data has been downloaded to disk and that you must wait for it to complete.

I’m happy to share that I’ve improved my object instancing system (trees, rocks, fences, etc.), which now works with both WebGPU and WebGL2.

Key improvements:

  • Merges up to 32 objects into a single draw call
  • Shadow rendering can be merged into just 1 draw call
  • Uses the same merge conditions as batching (based on the same combining logic)

Important note: this is instancing, not batching. Conceptually, it’s closer to dynamic batching, but implemented via instancing.

The implementation uses my OptiPixel library, with instancing built upon the BasicHierarchicalInstancer class. This approach has already reduced the number of draw calls for foliage and stems by a factor of 6: foliage from all LOD levels is combined into one group, and stems from different LOD levels into another. As a result, we get only 2 draw calls for 3 LOD levels and 8 calls for 4‑cascade shadows. The terrain itself renders in 1 call, and its shadows in 4 calls.

2 Likes