From 4b46b1a8e0706cf69b142ab7f1913a8513f097f5 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Sat, 27 Jun 2026 00:13:04 +0300 Subject: [PATCH] Update terrain plan --- src/features/editScene/TerrainRequirements.md | 71 ++++++++++++++++--- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/src/features/editScene/TerrainRequirements.md b/src/features/editScene/TerrainRequirements.md index 66c1a29..4e39ce5 100644 --- a/src/features/editScene/TerrainRequirements.md +++ b/src/features/editScene/TerrainRequirements.md @@ -432,10 +432,9 @@ m_world.component(); **In `EditorApp::setup()`** — construct after physics but before water/sun/skybox (terrain must exist before those systems try to interact with it): -```cpp -m_terrainSystem = std::make_unique( - m_world, m_sceneMgr, m_physicsSystem.get()); -``` + Ogre::Camera *cam = m_camera ? m_camera->getCamera() : nullptr; + m_terrainSystem = std::make_unique( + m_world, m_sceneMgr, cam, m_physicsSystem->getPhysicsWrapper()); **In `EditorApp::frameRenderingQueued()`** — call update **before** static-world generation and **after** visual mesh setup. Insert right after @@ -1012,6 +1011,8 @@ Minimum controls: - Add/remove/split/join/select nodes. - Inspector for node position, offset, edge levels. - "Comply terrain to roads" button. + - Physics debug: "Show Terrain Colliders" checkbox (off by default, + toggles `TerrainBodyDrawFilter` via `TerrainSystem`). - Prefab spawn mode (uses `TerrainPrefabSpawnerComponent`): - Add/remove spawn points (snapped to terrain surface). - Pick prefab from existing prefab list. @@ -1145,15 +1146,63 @@ Definition of done: a paged terrain renders in the editor; terrain pages load and unload as the camera moves. ### Milestone 2 — Physics integration -- Implement `ZigzagHeightfieldShape` as a `JPH::MeshShape` per page with zigzag - triangulation matching Ogre. -- Queue collider creation after page load and derived-data completion. -- Maintain `mColliders` map; safe remove/re-add on scene clear or component - removal. -- Add raycast helper to `TerrainSystem` for gameplay/editor tools. + +**Changes to TerrainSystem constructor**: Now takes `JoltPhysicsWrapper*` so +it can create/destroy static terrain collider bodies directly in the Jolt world. + +```cpp +TerrainSystem(flecs::world &world, Ogre::SceneManager *sceneMgr, + Ogre::Camera *camera, JoltPhysicsWrapper *physics); +``` + +**EditorApp wiring change**: Update `setup()` to pass `m_physicsSystem->getPhysicsWrapper()`. + +**Collider creation queue**: After `CustomTerrainDefiner::define()` finishes a +page and `isDerivedDataUpdateInProgress()` is false, create a per-page +`JPH::MeshShape` with zigzag triangulation (see section 3.3) and add a static +body at the page's world position. Bodies go into `Layers::NON_MOVING`. + +**mColliders map**: `std::unordered_map` keyed by +`packIndex(x, y)`. `TerrainCollider` holds `{pageX, pageY, JPH::BodyID, +pendingRemove}`. + +**Collider removal queue**: When a page unloads (detected via +`DummyPageProvider::unloadProceduralPage`), mark its collider `pendingRemove`. +In `update()`, only remove bodies when no derived data update is in progress. + +**Zigzag triangulation** (see section 3.3): Build `JPH::MeshShape` from +`terrain->getHeightData()` using the zigzag quad split matching Ogre's odd/even +row parity. + +**Debug drawing — TerrainBodyDrawFilter**: +- Implement `class TerrainBodyDrawFilter : public JPH::BodyDrawFilter` in + `TerrainSystem` that tracks terrain `BodyID`s in a `std::set`. +- `ShouldDraw(const JPH::Body &)` returns `false` for terrain bodies when + `m_showTerrainColliders == false` (the default). +- Add `void setShowTerrainColliders(bool)` toggle. +- Thread the filter into the physics wrapper: add a + `JoltPhysicsWrapper::setBodyDrawFilter(BodyDrawFilter*)` setter and pass it + to `BodyManager::DrawBodies(..., filter)`. +- Terrain editor gets a **"Show Terrain Colliders"** checkbox (off by default). + +**Raycast helper**: `TerrainSystem::getHeightAt(const Ogre::Vector3 &worldPos)` +picks the right page, samples the height data bilinearly, and returns the +world-space Y. Also add `raycastTerrain(const Ogre::Ray &ray, float &outT)` +that casts a ray against all loaded terrain pages' Jolt bodies using +`JPH::NarrowPhaseQuery::CastRay`. + +**Testing**: +- [ ] Drop a rigid body on terrain → rests flush (no sinking/floating). +- [ ] Toggle "Show Terrain Colliders" → wireframe matches terrain surface. +- [ ] Fly away and back → colliders for unloaded pages removed, new pages get colliders. +- [ ] Remove terrain entity → all collider bodies removed, no dangling Jolt bodies. +- [ ] Add/remove terrain repeated → stable memory (valgrind/ASan). +- [ ] Raycast from above hits terrain at correct height. +- [ ] Colliders are NOT visible in debug draw by default. Definition of done: rigid bodies and characters collide flush with the visible -terrain; removing/re-adding the terrain entity is leak-free. +terrain; terrain collider debug draw is off by default with a toggle; removing +and re-adding the terrain entity is leak-free. ### Milestone 3 — Serialization + heightmap editing + splat painting - Scene serialization for `TerrainComponent` (save/load JSON round-trip).