GregOrigin - Instant Organic Caves: Lightweight Procedural Runtime Structure Generator

IOC 0.1 in action (Youtube).

Read the docs.

đź“– Overview

Instant Organic Caves (IOC) is a small plugin designed to generate massive, seamless, and organic cave and/or rock systems procedurally at runtime. Unlike traditional marketplace assets that rely on static meshes or Blueprint construction scripts, IOC utilizes a "Metal C++" approach.

It builds geometry directly using Unreal's `FDynamicMesh3` core math libraries, bypassing overhead from the Blueprint VM and intermediate wrapper libraries. The result is a system that can generate infinite, seamless, Nanite-enabled environments suitable for high-fidelity production.

✨ Key Features

*Pure C++ Architecture:** No dependency on Blueprint logic, PCG Graphs, or external assets. The geometry is calculated mathematically from scratch.

*Direct Dynamic Mesh Manipulation:** Operates directly on `UE::Geometry::FDynamicMesh3` for maximum performance.

*Infinite World Generation:** Supports seamless chunk tiling using world-space Perlin Noise.

*Organic Smoothing:** Implements custom, stable Laplacian Smoothing to convert blocky voxel grids into smooth, eroded cavern walls.

*Welded Topology:** Custom meshing algorithm ensures watertight geometry with no internal faces, preventing shading artifacts and mesh tearing.

*Nanite & Lumen Ready:** programmatically enables Nanite support on generated meshes.

🚀 Quick Start

Single Chunk Generation

1. In a New Scene, open the Place Actors panel.

2. Search for `IOCProceduralActor` in Plugins.

3. Drag it into the viewport.

4. A cave chunk will generate immediately. Use the Details Panel to adjust settings like `Seed`, `Roughness`, and `Cave Size`.

  1. Use LeftAlt+LMB to duplicate the generated chunk in any direction. Chunks can be seamlessly merged. More sophisticated options to extend the structures will come in the next version.

Infinite World Generation (WIP, coming soon)

1. Search for `IOCWorldGenerator` in the Class list.

2. Drag it into the level.

3. In the Details Panel:

Set *Chunk Class** to `IOCProceduralActor`.

Set *Render Distance** (e.g., `2` for a 5x5 grid).

Set *Update Interval** (e.g., `0.5` seconds).

4. Press Play. As the camera moves, new cave chunks will form ahead of you seamlessly.

Please note: the plugin needs the PCG and GeometryScripting modules enabled.

Hi all. I am looking into the possibilities of merging this plugin with another one of mine, TerraDyne: I think it would make great sense since both are essentially runtime procedural systems to generate or manipulate organic structures in a level.
However, such a merge would result in a deeply complex unified plugin with a higher margin of error (and a book-length manual really).
If you have any comments or requests on this, please share it here or in email, thanks.

[0.3.0] - 2026-06-20 update :camping:

Added :plus: :newspaper:

    🎨 Pure Math Material: Developed M_IOC_MathRock , a zero-footprint master material that uses World Position and 3D Simplex Noise to generate organic rock strata without relying on texture memory.

    :rock: Hybrid PBR Pipeline: Upgraded the Master Material with a Use PBR Texture switch, instantly swapping between Pure Math and traditional Textures.
    :gem_stone: Seamless Biome Textures: Packaged three new 4K tileable rock textures directly into the plugin: Obsidian Flow, Limestone Crawl, and Alien Hive. (More to come later.)
    :world_map: Triplanar Projection: Implemented automatic Box Mapping to prevent texture stretching on generated vertical cave walls.
    :books: Vector Documentation: Overhauled the shipped Manual. Replaced static screenshots with clean, responsive SVG vector illustrations and added comprehensive guides for the new Hybrid Texture workflow.

  • Readiness Guard: Showcase flythrough camera now intelligently defers its start until all asynchronous procedural caves have completed generating (or up to a 30s fallback timeout).
  • Flythrough Looping: Added bLoopShowcase property to AIOCShowcaseLauncher, giving users control over whether the showcase flythrough loops continuously or halts after one pass.
  • Dedicated Tools Menu: Added Tools > Instant Organic Caves with one-click access to the setup wizard, validation, documentation, demo spawns, showcase launch, and showcase cleanup.
  • Launcher Quick Actions: AIOCShowcaseLauncher now exposes clearer Call In Editor actions for standard showcase start, capture showcase start, and showcase cleanup, with friendlier property labels and tooltips.
  • Wizard Quick Start UX: The setup wizard now exposes a welcome-page project snapshot, quick-start actions, clickable step navigation, and preset-to-custom workflow shortcuts.

Changed :coral:

  • Showcase Robustness: Refactored the showcase spawn pipeline into resilient conditional blocks. If a specific section's actor fails to spawn, the system gracefully skips it without crashing or desyncing the camera.
  • Concurrency Safety: Added a strict bIsActive lock to ShowcaseState with hardened reset logic to prevent overlapping showcases, memory pollution, and hot-reload errors.
  • Python Drift Prevention: Fully deprecated IOC_CreateShowcaseMap.py via runtime warnings and comments, establishing the C++ Setup Wizard as the single source of truth for starter map configuration.
  • Shipping Build Compatibility: Wrapped editor-only setup wizard capture functionality inside #if WITH_EDITOR blocks, completely resolving compilation errors in Game/Runtime/Shipping targets.
  • Typed Showcase/Demo API: Wizard and launcher flows now call a shared native module API instead of relying on string-built GEngine->Exec commands.
  • Validation Feedback: Installation validation now also shows editor notifications while still writing the full report to the Output Log.
  • Documentation Access: Wizard and editor menu actions now share a single documentation opener that prefers the local shipped docs and falls back to the website.
  • Wizard Practicality: Review now links directly to starter assets, preview-side workload visibility is stronger, and safer-first-pass actions surface earlier in the flow.
  • Standalone Packaging: Fixed Win64 game-target packaging by restoring the runtime material-domain include used by fallback cave materials.
  • Native Setup Flow: The setup wizard no longer depends on Python execution for starter assets or showcase-map creation; both workflows now use built-in editor APIs with explicit success/failure handling.
  • Validation Messaging: Installation checks now treat Python automation as optional and correctly describe starter assets as shipped plugin content.

This really needs at least 2 new videos to showcase new features and instruct on usage. Please bear with me.

0.3.5 update, 2026-07-18 :volcano:

Added

  • Authoritative runtime carving: Reflected carve records now replicate to late joiners, serialize through SaveGame, validate radius/input, and obey a bounded FIFO history.
  • Persistent streamed carving: AIOCStreamingManager owns a saveable carve history, routes excavation to affected chunks, and restores it after unload/reload.
  • Production resource budgets: Hard voxel, triangle, and scatter caps reject unsafe work while preserving the last valid generated mesh.
  • Multiplayer streaming controls: Authority tracks all player pawns, unions their desired chunks, caps retention, throttles loads, and releases chunks after the last player leaves.
  • Seam-safe streamed density: Voxel/LOD-aligned chunk dimensions, a one-voxel neighbor halo, stable global seeding, and locked smoothing boundaries prevent artificial interface caps.
  • World-aligned generated UVs: World-space chunks now project generated UVs from world coordinates so UV-driven materials do not restart at every chunk origin.
  • :artist_palette: Pure Math Material (updated): Developed M_IOC_MathRock, a zero-footprint master material that uses World Position and 3D Simplex Noise to generate organic rock strata without relying on texture memory.
  • :rock: Hybrid PBR Pipeline (updated): Upgraded the Master Material with a Use PBR Texture switch, instantly swapping between Pure Math and traditional Textures.
  • :gem_stone: Seamless Biome Textures (updated): Packaged three new 4K tileable rock textures directly into the plugin: Obsidian Flow, Limestone Crawl, and Alien Hive.
  • :world_map: Triplanar Projection (updated): Implemented automatic Box Mapping to prevent texture stretching on generated vertical cave walls.
  • Readiness Guard: Showcase flythrough camera now intelligently defers its start until all asynchronous procedural caves have completed generating (or up to a 30s fallback timeout).
  • Flythrough Looping: Added bLoopShowcase property to AIOCShowcaseLauncher, giving users control over whether the showcase flythrough loops continuously or halts after one pass.
  • Production bake controls: Stable unique naming, material override, lightmap UV/tangent generation, optional generated LOD, optional Nanite, and selectable collision mode.
  • Runtime status: Blueprint-visible success, failure reason, timing, voxel, triangle, LOD, and scatter metrics.
  • Regression coverage: Added runtime-contract, generation-budget, streamed-seam, and streamed-carve-persistence automation tests.

Changed

  • Cave transforms now participate correctly in world-space noise, biome, and carve sampling.
  • Generation cancellation is lifecycle-safe and checks cancellation during expensive parallel voxel/carve work.
  • LOD distance uses generated mesh bounds and never switches to an invalid LOD.
  • Player coupling is opt-in and disabled for network games unless explicitly allowed.
  • Demo/showcase commands are non-shipping cheat commands; the showcase launcher is inert in Shipping.

Fixed

  • Removed global debug-line flushing that could erase unrelated project visualization.
  • Removed module delegate leakage during shutdown.
  • Removed plugin-owned UE 5.7 deprecation warnings for networking and Nanite access.
  • Fixed Shipping compilation of the showcase launcher.
  • Fixed world-space generation seeds being ignored and per-chunk seeds breaking density continuity.

[0.4.0] update, 2026-09-09 :brown_mushroom: :camping:

At a glance:

  • Support for UE5.5, 5.6, 5.7, 5.8.x
  • An original scatter library
  • 10x performance boost
  • All content re-authored on UE5.5 to ensure compatibility
  • New demo map and offline / online tutorial
  • Redesigned Setup Wizard
  • Major rehauling of cave materials
  • Carving and instrumentation upgrade
  • Network update: delta-replicate
  • Many fixes

A long overdue major update. Carving, content and onboarding. Every shipped asset was re-authored on the 5.5 floor, the plugin gained its own scatter library, the Setup Wizard was rebuilt, and a demo map and tutorial now give two routes in that need no setup.

A deeply technical changelog follows, aimed mainly at enthusiasts. The online manual and setup tutorial may be an easier read otherwise. Please remember that the open-source version is also advanced, updated and supported.

Verified on UE 5.5, 5.6, 5.7 and 5.8. Automation suite 21/21 green on the 5.5 floor, up from 14 tests, and every assertion added this cycle was negative-tested: deliberately broken, observed to fail, then restored.

:high_voltage: Performance — carve latency 200 ms to 118 ms (1.7x)

Measured on an 80^3 cave (3200 uu bounds, 40 uu voxels, non-tunnel, one sphere carve).
New per-stage instrumentation, logged when bLogPresetDebug is set, drove all of it:

stage before after
noise fill 23 ms 0 ms (replayed)
carve 0.3 ms 0.3 ms
face extract 10.5 ms 10 ms
Laplacian smooth 73 ms 7.2 ms
mesh build 58 ms 64 ms
overlays 35 ms 35 ms
worker total 200 ms 118 ms
  • Laplacian smoothing was allocating a TSet<int32> per vertex to hold adjacency – one
    hash set per mesh vertex, which made allocator traffic the single largest cost in the whole
    generator (36% of generation time). Replaced with compressed-sparse-row adjacency built in
    two linear passes, with per-slice sort-and-unique reproducing TSet’s unique-neighbour
    semantics. The per-vertex update has no cross-vertex dependency, so it now also runs through
    ParallelFor. 10x faster on that stage.
  • Added FIOCVoxelCache: the post-noise, pre-carve voxel field is cached and replayed, so
    a carve no longer re-evaluates the noise. Keyed by a signature covering every input to the
    fill (seed, noise parameters, tunnel geometry, biome overrides, spline segments, actor
    transform, bounds) plus voxel size and grid dimensions – change any generation parameter and
    the signature stops matching, so a stale field cannot be served and there is no invalidation
    call to forget. Stored as one bit per voxel (a 2M-voxel streamed chunk costs ~250 KB); only
    caves that actually carry carves populate a cache. Toggleable in Project Settings.
  • The carve pass is restricted to the union bounding box of the carves’ influence. Outside
    it the field is identical to the filled or replayed result. The remaining ~110 ms is entirely mesh build (64 ms) and attribute overlays (35 ms), both bound
    by single-threaded FDynamicMesh3 append APIs.

:collision: Breaking

  • AIOCProceduralActor::RuntimeCarves changed type from TArray<FIOCCarvingCapture> to
    FIOCCarveHistory. C++ that iterated it should use RuntimeCarves.Items or the new
    GetRuntimeCarves(); Blueprint should use GetRuntimeCarves(). The SaveGame layout for
    carve history changed
    – previously saved carve histories will not load.
  • OnRep_RuntimeCarves is gone; the FastArray notifies through its own hook.

:moai: Content — everything re-authored on the 5.5 floor

  • All shipped assets are now fully compatible with the declared 5.5 floor.
    Forward compatibility runs one way only — there is no downgrade path and
    no descriptor setting that helps. Every asset was rebuilt natively on 5.5 by dumping its
    semantic content on a newer engine and replaying it through the editor API, then re-dumping
    the rebuild on 5.5 and diffing: 279 values compared, one difference, and that one is an
    engine limitation carrying no data.
  • Packaging.ContentEngineFloor now scans every shipped .uasset and .umap and fails on
    anything saved above the floor, so this cannot recur silently.

:adhesive_bandage: Fixed — cave materials

  • Three base materials were one-sided. A cave is a shell – TunnelRadius of air inside WallThickness of rock – and the player stands inside it, so the bore’s
    surfaces are backfaces and were being culled. All three are now two-sided,
    which also fixes shading, since Unreal flips the vertex normal on
    backfaces for two-sided materials.
  • Both flags are set by Resources/SetMaterialRenderFlags.py and guarded by the
    Content.MaterialRenderFlags automation test.
  • :artist_palette: M_IOC_SmartCave ignored vertex colours. VertexColor was wired to nothing
    and both LinearInterpolate alpha pins sat at const_alpha = 0.5, so the material rendered a
    fixed 50/50 blend. The authoring script wired outputs named "Green"/"Blue"; the outputs
    are R/G/B/A.
  • :artist_palette: M_IOC_MathRock ran its noise at default world scale. The Noise position input was
    unconnected and WorldPosition → Multiply(x0.002) dangled — the script targeted a pin named
    "Position", which is actually "World Position".
  • :puzzle_piece: IOC_Fn_ScatterCrystals computed a density it discarded — NormalToDensity_0.Out went
    nowhere. It now feeds DensityFilter_0.In.
  • ConnectMaterialExpressions returns false on an unknown pin or
    output name and changes nothing. Every authoring
    script now routes through a helper that raises on rejection.

:rock: Added — an original scatter library

  • Eight meshes generated with GeometryScripting and shipped in
    /InstantOrganicCaves/InstantOrganicCaves/Geometry/: three rocks from boulder to gravel, two
    crystals, a geode, a stalactite and a stalagmite. Each has two LODs, simple collision, and a
    pivot placed for how it is used — the stalactite hangs from its top, the rest sit on their
    base — so instances neither float nor sink when aligned to a surface.
  • Content.ScatterMeshLibrary checks all eight for material slots, LOD count and reduction,
    triangle budget, collision, real-world scale and pivot placement. All eight gates have now
    been proven able to fail.

:compass: Added — two routes in that need no setup

  • :world_map: A demo map ships: /InstantOrganicCaves/Maps/IOC_DemoMap, reachable from
    Tools → Instant Organic Caves → Open Demo Map. It holds one launcher and a PlayerStart
    and nothing else — every cave is built at runtime on Play, so there is no baked lighting to
    rebuild, nothing to rot, and no content references beyond a native class.
  • :open_book: A tutorial ships: Resources/Docs/Tutorial.html. The manual documents every property
    and teaches nothing, which left no guided path for a new user. The tutorial
    covers demo, wizard, presets, sizing, the six parameters that matter, scatter and
    troubleshooting, with a preset explorer that draws each cave’s cross-section to scale from
    the real preset values and a voxel budget calculator running the wizard’s own arithmetic.
  • :broom: IOC.ClearAllDemos removes everything any demo command added, including the playtest
    character, so the commands leave no residue in a customer’s level.

:magic_wand: Changed — the Setup Wizard

  • Every SWrapBox had always been wrapping at 100px. SWrapBox defaults to
    PreferredSize = 100 with UseAllottedSize = false, and all twelve instances set neither —
    so button rows stacked vertically regardless of available width.
  • The wizard opens on a first run with a working route forward. IOC.OpenSetupWizard opens it without the menu.

:globe_with_meridians: Network

  • RuntimeCarves now delta-replicates. It was a plain TArray<FIOCCarvingCapture>, so
    every carve resent the whole array – roughly 25 KB to each relevant client against a
    256-entry history. It is now FIOCCarveHistory, a FFastArraySerializer. The common case
    (append) marks one item and sends one small delta; only FIFO eviction degrades to a full
    array update, because a removal invalidates the replication keys after it.
  • Client-side rebuilds are driven by PostReplicatedReceive, which fires once per received
    update, rather than by the per-element add/change/remove hooks.

:sparkles: Added — carving and instrumentation

  • InstantOrganicCaves.Cave.CarveFieldCacheParity – proves a replayed field produces geometry
    identical to a recomputed one, that two consecutive cached generations agree, and that
    changing the seed invalidates the cache rather than serving the stale field.
  • Production.RuntimeContract now asserts the carve history carries
    STRUCT_NetDeltaSerializeNative. Omitting the type trait still compiles and still
    replicates, just as a whole array – this is the only check that distinguishes the two.
  • Per-stage generation timings behind bLogPresetDebug.

:test_tube: Verification

  • Suite grown from 14 tests to 21. Seven are new: Content.ScatterMeshLibrary,
    Content.MaterialRenderFlags, Content.WizardStyleAssets, Demo.DemoMap,
    Demo.ShowcaseLifecycle, SetupWizard.ButtonSweep and SetupWizard.Layout. The
    fourteenth, Packaging.ContentEngineFloor, existed and was the one failure — it passes now
    that the content is authored on the floor.
  • Every new assertion was negative-tested. Two proved worth the effort by exposing tests
    that could not have failed: a mesh-breaking helper reported success while doing nothing,
    because the editor library it called is a silent no-op outside a real editor session; and an
    early layout test emitted four confident failures.

:brick: Structure

  • Split out an InstantOrganicCavesEditor module (Type: Editor).
  • The showcase still runs in PIE and packaged builds, so it stayed in the Runtime module; its level-viewport control is inverted through FIOCShowcaseViewportHooks, which the editor module binds on startup. The Runtime module no longer depends on LevelEditor, ToolMenus or ApplicationCore at all.
  • FInstantOrganicCavesModule::ValidateInstallation / OpenDocumentation moved to FInstantOrganicCavesEditorModule. API break for any C++ that called them.
  • Editor logging goes to a separate LogIOCEditor category.

:sparkles: Also added

  • Project Settings page (UIOCSettings, Project Settings > Plugins > Instant Organic Caves): fallback cave material as a FSoftObjectPath, max grid cells per axis, max spline samples, and the vertex welding toggle.
  • Blueprint-assignable generation events. OnGenerationStartedEvent and OnGenerationFinishedEvent are BlueprintAssignable; generation is asynchronous and can take seconds, and Blueprints previously had to poll bIsGeneratingDisplay on tick to know when a cave was ready. The native C++ delegates are unchanged and still broadcast.
  • GenerateCave and RequestRegeneration are now BlueprintCallable.
  • Vertical chunk streaming. AIOCStreamingManager keys chunks by FIntVector and gained VerticalStreamRadius. It defaults to 0, which reproduces the previous single-layer behaviour exactly; raising it streams cave systems deeper than one chunk. Note the chunk count scales by (2 * VerticalStreamRadius + 1), so MaxLoadedChunks needs raising to match.
  • InstantOrganicCaves.Cave.VertexWelding regression test: asserts welding preserves every triangle while sharing vertices, and logs the measured saving.

:wrench: Additional changes

  • Generated meshes weld their vertices. The generator emitted four unshared vertices per quad because FDynamicMesh3 rejects triangles that would create a non-manifold edge – something diagonal-touching voxels produce constantly. It now shares a vertex per grid corner and falls back to duplicated vertices for only the individual triangles that actually fail, so the manifold guarantee holds and no triangle is lost. Measured 2.93x fewer vertices (5504 → 1881 for 2752 triangles) on the test cave, with the same reduction carried into cooked collision. Revertible via the project setting.
  • The PCG node has a version-gated output path. UPCGBasePointData (structure-of-arrays) does not exist on 5.5, so 5.5 keeps UPCGPointData + TArray<FPCGPoint> while 5.6+ uses FPCGContext::NewPointData_AnyThread with the SoA value ranges – which also picks up UPCGPointArrayData where a project has enabled it. The solid-voxel scan was restructured into a count-then-fill pass so both back-ends write output in parallel with no per-point reallocation.
  • TObjectPtr for all UPROPERTY object references on the cave actor, streaming manager and character.
  • Editor UI strings converted from INVTEXT to LOCTEXT in the menus and validation notifications.

:adhesive_bandage: Additional fixes

  • PCG element allocated UObjects off the game thread. FIOCVoxelCoreElement::ExecuteInternal called NewObject<UPCGPointData>() directly; PCG elements run on worker threads (IPCGElement::CanExecuteOnlyOnMainThread defaults to false), so this raced the garbage collector. Now uses FPCGContext::NewObject_AnyThread.
  • Cellular Automata seeding produced a lattice, not noise. The initial fill used a single LCG step, which leaves consecutive cells a fixed stride apart and yields regular banding. Replaced with a MurmurHash3-finalised, coordinate-keyed hash that is also stable across grid resizes.
  • Streaming manager held raw UObject* chunk pointers in a non-UPROPERTY map, invisible to the GC and left dangling when a chunk was destroyed outside UnloadChunk. Now TWeakObjectPtr, with an explicit prune pass.
  • Clients overwrote replicated generation settings. BeginPlay re-expanded the cave preset on every peer, clobbering the replicated recipe and producing client geometry (and collision) the server did not have. Preset expansion is now authority-only.
  • The legacy preset migration could hijack runtime actors. ShouldAutoPreset() is a value-match heuristic over user-editable fields; it no longer runs at BeginPlay, only in a genuine editor world, so a streamed chunk whose settings coincide with the defaults is not silently converted into a tunnel.
  • Generation bounds were silently truncated. The working grid is capped per axis; exceeding it shrank the cave with no diagnostic. The cap is raised to 2048 cells per axis and clamping now logs a warning.
  • Splines were chorded, not followed. Tunnel generation read only GetLocationAtSplinePoint, so a two-point spline with tangents produced a straight tunnel and curves were clipped by bounds derived from the same chords. Splines are now sampled by arc length, backed by a new uniform segment grid so the extra segments do not turn the nearest-segment query into an O(voxels x segments) scan.
  • World-space noise tiled. FMath::PerlinNoise3D masks its lattice with & 255, repeating roughly every 512 m at the default frequency and folding large seed offsets back onto the same lattice. Replaced with a hash-lattice gradient noise of matching range and distribution, so existing thresholds still apply. Regenerating an existing cave will change its shape.
  • Collision was re-cooked on every mesh edit. Complex-as-simple collision updates are now deferred and cooked once per completed generation.
  • The demo and showcase commands changed the user’s level. They took the first DirectionalLight / SkyLight / Fog / PostProcessVolume found in the level, overwrote its settings and renamed it. Environment dressing is now plugin-owned, tagged, transient in editor worlds, and removed by IOC.ClearShowcase.
  • IOC.CaptureWizardPreset — an authoring screenshot tool that spawns actors into the open level, moves the viewport and can quit the editor — is now registered only when the editor is launched with -IOCDevTools, and its retry ticker is removed on module shutdown.
  • Setup wizard rollback snapshot held bare UObject* references on a Slate widget. SIOCSetupWizard is now an FGCObject and reports them; the referenced fields use TObjectPtr.
  • Authoring Python scripts shipped with absolute paths from the author’s machine (including a user-profile path). Paths are now relative or environment-driven, logging goes to the Output Log.
  • AIOCCharacter no longer teleports to an arbitrary cave on BeginPlay: the snap is an exposed, documented option, picks the nearest cave, honours spline mode, and runs on the authority only. Input modifiers use CreateDefaultSubobject instead of NewObject during construction.
  • Property edits that cannot affect geometry (bake options, debug toggles, LOD switch distance, runtime-carve limits) no longer trigger a full regeneration.
  • Runtime carves within a frame are coalesced into a single rebuild instead of one full revoxelisation each.
  • bShowDebugViz gizmos persist while the box is ticked. They were issued once from OnConstruction into the transient line batcher, which expires them after about a second.
  • UIOCVoxelCoreSettings exposes MaxVoxelCount instead of a hard-coded 15M ceiling.

[0.4.1] update, 2026-09-23 :volcano:

:glowing_star: At a glance

  • :counterclockwise_arrows_button: Cave meshes face into the cave. Collision, scatter and lighting now match the surface you see.
  • :world_map: Interactive tour: six feature zones on one walkable route, then a portal to an endless
    streamed tunnel. Ships as a map.
  • :pick: Player carving: AIOCCharacter can carve the cave under its crosshair (opt-in).
  • :fog: Biome blending: AIOCBiomeVolume::BlendDistance eases a volume’s overrides in rather
    than switching them at its face.
  • :bug: Fixes: capsule carves, spline bends, carve falloff, runtime biome volumes,
    biome ledges, streaming placement and stalactites.
  • :blue_book: Illustrated demo guide: Resources/Docs/DemoGuide.html, with a frame from every zone.
  • :test_tube: 35 automation tests, up from 22.

:white_check_mark: Verified: automation suite 35/35 green on UE 5.8 and on the 5.5 floor, 0 ensures; every
new test negative-tested. BuildPlugin unity and strict passes succeed with zero warnings on 5.5,
5.6, 5.7 and 5.8, and all packages pass the isolated-build validator. The shipped tour map (262 m in 53 s) starts cleanly in a standalone -game run.

:collision: Upgrading from 0.4.0 — behaviour changes

  • :counterclockwise_arrows_button: Every cave looks and behaves differently. Surfaces face into the cave, so lighting,
    collision from inside a cave and scatter placement all change.
  • :tooth: Stalactites now grow along +Z from their base. Scatter layers that place SM_IOC_Stalactite
    need Align To Normal on; with it off, stalactites now point up.
  • :pill: Capsule carving components carve a capsule. They used to carve everything within the
    capsule’s length inside the carve pass’s bounds: a box on their own, and the whole region when
    beside a larger carve. Caves that use capsule carves change shape.
  • :pick: A carve never puts rock back. Where carve falloffs overlap, the strongest carve now wins,
    so caves with overlapping falloffs come out slightly more open.
  • :thread: Spline tunnels are sealed on the outside of every bend. Tunnels whose bends showed slits
    to the outside are now closed.
  • :round_pushpin: AIOCStreamingManager builds where it is placed. It always used the world origin; a
    manager placed elsewhere now builds its caves around its own location.

:counterclockwise_arrows_button: Fixed

  • Vertex normals now agree with the winding. They pointed at the air while the winding did not,
    and two-sided shading flips the normal on back faces, so surfaces were lit from behind.
  • The smart-material ceiling mask was inverted. SmoothStep(-0.6, -0.85, Up) has its bounds
    reversed and returned 1 for every surface above -0.6, so M_IOC_SmartCave painted the ceiling
    colour on floors and walls. It now mirrors the floor test.

:world_map: Added — the interactive tour

  • Six zones, one route, ~264 m. The Mouth (a drop-in cave actor on a preset), The Winding Run
    (a spline tunnel that a biome volume flares open), Crystal Gallery (a carved hall dressed by
    scatter layers), Alien Hive (domain warp), Strata Canyon (terraces switched on by a second
    biome volume) and The Forge (a hall shaped by sphere, box and capsule carving components, and the
    one cave the player may carve). A glowing crystal by the Forge’s far wall leads to Infinite
    Depths
    , where an AIOCStreamingManager builds cave around the walking player.
  • Built from four cave actors: two tunnels and two solid-block chambers whose rooms are carved,
    joined tunnel to chamber through carved passages sized from the tunnel mouths measured after they
    generate. Walkable about a second after spawning; no window to the outside anywhere along the
    route except the entrance.
  • A caption per zone on first entry (what the feature is, how to use it, live generation
    numbers), and a “Generating caves…” caption while it builds.
  • Carve the Forge yourself: left mouse / right trigger with the crosshair on the rock.
  • Ships as a map: /InstantOrganicCaves/Maps/IOC_InteractiveDemo (authored on UE 5.5; a launcher
    in Interactive mode and a PlayerStart), opened from Tools > Instant Organic Caves > Open
    Interactive Demo
    or the Setup Wizard’s Open Interactive Demo button. Also
    FInstantOrganicCavesModule::SpawnInteractiveTour, the console command IOC.SpawnInteractiveTour
    and a Spawn Interactive Tour menu entry.
  • AIOCShowcaseLauncher Interactive Demo mode (bInteractiveMode, Start Interactive Demo)
    runs the tour at the launcher’s location instead of the flythrough.
  • IOC.TourAutopilot walks the tour on its own – the route, a carve in the Forge, the portal and
    the depths – for recording and kiosks (-IOCTourAutopilot, -IOCTourAutopilotQuit,
    -IOCTourNoCaptions). Zone entries log their engine frame, for timing titles on a frame dump.
  • The caption overlay is shared by the showcase and the tour, and no longer takes mouse input.

:bug: Fixed

  • Biome volumes left a ledge. Overrides switched at the volume’s face, leaving a step in a tunnel
    floor wherever the radius changed – 186 cm in the test case. BlendDistance eases them in; 45 cm
    with a 10 m blend. The default, 0, keeps the old switch.
  • Capsule carves cut a slab. The capsule distance took the closest axis point as
    (x, y, clamped z), dropping the radial term, so everything within the capsule’s length read as
    inside. The carve pass visits the union of all carves’ bounds, so a capsule beside any larger carve
    hollowed out that whole region – the showcase’s Carved Chamber included, which now has its proper
    shape.
  • Spline tunnels had slits on the outside of every bend. A voxel beyond the end of one spline
    segment and before the start of the next counted as “past the tunnel’s open end” and was dropped,
    cutting a wedge through the wall wherever the spline turned. Only a spline’s true first and last
    segments are open now. Measured on the tour’s tunnel: 228 rays escaped around one bend before, 0 after.
  • Adding a carve could add rock. In a falloff band the carve probability came from the nearest
    carve rather than the strongest, so a new carve’s weak outer band could undo a stronger carve’s
    work. A click in the Forge grew a wall 1.7 m in front of where the player aimed. The pass now takes
    the strongest carve, so carving only ever removes rock.
  • Scattered stalactites grew into the ceiling. See Content below.
  • The walking lane is checked, not assumed. The demo traces the floor every metre (highest rock
    under each 1 m x 2.1 m footprint), sweeps the character’s capsule along the lane, carves a corridor
    with CarveAtLocation wherever rock intrudes, removes scatter props reaching into it (they have no
    collision), then lays one-metre slabs that follow the floor. The same lane runs through every cave
    of the tour and through IOC.SpawnSpectacular.
  • The freeze while the cave generates now holds. Possess() runs Restart(), which reset the
    movement mode and undid the freeze. Possession now happens first.
  • IOC.SpawnSpectacular got a lighting pass: staged warm-key / cool-fill / violet-rim lighting
    in physical units, a SkyAtmosphere for the real-time SkyLight, and limestone / alien-rock surfaces.
  • AIOCCharacter forces an Enhanced Input component, so it works in host projects still configured
    for the legacy input component.

:sparkles: Added — API

  • :pick: AIOCCharacter carving, opt-in: bEnableCaveCarving (off by default),
    SetCaveCarvingEnabled, CarveAtAim, CarveRadius, CarveReach, and PlayerCarvableTag
    (IOC_PlayerCarvable). Only caves with that tag accept the player’s carves. The carve keys live in
    their own mapping context, installed only while carving is on, so a project’s own use of the left
    mouse button is untouched.
  • :fog: AIOCBiomeVolume: BlendDistance, bUseBoxExtent, BoxExtent.
  • :world_map: FInstantOrganicCavesModule: SpawnInteractiveTour(World, Origin), and
    GetShownCaptionTitle for tests and tools.
  • :keyboard: Console: IOC.SpawnInteractiveTour, IOC.TourAutopilot.

:rock: Content

  • SM_IOC_Stalactite re-authored to grow from its base along +Z, like SM_IOC_Stalagmite.
    Scatter aligns +Z to the surface normal, which points into the cave – down, on a ceiling – so the
    normal is what hangs it. Authored tip-down with its pivot on top, it only suited the inside-out
    mesh; with correct normals every stalactite on a ceiling pointed up into the rock and vanished.
    Regenerated on UE 5.5 from its seed; the other seven meshes are unchanged.
  • New map IOC_InteractiveDemo, authored on UE 5.5.
  • Poisson spacing packs a surface. Worth knowing when tuning scatter: with
    PoissonMinSeparation set, the scatter throws 30x the candidates and keeps every one far enough
    apart, so the result approaches the spacing limit whatever Density says. The tour uses density
    alone.

:books: Documentation

  • :blue_book: New Resources/Docs/DemoGuide.html, replacing IOC_DEMO_GUIDE.md: the tour zone by zone,
    illustrated with frames from the game, plus its controls, console commands, how to record it and a
    presenter’s script. Its images are inlined, so it works opened from disk.
  • :graduation_cap: Tutorial: the two demo levels, the tour’s zones and controls, IOC.SpawnInteractiveTour,
    biome blending, player carving, stalactite pivots and Poisson spacing, and two new
    troubleshooting entries.
  • :open_book: Manual: supported engines 5.5-5.8, the Tools menu, the wizard’s and launcher’s interactive
    entries, streaming placement, the new biome properties, carve falloff, a Player Carving section,
    decoration pivots and spacing, the new console commands and API.
  • All three pages link to each other.

:test_tube: Tests — 35, up from 22

  • Mesh orientation: Cave.NormalOrientation – from inside a tunnel, the floor faces up, the
    ceiling faces down, physics hits the floor the mesh shows, vertex normals agree with the winding,
    and floors and ceilings carry the right smart-colour masks. Against the inside-out mesh all three
    facing checks fail.
  • Generator defects: Carving.CapsuleShape, Carving.NeverAddsRock, Cave.SplineBendSealed,
    Cave.BiomeBlend, Cave.BiomeVolumeBox, Content.ScatterFacesIntoCave, and a placement check in
    Production.StreamingCarvePersistence.
  • The tour: Demo.InteractiveLaneInBore (the walkway on the cave floor at 12 stations across
    all six zones, a route of at least 200 m, nothing left behind by IOC.ClearAllDemos),
    Demo.InteractiveRouteSealed (from head height over the walkway, no ray sideways or upward reaches
    the void except out of the entrance), Demo.InteractiveCarving (a click at a Forge wall carves the
    Forge only and digs into the wall; a click in Tunnel B carves nothing), Demo.InteractiveStreaming
    (the portal puts the player on a streamed floor, inside the tunnel, able to walk) and
    Demo.InteractiveBudget (walkable within 4 s; measured 0.7 s).
  • Real input: Demo.InteractiveInput sends a real key event through Slate into the focused game
    viewport in PIE (one layer down under -NullRHI, where the viewport has no size and drops keys),
    walks the whole tour and requires every zone caption in route order.
  • Coverage: Demo.DemoMap covers both shipped maps; SetupWizard.SafetyAndValidation and
    ButtonSweep cover the new command, map and button. Demo.ShowcaseLifecycle no longer fails inside
    a level with its own IOC_-labelled actors.
  • Every new test was negative-tested: broken on purpose, observed to fail, then restored.

:warning: Known

  • AIOCCharacter has no mesh: the third-person camera follows an invisible capsule. For now, this is intentional.
  • Runtime carving still re-meshes the whole actor per carve (unchanged from 0.4.0).
  • SetupWizard.Layout still checks how the wrap boxes are built, not their laid-out width (see 0.4.0).

Basic procedural walkthrough of the 0.4.1 interactive demo: