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:

Another interactive 0.4.1 demo:

A comprehensive tutorial video is now available:

[0.4.5] update, 2026-10-01 :mount_fuji:

:candle: A dark level, in its own rock — and every surface rebuilt at 2K. The Warren is a second
playable demo: 346 m of tight, organic burrow walked by flashlight, with scripted moments, a rock plug
you carve through, and a hollow beyond it open to the daylight. Each of its six beats wears its own
rock, drawn by a new world-aligned material you can put on any cave. Around it, every texture and prop
in the plugin was rebuilt: ten 2048² rock sets drawn world-aligned, and thirteen props modelled and
baked in Blender with real UVs. The setup wizard lost seven rough edges on the way. The release after
0.4.1 is numbered 0.4.5; there was no public 0.4.2 to 0.4.4.

:glowing_star: At a glance

  • :candle: The Warren — six beats, ~346 m, lit only by the character’s flashlight. Ships as
    /InstantOrganicCaves/Maps/IOC_DarkDemo.
  • :rock: Six rock sets, one per beat — flesh-rock, mycelium, rusted shale, calcified bone,
    weeping stone and fractured basalt.
  • :brick: M_IOC_WarrenRock — a world-aligned rock material: no UV streaks, real surface relief
    under a torch, usable on any cave.
  • :hole: Organic Warren preset — a tight, heavily warped bore: a burrow rather than a bore hole.
  • :bone: Five new props — roots, a fungal shelf, an egg sac, a bone pile and a membrane, plus a wet
    organic material and a glowing fungus one.
  • :pick: Carve to continue — the level dead-ends in rock; carve through it and walk on into the
    Hollow.
  • :clapper_board: IOC.WarrenAutopilot — walks the whole level by itself, for recording and kiosks.
  • :framed_picture: 2K rock, world-aligned — obsidian, limestone, alien, cave floor and the six Warren sets are
    2048², and the default cave skin (MI_IOC_CaveWalls) now draws them world-aligned too: no UV
    streaks, real relief in the normal map, glowing veins on the alien set.
  • :rock: Thirteen props, rebuilt in Blender — sculpted, UV-unwrapped, baked onto three 2048² atlases
    (rock, crystal, organic), two LODs and convex collision each.
  • :mage: A better-mannered setup wizard — it keeps the lights already in your level, stays in front
    of the editor, says “Setup Complete” without contradicting itself, shows every preset name in
    full, and keeps its banner’s title at any window size.
  • :mobile_phone: Platforms: Win64, Linux and Android. The modules’ PlatformAllowList is now
    [Win64, Linux, Android] (it was [Win64, Mac, Linux]), and all three are compiled for every
    supported engine before release.
  • :test_tube: 49 automation tests, up from 35.

:white_check_mark: Verified: automation suite 49/49 green on UE 5.5, 5.6, 5.7 and 5.8, each built from a clean
copy of the plugin in a content-free host (PluginTestMatrix), and 0 ensures in the 5.8 and 5.5-floor
runs of the dev project. The
Warren’s tests and the four new wizard tests were negative-tested, as was the budget-message check;
SetupWizard.OwnedByEditor and SetupWizard.LiveLayout were run in a rendering editor, where a
headless suite skips them. The
Warren’s own autopilot walks it end to end — through the carved plug and across the Hollow — in a
standalone -game run. All new and rebuilt content is authored on UE 5.5.

:collision: Upgrading from 0.4.1

  • :artist_palette: Caves using the default material look different. MI_IOC_CaveWalls (parent
    M_IOC_MathRock) is now world-aligned, so the cave’s UVs and TextureTiling no longer place its
    texture: use the material’s TileSize (world cm per repeat) instead. CaveStyleTexture and the
    Use PBR Texture switch keep their names; set CaveStyleNormal to the style’s _N map when you
    change styles.
  • :artist_palette: M_IOC_SmartCave is textured. Color_Wall, Color_Floor and Color_Ceiling are now tints
    over the wall and floor textures (neutral by default) rather than flat colours, Roughness multiplies
    the maps, and it blends by world normal, so it no longer needs bGenerateSmartColors. Instances that
    set strong colours will tint the rock rather than replace it.
  • :rock: The thirteen props were replaced in place — same names and paths, so scatter layers, PCG graphs
    and placed actors keep working, but the geometry is new and each mesh has one material slot. If you
    overrode a prop’s material, check it still lands where you want.
  • :mage: The wizard’s Set up lighting no longer duplicates your lights. It adds only the directional
    light, sky light, height fog and unbound post-process volume the level lacks.
  • :desktop_computer: Mac is no longer listed. The modules’ PlatformAllowList is [Win64, Linux, Android], so the
    plugin does not load in a Mac editor or build for Mac.
  • :package: The package is larger: plugin content grows from about 27 MB to about 209 MB, almost all of it
    the 2048² textures (normal maps are stored uncompressed-quality BC5 at 9–13 MB each).

:candle: Added — the Warren, the dark demo level

  • :compass: Six beats, one descent, ~346 m. The Gullet (a tight warped crawl with membranes strung
    across it), The Nest (five overlapping sphere carves — pods, not a room — with egg sacs, roots
    and a glowing fungus cluster), The Throat (tighter and steeper; the roof comes down behind you),
    The Bone Garden (a low hall of columns and bone piles, with a light that dies as you approach),
    The Weep (the narrowest run, where an alcove opens behind you) and The Hollow (reached only by
    carving through a rock plug, ending at a crack of daylight).
  • :building_construction: Built from six cave actors: three tight spline tunnels and three solid blocks whose rooms
    are carve components, joined tunnel to block through passages sized from the tunnels’ measured
    mouths — the same join recipe as the interactive tour.
  • :flashlight: Lit by the flashlight. The level places four lights in 346 m: the fungus, the dying lamp,
    a rim on the Hollow’s far wall and the daylight crack. Sun and sky are turned down to almost
    nothing.
  • :performing_arts: Scripted moments, no creature. A collapse that drops rubble behind you with a stutter of
    the flashlight, a light that goes out as you close on it, and a side alcove that opens in rock
    you have already walked past. Each is a carve or a prop, placed against its own trigger point, so
    nothing can land in front of you.
  • :pick: Carve to continue. The level ends in solid rock, and only that cave accepts your carves.
    Carve through the plug and a walkway is laid beyond it, joined to the one you arrived on, into the
    Hollow and on towards the daylight.
  • :world_map: Ships as a map: /InstantOrganicCaves/Maps/IOC_DarkDemo (authored on UE 5.5), opened
    from Tools ▸ Instant Organic Caves ▸ Open Dark Demo or the Setup Wizard’s Open Dark Demo
    button. Also FInstantOrganicCavesModule::SpawnDarkWarren, the console command
    IOC.SpawnDarkWarren, a Spawn Dark Warren menu entry, and AIOCShowcaseLauncher’s new
    Dark Warren mode.
  • :clapper_board: IOC.WarrenAutopilot walks the level on its own — the route, the scripted moments,
    carving the plug and out across the Hollow (-IOCWarrenAutopilot, -IOCWarrenAutopilotQuit,
    -IOCWarrenNoCaptions). Beats and events log their engine frame, for timing a recording.

:rock: Added — the Warren’s own rock

Each beat wears a rock of its own, so every stretch of the descent looks like a different place:

  • :anatomical_heart: Gullet — wet, folded, flesh-toned rock, glossy in the creases.
  • :mushroom: Nest — dark stone laced with pale fungal threads and flecked with spores.
  • :brown_circle: Throat — cracked shale with rust weeping from the cracks.
  • :bone: Bone Garden — pale, pitted, calcified stone the colour of old bone.
  • :droplet: Weep — dark wet stone with teal and white mineral seeps that glisten under the torch.
  • :volcano: Hollow — fractured basalt, with lichen where the daylight reaches.
  • :artist_palette: Each set is a colour map with roughness in its alpha plus a normal map, 2048², in
    Textures/Warren/ (T_Warren_<Beat>_D / _N). They are generated from fixed seeds, so they tile
    without seams.
  • :brick: M_IOC_WarrenRock draws them world-aligned (triplanar): colour, roughness and normals
    are projected in world space, ignoring the cave’s UVs, so nothing smears where the UV projection
    changes and the torch finds real relief in the rock. Parameters: RockColour, RockNormal,
    TileSize (world cm per repeat), RoughnessScale, FloorWetness (below 1, up-facing surfaces
    read wetter) and NormalStrength.
  • :repeat_button: Use it on your own caves: set CaveMaterial to an instance of it with any of the six sets
    (see the Manual’s Warren Rock). The Warren falls back to the shared rock textures if the set is
    missing, so it never renders untextured.

:sparkles: Added — preset and API

  • :hole: EIOCCavePreset::Warren (“Organic Warren”): TunnelRadius 350, WallThickness 70,
    NoiseFrequency 0.009, VoxelSize 25, DomainWarpIntensity 260. Like Tight Crawlspace it is a
    shape, not a promise a character fits; the demo opens its own tunnels up for walking.
  • :electric_plug: FInstantOrganicCavesModule::SpawnDarkWarren(World, Origin), and GetDarkWarrenPlug for
    tests and tools.
  • :rocket: AIOCShowcaseLauncher::bDarkWarrenMode / StartDarkWarren().

:package: Content

  • :bone: Five new generated props, seeded and reproducible like the other eight:
    SM_IOC_Root_A, SM_IOC_FungalShelf, SM_IOC_EggSac, SM_IOC_BonePile, SM_IOC_Membrane.
    Thirteen props ship now.
  • :green_circle: M_IOC_Organic with BaseColor, Roughness and EmissiveColor parameters — the first
    shipped material to expose emissive — plus MI_IOC_Organic (wet) and MI_IOC_Fungus (glowing).
  • :rock: Twelve rock textures and M_IOC_WarrenRock (above).
  • :ice: Both new base materials are two-sided and flagged for instanced static meshes, like every
    other shipped material.
  • :white_check_mark: All new and rebuilt assets, the map included, were authored on the UE 5.5 floor. 61 content
    assets ship (46 in 0.4.1’s count plus the 2K rework below).

:framed_picture: Changed — every texture and prop, rebuilt at 2K

  • :rock: Four shared rock sets at 2048²: T_RockObsidian, T_RockLimestone, T_RockAlien and
    T_CaveFloor, each a colour map with roughness in alpha plus a _N normal map. Obsidian is glassy
    scalloped fracture with knife-edge ridges, limestone pale water-worn stone, alien dark bioporous
    stone with veins, and the floor packed grit and pebbles. The six Warren sets are 2048² as well.
  • :brick: M_IOC_MathRock is world-aligned. The default cave skin (MI_IOC_CaveWalls) projects its
    texture in world space like M_IOC_WarrenRock, so it never streaks where the generator’s UV
    projection changes axis, and it finally has a normal map. New parameters: CaveStyleNormal,
    TileSize, ProjectionContrast, NormalStrength, RoughnessScale, Tint, VeinGlow and
    VeinGlowColour (the alien set’s veins glow). With Use PBR Texture off it is still the
    zero-texture rock, now with a gentler bump that no longer tips whole patches away from the light.
  • :puzzle_piece: M_IOC_SmartCave is textured: a wall set and a floor set blended by world normal, tinted by
    its three colours (see Upgrading).
  • :rock: Thirteen props, modelled in Blender. Each prop is a fixed-seed sculpt, decimated to a game
    mesh with real UVs, with a lighter LOD1 and convex collision. The props bake onto three shared
    2048² atlases — rock, crystal, organic — with colour, roughness, normal and emissive, drawn by one
    new master, Materials/M_IOC_Prop (Tint, RoughnessScale, EmissiveColour,
    EmissiveStrength, RimGlow). MI_IOC_PropRock is new; MI_IOC_Crystal, MI_IOC_Organic and
    MI_IOC_Fungus now derive from it. Crystals glow at their rims and the fungus shelves glow.
  • :repeat_button: Regenerable from source: the textures come from Resources/GenerateRockTextures.py and the
    props from Resources/Blender/GenerateScatterProps.py (Blender 5.2) plus
    Resources/ImportScatterProps.py. None of these scripts ship.

:mage: Fixed — the setup wizard

  • :light_bulb: It no longer puts a second sun in a lit level. Set up lighting always spawned a
    directional light, sky light, height fog and post-process volume, and the UE Basic template already
    has the first three. The first Generate in a new level left two suns fighting over the sky (UE
    prints a warning over the viewport) and doubled the fog. It now adds only what the level lacks and
    logs what it kept.
  • :window: It stays in front of the editor. It was an unowned window, so the moment the editor took
    focus it drew over the wizard, and Generate Cave focuses the editor by selecting the new cave. The
    Finish page, with Undo Added Actors, vanished behind the level editor exactly when it was
    needed. The wizard is now owned by the editor’s main window.
  • :white_check_mark: The Finish page says what happened. A successful setup read “Setup Complete” over “No cave was
    generated yet”, above the new cave’s statistics.
  • :label: Preset names are no longer cut off. At the wizard’s default size every style card clipped
    its name (“[A] Larg”), its description and its spec line: an empty spacer took half of each title
    row, and the description wrapped at a fixed 250 px on a card about 170 px wide. Everything on a
    card now wraps to the card.
  • :framed_picture: The banner keeps its title when the wizard is widened. Its art was cropped into a fixed
    196 px box, so a wider window scaled the art up and cropped the title away. The banner’s height now
    follows its width, showing the same slice of the art at any size.
  • :chequered_flag: After Undo Added Actors, the Finish page stops describing the undone setup. Its “Spawned new
    cave actor” and “LOD generated” badges stayed under “Setup Not Run”; they now show only while a
    setup is running or done.
  • :snake: The validation report no longer mentions Python helpers that don’t ship. It said Python was
    “enabled for optional Resources/*.py automation helpers”; those are authoring scripts excluded from
    the package, and the plugin needs no Python.
  • :broom: “Reconfigure an existing cave actor” is no longer restored from an earlier session. It names
    an entry in that session’s cave list, so restored it made Generate fail with “the selected cave
    actor is no longer available”. And the automation tests no longer save their own wizard settings
    over yours.

:bug: Fixed — generation errors

  • :speech_balloon: LastGenerationError names the budget that stopped a cave. A generation refused by
    MaxVoxelCount or MaxGeneratedTriangles reported the generic “Generation produced no surface…”;
    it now carries the same message the log does (“Voxel grid budget exceeded (…)”).

:bug: Fixed

  • :bullseye: A scripted event could fire where the player stands rather than where it belongs. The
    collapse placed its rubble relative to the player’s position at the moment it triggered, so a
    player who covered ground in one step — a teleport, a hitch — could have it land in front of
    them, or on them. Events now place themselves against their own trigger point.
  • :ladder: Carves that sank below a chamber’s floor left steps nobody could climb. Sphere and capsule
    carves centred less than their own radius above the floor scoop pits through it; the walkway
    followed them down and back up, leaving a 96 cm step — a character climbs 45 cm. Every round
    carve in the level now sits tangent to its floor, and Demo.WarrenLaneInBore measures the
    tallest step on the walkway.

:wrench: Changed

  • :link: The interactive tour and the Warren now share their cave-building helpers
    (IOCDemo::MakeRockMaterial, AddScatterLayer, AddCarveComponent, SplinePointAt,
    MeasureFloorBelow) rather than keeping two copies.

:books: Documentation

  • :blue_book: The demo guide covers both levels: a new The Warren, beat by beat section with a frame
    from each beat, and the new commands in its command table.
  • :graduation_cap: Tutorial: a third demo card, the Organic Warren preset in the preset explorer with its real
    values, and IOC.SpawnDarkWarren in the console list.
  • :open_book: Manual: the preset table, the new console commands, the wizard’s new button, and a
    Warren Rock (world-aligned) section on using the new material. The material pipeline is rewritten
    for the world-aligned M_IOC_MathRock and the textured M_IOC_SmartCave, the scatter section lists
    all thirteen props and their atlases, and the wizard’s Environment step says it keeps your lights.
  • :graduation_cap: Tutorial: the scatter section lists the organic props as well as the mineral ones.

:test_tube: Tests — 49, up from 35

  • :railway_track: Demo.WarrenLaneInBore — six beats tile a route of at least 280 m, the walkway lies on the
    cave floor at twelve stations, no step along it is taller than a character can climb, and
    IOC.ClearAllDemos leaves nothing behind.
  • :locked: Demo.WarrenRouteSealed — from head height over the walkway, no ray reaches the void except
    out of the entrance.
  • :performing_arts: Demo.WarrenBeats — each scripted moment fires once, in route order; the way forward is as
    clear after the collapse as before it; the dying light ends at zero; the alcove opens behind its
    trigger.
  • :pick: Demo.WarrenPlug (PIE) — a click at the plug carves the Hollow, carving through opens a
    character-sized way on, no other cave in the level accepts a carve, and a character walks
    from the end of the walkway through the carved plug and 5 m beyond, with real movement input.
  • :new_moon: Demo.WarrenDarkness — at most four placed lights, none of them a key light, sun and sky
    turned down, and the character’s flashlight lit.
  • :rock: Demo.WarrenRock — each of the six caves renders its own rock set through M_IOC_WarrenRock;
    colour maps are sRGB with roughness in alpha, normal maps are linear normal maps.
  • :stopwatch: Demo.WarrenBudget — walkable within 3 s (measured 0.6 s).
  • :hole: Cave.PresetWarren — the preset is tighter and more warped than the wide default, with a
    voxel fine enough to resolve it.
  • :rock: Content.RockStyles — every shared rock style is a 2048² pair (sRGB colour that keeps its
    roughness alpha, and a normal map that is not sRGB); both cave materials take world-space normals
    and expose their style parameters; MI_IOC_CaveWalls wears obsidian with its normal map; and a
    style swap moves the normal map with the colour.
  • :world_map: Content.PropAtlases — the three prop atlases are 2048² with the same colour/normal rules, and
    every prop is UV-mapped into its atlas and wears an M_IOC_Prop instance sampling its family’s maps.
  • :light_bulb: SetupWizard.KeepsLevelLighting — in a lit level, Set up lighting adds no second directional
    light, sky light or fog, and a test run leaves your saved wizard settings untouched.
  • :window: SetupWizard.OwnedByEditor — the wizard window is a child of the editor’s main window (needs a
    rendering editor; skipped in a headless run).
  • :white_check_mark: SetupWizard.FinishMessage — after setup the Finish page does not also say no cave was generated,
    and with no setup done (never run, or undone) no badge describes one.
  • :triangular_ruler: SetupWizard.LiveLayout — opens the real wizard window and measures what the editor drew: at the
    default size no text on a style card is narrower than it needs, and widened, the banner keeps its
    height-to-width ratio (needs a rendering editor; skipped in a headless run).
  • :plus: Extended: Production.GenerationBudget checks that the refusal names the voxel budget;
    Demo.DemoMap covers three shipped maps, Content.ScatterMeshLibrary thirteen
    props, Content.MaterialRenderFlags both new materials, Content.ShippedDocumentation the
    guide’s new section, and the wizard’s sweeps the new command, map and button.

[0.5.0] update, 2026-10-25

:foot: Floors you can walk at any frame rate, and dressing that stays where it is. A cave’s floor is
now smoothed harder than its walls, which fixes the one open defect from 0.4.5: at 120 frames a second
and above, a Character stuck on the first floor step it met. Scatter props are now placed per
triangle, so a runtime carve re-dresses only the rock it changed instead of reshuffling the whole cave,
and a path you keep clear of props stays clear through every rebuild. The IOC Voxel Core PCG node now
does what the Manual always said it did — points on the rock’s surface, facing the air. The setup
wizard offers the sixth preset, the props lost their wet look, streamed tunnels lost a crack at every
chunk seam, and tunnel generation takes about 40% less time.

:glowing_star: At a glance

  • :foot: Walkable floors at any frame rate — WalkableFloorSmoothing (default 8) gives up-facing
    surface extra smoothing passes. Floor area too steep to walk on drops from about 30% to about 1%.
  • :rock: A carve re-dresses only the rock it changed — every other prop in the cave stays exactly
    where it was.
  • :construction: Paths stay clear — ScatterExclusions, AddScatterExclusionPath() and
    bScatterOnRuntimeCarves keep props out of a corridor, or out of a fresh hole, through every rebuild.
  • :seedling: PCG node on the surface — Surface Only points, turned to face the air, with an optional
    surface offset, exposure as density, per-point seeds, and noise that no longer repeats.
  • :mage: Organic Warren in the setup wizard, with its own dressing, dark lighting and cost estimate;
    four layout fixes; two presets’ cost estimates corrected.
  • :high_voltage: Faster tunnels — mesh building, attribute overlays and hole filling reworked or run in
    parallel: about 40% off a tunnel’s generation at 25 cm voxels.
  • :artist_palette: Props without the wet look — rock props bake the roughness they were meant to have, and no
    longer darken where a neighbouring prop sat during the bake.
  • :shield: A cave too big for collision says so, instead of letting the player fall through it.
  • :puzzle_piece: No crack at streamed tunnel seams — a slot up to 2.5 m deep across the floor at every
    chunk seam is closed.
  • :hole: Demo fixes — the Warren’s walkway is clear of rock, the tour’s portal is entered by walking
    off the end of the walkway, and pruned props no longer come back after a carve.
  • :test_tube: 56 automation tests, up from 49.

:white_check_mark: Verified: automation suite 56/56 green on UE 5.5, 5.6, 5.7 and 5.8, each built from a clean
copy of the plugin in a content-free host (PluginTestMatrix; the 5.8 leg was built by hand with
-NoHotReloadFromIDE because a 5.8 editor was open), 0 ensures on every engine. The plugin also builds
for Linux and Android, Development and Shipping, on 5.5 and 5.8. Every new test and check was
negative-tested; SetupWizard.OwnedByEditor and SetupWizard.LiveLayout were run in a rendering
editor. The re-imported props and the renamed PCG instance were saved on UE 5.5.

:collision: Upgrading from 0.4.5

  • :foot: Floors are smoother. Caves regenerate with WalkableFloorSmoothing = 8: floors keep their
    shape but lose the one-voxel steps. Set it to 0 (actor, or AIOCStreamingManager) for the old
    floors. Generation costs about 2–3 ms more on a mid-size tunnel.
  • :rock: Every cave’s dressing is laid out afresh — same layers, same density, different (and now
    stable) positions. Per-layer counts can differ by a few props from 0.4.5, since fractional counts
    now round per triangle.
  • :seedling: IOC Voxel Core outputs Surface Only, rotated to the surface. Existing graphs pick this up.
    Set PointMode to All Solid and turn off bAlignPointsToSurface for the old output. Its
    Perlin Tunnel and Infinite modes now sample the cave actor’s noise, so their fields change.
  • :shuffle_tracks_button: NewPCGGraphInstance is now IOC_GraphInstance_Master (no redirector is shipped; nothing in
    the plugin referenced it). Re-point anything of yours that used it.
  • :globe_with_meridians: New replicated properties on AIOCProceduralActor: WalkableFloorSmoothing,
    ScatterExclusions, bScatterOnRuntimeCarves. Server and clients must run the same plugin version.
  • :mage: Wizard settings migrate themselves. Custom moved from index 5 to 6 to make room for Organic
    Warren; a saved Custom selection is carried across.

:foot: Fixed — Characters sticking on cave floors at high frame rates

  • :snail: At 120 ticks a second and above, the player stuck on the first floor step. After 2–3
    smoothing passes, a one-voxel step in the floor is still a 45–62° ramp: steeper than a Character’s
    walkable angle, so only a step-up crosses it. The step-up probe is one tick of movement — under
    2 cm at 240 Hz — so it landed back on the ramp, the step was undone, and the character stood still
    with W held. 30 and 60 ticks/s walked through. Found in 0.4.5’s Infinite Depths, 0.4 m from the
    portal; any IOC floor could do it.
  • :wrench: WalkableFloorSmoothing (IOC|Shape, default 8; on the streaming manager too): floors get at
    least that many passes, walls and ceilings keep SmoothIterations, and vertices on the grid’s outer
    faces stay put so chunk seams don’t move. On the depths recipe, floor area steeper than 44.8° goes
    from 32% to under 1%.
  • :test_tube: Demo.InteractiveStreamingHighTickRate walks the depths for 5 s of game time at a fixed
    1/240 s step: 24 m, never stalled more than 0.14 s. With the fix removed it reproduces the defect
    exactly — 47 cm, stuck for 4.6 s. Cave.WalkableFloor compares a cave with the setting on and off.

:rock: Fixed — scatter that moved, and paths that filled back up

  • :game_die: One carve moved nearly every prop in the cave. Scatter drew every prop from one random
    stream and carried fractional counts from triangle to triangle, so any change to the mesh shifted
    every prop after it. Each triangle now draws from its own stream, keyed by where it is; Poisson-spaced
    layers are dart-thrown in a per-prop order. Props away from a carve stay put (Cave.ScatterStableAcrossCarves:
    every one of 123 plain and 328 Poisson-spaced props kept).
  • :construction: Props pruned from a walkway came back after a carve. The demos removed scatter from their
    walkways once; the next rebuild scattered the cave again, and a stalagmite stood up through the
    Forge’s walkway. Exclusions now live on the cave (ScatterExclusions, actor-local capsules) and every
    scatter pass applies them — first generation, carve rebuilds and replicated rebuilds alike.
    AddScatterExclusionPath(WorldPoints, Radius) adds a corridor and removes what is already in it.
  • :hole: A fresh hole grew props. With bScatterOnRuntimeCarves off, nothing is scattered inside a
    runtime carve’s reach, so a pocket dug half way up a wall no longer sprouts a floating stalagmite.
    The tour’s Forge and the Warren’s Throat, Weep and Hollow use it.

:puzzle_piece: Fixed — a slot across the floor at every streamed tunnel seam

  • :hole: Streamed tunnels had a crack at every chunk seam. Density chunks get a one-voxel halo and
    their seam vertices are pinned; tunnel chunks had neither, so smoothing pulled each chunk’s floor
    back from its neighbour’s. On the Infinite Depths recipe, rays cast down at a seam fell 1.0–2.5 m
    below the floor either side — every ~24 m. Seam vertices of streamed tunnel chunks are now pinned to
    the shared voxel lattice like the density chunks’, so both sides meet; what remains is a shallow
    groove (worst 31 cm on that recipe) where a pinned vertex sits below its smoothed neighbours
    (Production.StreamingTunnelSeam).

:seedling: Changed — the IOC Voxel Core PCG node

  • :round_pushpin: PointMode: Surface Only (new default) emits one point per solid voxel that touches air; All
    Solid keeps the old every-voxel output, most of it buried rock.
  • :compass: bAlignPointsToSurface turns each point so +Z faces the air — meshes stand on floors, lean
    out of walls, hang from ceilings. SurfaceOffset moves points towards the air.
  • :fog: bExposureAsDensity: density is the share of a voxel’s 26 neighbours that are air, for a
    Density Filter that keeps exposed ridges.
  • :seedling: Every point gets a seed from its position, so spawners vary per point and stay stable.
  • :repeat_button: No more repeating noise. The node used FMath::PerlinNoise3D, which tiles every 256 noise
    units — every ~51 m in Infinite mode at the default frequency. It now uses the cave actor’s
    gradient noise, which has no period. In Infinite mode the surface test reads the neighbouring
    chunk’s rock from the halo, so a chunk border is not mistaken for surface.

:mage: Changed — the setup wizard

  • :hole: Organic Warren is offered as the sixth style: a card, a row in the comparison table, its own
    dressing (roots on the ceiling, fungal shelves on the walls, egg sacs on the floor), texture tiling,
    render rig, cost estimate and Convert-to-Custom values, and dark, flashlight-ready lighting.
  • :1234: The cost estimate counted the wrong number of scatter layers for Large Tunnel and Open
    Cavern (3 where the preset builds 5); every preset now agrees with what it builds.
  • :triangular_ruler: Two labels were cut off at 150 % display scaling: “Reconfigure an existing cave actor instead of
    spawning a new one” (it needed 457 px and got 412) and the “Done” step badges. Both fit now, 29
    fixed-width text wraps follow their container instead, and the window’s minimum size is 960×720.
  • :control_knobs: Smaller fixes: Alien Hive’s and Strata Canyon’s radii in the comparison table match the presets
    (400 and 1000 cm); the Preset Workflow buttons sit under their description; the “Selected” badge
    moved to the card’s footer; risk and validation colours update live instead of keeping the colour
    they had when the page was built.

:high_voltage: Performance

On a 28 m tunnel with a 7 m bore at 25 cm voxels (1.3 M voxels), the generator’s worker time went from
87–90 ms to 52–57 ms: hole fill 33 → 14 ms, mesh build 15.4 → 9.7 ms, overlays 10.4 → 3.1 ms. The new
floor smoothing adds about 2 ms of that back.

  • :brick: Mesh attributes are enabled after the vertices and triangles are appended, not before.
  • :artist_palette: Normal, colour and UV overlays are computed in parallel and filled one overlay per task, one
    element per vertex. This also fixes UV elements that were shared between a welded vertex and the
    copy the welder split off for a non-manifold triangle, which broke the overlay’s invariant.
  • :hole: The tunnel hole-fill pass runs in parallel over Z slices, with an identical result; it was the
    largest single-threaded stage.

:artist_palette: Fixed — the props’ look

  • :droplet: Rock props rendered wet. The bake script passed output ranges to a helper that expects input
    ranges, so rock roughness came out near 0 (atlas average 0.17 where 0.72–0.9 was asked for). Rock
    roughness now averages 0.68; crystal and organic roughness are corrected the same way.
  • :new_moon: Props were darkened by their neighbours. All thirteen props sit at the origin in the bake
    scene, and the ambient-occlusion bake counted the others as occluders. Each prop now bakes alone.
  • :package: The thirteen meshes, three atlases and four material instances were re-imported on UE 5.5 and
    replaced in place.

:shield: Added — the collision cap warning

  • :hole: Unreal builds no collision for a dynamic mesh over 250,000 triangles
    (geometry.DynamicMesh.MaxComplexCollisionTriCount) and says so once per session, at Display level —
    while IOC allows 2,000,000. A big cave rendered and the player fell through it. Such a cave now logs a
    warning by name every time, sets bLastCollisionSkipped, and GetPerformanceSummary() ends with
    “NO COLLISION” (Production.CollisionCapWarning).

:hole: Fixed — the demos

  • :pick: The Warren’s walkway was blocked in two places in the Nest. The lane re-ran the same carve
    three times, and an identical carve changes nothing, so 2 of 615 clearance checks stayed in rock
    every run. Lane carves are now sized by the cave’s voxel — a sphere on each end of the character’s
    clearance capsule, reaching a voxel past it — and each later round reaches half a voxel deeper.
    With 0.4.5’s floors it clears the Nest in one round (Demo.WarrenPlug now checks the count).
  • :cyclone: The tour’s portal was up the Forge’s end wall. Its trigger started 2 m past the walkway, on a
    slope steeper than a character can walk, and its crystal stood in the rock. The trigger now starts
    just past the walkway’s end and the crystal and its light stand on the generated floor
    (Demo.InteractiveLaneInBore).
  • :construction: Walkways in both demos keep their corridor through every rebuild (above);
    Demo.InteractiveLaneInBore and Demo.WarrenLaneInBore check it independently of the cave.

:books: Docs

  • Manual: WalkableFloorSmoothing, scatter stability and exclusions, the PCG node’s output settings,
    the collision cap, two new troubleshooting entries; the tutorial and demo guide say six presets,
    thirteen props and three demo maps.

:test_tube: Tests

  • :new_button: Seven new tests: Cave.WalkableFloor, Cave.ScatterStableAcrossCarves,
    Cave.ScatterExclusionSurvivesRebuild, Demo.InteractiveStreamingHighTickRate,
    Production.StreamingTunnelSeam, Production.CollisionCapWarning and PCG.VoxelCoreSurface (the
    node’s work now sits in IOCVoxelCore::BuildPoints, so it can be tested without a PCG context).
  • :plus: Extended: SetupWizard.Workflow checks every preset’s dressing against its cost estimate and the
    Organic Warren’s values; SetupWizard.Layout counts the style cards; SetupWizard.LiveLayout sweeps
    every page and scroll position for cut or spilling text; Demo.InteractiveLaneInBore and
    Demo.WarrenLaneInBore check the walking corridor for props (with their own geometry, not the cave’s)
    and the portal; Demo.WarrenPlug checks the walkway is clear of rock.
  • :hammer: Every new test and check was negative-tested: each failed against a build with its fix removed
    (the 240 Hz walk reproduced the original stall exactly), and the live layout sweep caught both cut
    labels in the 0.4.5 wizard.