Scripting Support (C#)
advanced scriptingVoxel Play 4 · Scripting / API
Getting Started
Voxel Play 4 exposes its public API through the VoxelPlayEnvironment class (singleton). All methods and properties documented in this section belong to VoxelPlayEnvironment unless otherwise noted.
Add using VoxelPlay; at the top of your script. No additional setup is needed beyond importing the Voxel Play package.
using VoxelPlay;
// Get the singleton instance
VoxelPlayEnvironment env = VoxelPlayEnvironment.instance;
// Place a voxel
VoxelDefinition stone = env.GetVoxelDefinition("Stone");
env.VoxelPlace(new Vector3d(0, 10, 0), stone);
// Subscribe to events
env.OnVoxelDestroyed += (chunk, voxelIndex) => {
Debug.Log("Voxel destroyed!");
};
Namespace
All Voxel Play types live under the VoxelPlay namespace. Add using VoxelPlay; at the top of your scripts.
Key Types
class VoxelPlayEnvironmentMain API singleton. Access via VoxelPlayEnvironment.instance. All world, voxel, terrain, item, model, and event APIs are accessed through this class.
struct Vector3dDouble-precision 3D vector used for world positions. Supports large worlds without floating-point precision issues.
struct VoxelRepresents a single voxel with its type, color, light, and metadata.
struct VoxelIndexReferences a specific voxel within a chunk (contains chunk reference + voxel array index).
struct VoxelHitInfoContains raycast hit data: chunk, voxel index, hit point, normal, and distance.
class VoxelChunkRepresents a 16×16×16 chunk of voxels. Contains voxel data, mesh, lighting, and colliders.
class VoxelDefinitionScriptable object defining a voxel type (textures, sounds, resistance, rendering mode, etc.).
class ModelDefinitionScriptable object representing a 3D voxel model that can be placed in the world.
class ItemDefinitionScriptable object defining an item (tool, weapon, block) with its properties and category.
class BiomeDefinitionScriptable object defining a biome with its terrain rules, vegetation, and voxel types.
class VoxelPlaceholderMonoBehavior attached to custom voxel GameObjects. Allows per-voxel scripting.
Enums
enum ChunkModifiedFilter { Anyone, OnlyModified, NonModified }Filter for chunk queries. OnlyModified returns chunks changed by the player; NonModified returns untouched chunks.
enum ColliderTypesFilter for collider detection in raycasts and voxel queries.
enum HideStyleControls how hidden voxels are rendered (fully invisible, semi-transparent, etc.).
enum ItemCategoryCategorizes items (voxel, tool, torch, weapon, general).
Delegates
delegate float SDF(Vector3d position)Signed Distance Function delegate used for custom volume definitions when querying voxels in arbitrary shapes.
API Sub-Pages
Due to the extensive API (~177 public methods), the documentation is organized into functional areas:
- World & Chunk Management — World operations, chunk access, visibility, and redraw
- Voxel Operations — Placement, destruction, damage, and collapse
- Voxel Queries — Index lookups, position calculations, and spatial queries
- Voxel Properties — Color, rotation, visibility, custom properties, highlighting, and physics
- Environment & Terrain — Raycasting, terrain height, biomes, water, lighting, and time
- Items & Models — Item spawning, torches, model placement, and UI messaging
- Events — All event callbacks for voxels, chunks, environment, and models
OBJ Export
VoxelPlayOBJExporter is a static utility class for exporting voxel models to OBJ format with textures.
A minimal example that builds a textured GameObject from a model and writes it to OBJ:
using UnityEngine;
using VoxelPlay;
public class MyScript : MonoBehaviour {
public ModelDefinition model;
void Start() {
// Create a standalone textured GameObject from a model
GameObject go = VoxelPlayEnvironment.ModelCreateGameObject(model);
go.transform.position = Vector3.zero;
// Export the model to OBJ for external tools
VoxelPlayOBJExporter.ExportModelToOBJ(model, Application.dataPath + "/../Export");
}
}
ExportModelToOBJ
static string ExportModelToOBJ(
ModelDefinition md,
string outputFolder,
Vector3? scale = null, // null = Vector3.one
bool useTextures = true, // false = geometry only
string fileName = null // override output name (in-memory models)
);
Exports a ModelDefinition to .obj + .mtl + PNG textures. Returns the path of the generated OBJ file, or null on failure. Supports regular voxels, microvoxels with dual materials, and rotated model bits.
ExportVoxelToOBJ
static string ExportVoxelToOBJ(
VoxelDefinition vd,
string outputFolder,
Vector3? scale = null,
bool useTextures = true,
string fileName = null, // override output name (in-memory definitions)
bool? forceAlphaCutout = null // true = bake alpha cutout regardless of renderType
);
Exports a single VoxelDefinition (including its microvoxels and secondary material) to OBJ.
Model Conversion
VoxelPlayConverter static methods for generating standalone GameObjects, with full microvoxel texture support and primary/secondary material routing.
GenerateVoxelObject (ModelDefinition)
static GameObject GenerateVoxelObject(
ModelDefinition md, Vector3 offset, Vector3 scale,
bool useTextures = true, bool useNormalMaps = true,
bool usePBR = false, GameObject updateGameObject = null
);
Generates a textured GameObject from a ModelDefinition. Mixed models (regular + microvoxel bits) are packed into a single mesh with a single TextureArray material. Pass an existing GameObject via updateGameObject to update it in place.
GenerateVoxelObject (VoxelDefinition)
static GameObject GenerateVoxelObject(
VoxelDefinition vd, Vector3 offset, Vector3 scale,
bool useTextures = true, bool useNormalMaps = true,
bool usePBR = false, GameObject updateGameObject = null
);
Generates a textured GameObject from a single VoxelDefinition. Microvoxels render with correct primary and secondary textures based on the layout mode (Slabs, TopCap) and per-quad palette routing.
Convenience Wrappers
// On VoxelPlayEnvironment (instance or static)
GameObject ModelCreateGameObject(ModelDefinition md, ...);
GameObject VoxelCreateGameObject(ModelDefinition md, ...);
Delegate to VoxelPlayConverter.GenerateVoxelObject. Signatures match those methods.
Microvoxel Thumbnails
// MicroVoxels instance method
Texture2D GenerateThumbnail(int width = 256, int height = 256);
Renders a preview image of the microvoxel shape to a Texture2D. Uses a temporary camera and command buffer - no scene objects are affected. Works at runtime and in the editor. The caller is responsible for destroying the returned texture.
PBR Texture Packing
// TextureTools static method
static Texture2D PackSurfaceMap(
Texture2D metallic, Texture2D smoothness,
Texture2D occlusion, Texture2D height,
int resolution = 256
);
Packs four separate PBR channel textures into a single surface map for the VP PBR model shader. Call at runtime or use the editor utility under the VoxelDefinition inspector.
Model Placement
// VoxelPlayEnvironment - enhanced ModelPlace
void ModelPlace(
Vector3d position, ModelDefinition model,
...,
bool skipEmptyVoxels = false
);
New skipEmptyVoxels parameter. When true, empty positions in the model do not overwrite existing voxels (e.g. water), so models can be placed inside filled volumes without creating air pockets.
Model bits also capture and restore the per-voxel smooth override (ModelBit.smoothOverride): a captured selection keeps which voxels were flipped smooth or cubed, and placing the model applies the override again. See Smooth Terrain.
Biome Lookup
// VoxelPlayEnvironment - new 3-parameter overload
BiomeDefinition GetBiome(float altitude, float moisture, float temperature);
Adds the temperature axis for VP4's 3-axis biome selection. See Biome System Upgrades for details on configuring BiomeZone temperature ranges.
Microvoxel methods
Six new overloads on VoxelPlayEnvironment for placing and destroying microvoxels at an explicit world position, without a VoxelHitInfo or normal-based offset. Designed for procedural generators and world-edit / brush tools. They share the existing MicroVoxelPlace / MicroVoxelDestroy name; C# discriminates by the 2nd parameter type (int = cube, Vector3d = AABB, float = sphere radius).
Cube at position
bool MicroVoxelPlace(Vector3d position, int size, VoxelDefinition voxelType, Color tintColor = default, int rotation = 0);
bool MicroVoxelDestroy(Vector3d position, int size, float probability = 1f);
Places or destroys a cube of size x size x size microvoxels centered on a world position. When microVoxelsSnap is enabled (default) and the cube fits in a single parent voxel, a fast path skips per-microvoxel lookups and just toggles bits.
Axis-aligned bounding box
bool MicroVoxelPlace(Vector3d boxMin, Vector3d boxMax, VoxelDefinition voxelType, Color tintColor = default, int rotation = 0);
bool MicroVoxelDestroy(Vector3d boxMin, Vector3d boxMax, float probability = 1f);
Fills or clears every microvoxel whose center lies inside the given AABB. Bounds are taken as-is (no snap), so callers can paint arbitrary rectangular regions.
Sphere brush
bool MicroVoxelPlace(Vector3d center, float radius, VoxelDefinition voxelType, Color tintColor = default, int rotation = 0);
bool MicroVoxelDestroy(Vector3d center, float radius, float probability = 1f);
Sphere brush. radius is in world units (1 unit = 1 voxel; MicroVoxels.SIZE = 1/16 unit per microvoxel). Microvoxels whose center is within radius of center are placed or removed.
Painting cells
bool MicroVoxelSetColor(Vector3d position, Color32 color);
Paints the microvoxel cell at a world position with a color via the palette system (occupancy is unchanged; a plain full voxel is converted to a full microvoxel grid first, so any solid surface can be painted). Requires Enable Tinting; painted colors persist in saved games. Demo 1 (Earth) binds it to its graffiti mode: press P, then hold the left mouse button and drag to spray. See Colored Microvoxels.
Batch Microvoxel Placement
bool VoxelPlace(List<Vector3d> positions, VoxelDefinition voxelType, List<MicroVoxels> microVoxels, Color tintColor = default, bool refresh = true);
Places the same voxel type on multiple positions, each with its own MicroVoxels data (one entry per position). Affected chunks are refreshed once per batch instead of once per voxel, so this is the right call for stamping code-built props that rasterize a different 16x16x16 shape into each cell. Returns true if every voxel could be placed.
Detail Generators: contract and best practices
Custom detail generators (subclasses of VoxelPlayDetailGenerator) that sculpt content at generation time must follow three rules. They come from how the engine schedules chunk creation and meshing, and breaking them produces bugs that only show up under load.
Register every voxel definition in Init()
public override void Init() {
env.AddVoxelDefinitions(concrete, masonry, glass, wood);
}
All voxel definitions your generator will ever place must be registered inside Init(), which runs during world initialization, right before the texture atlas is built. Registering definitions later (mid-generation, from AddDetail) forces a texture rebuild while meshing threads may already be iterating the atlas, which can surface as missing textures or thread exceptions. The batch VoxelPlace overloads auto-register unknown definitions as a safety net, but treat that as a fallback, not the design.
Nested AddDetail calls are managed by the engine
If your sculpting calls VoxelPlace or any API that touches a neighbor chunk that does not exist yet, the engine creates that chunk inline. Your generator is never re-entered for it: while a generator is busy inside AddDetail, chunks created this way are queued per generator and processed automatically right after the current call returns, so per-call state (scratch buffers, shared lists) is safe without any guard in your code. If your generator is genuinely re-entrancy safe and you prefer inline processing, set allowNestedExecutions = true on the generator asset to opt out of the deferral.
MicroVoxels ownership: what isShared controls
isShared is the copy-on-write ownership bit of a MicroVoxels instance. While it is false the instance is exclusively owned by the single cell that stores it, and every mutation (digging individual micro voxels, painting, layout or secondary-type changes) edits it in place with zero allocations. This is the fast path and the normal lifelong state for most instances in a world: per-cell unique content, and any clone produced by a previous edit. When it is true the instance is referenced from more than one place, so mutation paths clone it first and the cell keeps the clone, which is again exclusively owned (isShared = false).
The flag is promoted to true automatically when the same instance is stored into a second cell, and definition assets (MicroVoxelsDefinition, model bits) are born shared. The one case where you should still set it manually is a reusable template built in code: automatic promotion only happens on the second placement, so between the first placement and the second the template sits in one cell as exclusively owned, and any mutation reaching that cell (player digging, a merge, a damage pass) would edit your template in place and corrupt every future placement. Creating code-built templates with isShared = true closes that window. See Microvoxels for details and for colored microvoxels.
Smoke Particles
GameObject CreateSmokeParticle(Vector3d position, float scale = 0.35f, float duration = 6f, Color32 color = default);
void CreateSmokeParticles(Vector3d position, int amount, float scale = 0.35f, float duration = 6f, Color32 color = default);
Spawns smoke puffs from the shared particle pool. Puffs ignore gravity and rise with a chaotic wander that widens with age, so a steady emitter produces a column that opens into a cone. Under an opaque ceiling a puff stops rising and drifts horizontally hunting for an opening, re-picking its direction when the path closes, and resumes its ascent once the sky clears - smoke poured into a room escapes through windows or up stairwells by itself.
amount(plural form) emits a burst, mirroring the impact particles API; each puff varies its scale and duration.scaleis the birth size; puffs swell to roughly 2-3x with an eased-in curve and dissolve at the end of their life.colordefaults to smoke grey; its alpha drives transparency (default 178/255). Particles are born blazing yellow and cool through ember red into the smoke color over the first fifth of their life.- Puffs collide with opaque geometry but never with each other or with other particles (the particles layer ignores itself).
- Smoke shares the pool with damage debris (
particlePoolSize, default 1000). Heavy use - several persistent emitters - can exhaust it silently; raise the pool size in the environment inspector or from a detail generator'sInit().
The calls are one-shot: for a persistent fire, invoke them on a timer from your own component.
Voxel Fires
bool SetVoxelOnFire(Vector3d position, float intensity = 1f, bool light = false);
bool ExtinguishFire(Vector3d position);
bool IsVoxelOnFire(Vector3d position);
int firesCount;
event System.Action<Vector3d> OnFireStarted;
event System.Action<Vector3d> OnFireExtinguished;
delegate bool FireSpreadEvent(Vector3d fromVoxelPos, Vector3d toVoxelPos, VoxelChunk toChunk, int toVoxelIndex);
event FireSpreadEvent OnFireSpread;
A fire is anchored to an existing voxel, which acts as its fuel. While it burns, the engine emits smoke bursts from it (see Smoke Particles): puffs are born blazing yellow with an emissive glow, cool through ember red and rise as a darkening column. intensity scales the size and lifetime of the puffs.
- Destroy the fuel, kill the fire. Every emission tick re-checks the anchor voxel; if it was destroyed by any means (player, explosion, scripts), the fire extinguishes itself and raises
OnFireExtinguished. No special integration is needed in destruction code. SetVoxelOnFirereturnsfalsewhen the position holds no voxel; starting a fire twice on the same voxel is a no-op.light = truemakes the fire emit light like a torch (voxel torch lightmap plus a flickering point light) without any torch object; the light is materialized only while the camera is withinfiresLightRange.ExtinguishFireputs a fire out programmatically (water, extinguishers, rain systems).- Fires beyond
firesSmokeRange(environment field, default 60) pause their emission but stay alive. - The events make gameplay hooks trivial: objectives like "put out all fires", scoring, or audio can subscribe without polling.
Fires are runtime state and are not serialized with saved games yet. Demo 1 (Earth): press I to ignite the targeted voxel, press it again to extinguish.
Fire spread & burn outcomes
Beyond a single anchored fire, flammable voxels catch fire from burning neighbours. Spreading checks all 26 surrounding voxels with an upward bias, so flames climb through a structure faster than they creep sideways or downward. Flammability is configured per Voxel Definition (flammability, burnDuration, burnOutcome, burnsInto). Two environment fields tune the simulation globally: firesSpreadSpeed multiplies the chance of spreading to neighbours, and firesSpreadMax caps how many spread-born fires can exist at once (fires started with SetVoxelOnFire are exempt from the cap).
When a burning voxel is consumed it resolves its BurnOutcome:
- Disappear - the voxel is removed (default).
- Transform - the voxel becomes its
burnsIntodefinition (for example, charred wood). - Char - the voxel stays in place but darkens progressively toward a charred color and no longer reignites (requires Enable Tinting).
Fire that reaches water is put out with a steam burst. Subscribe to OnFireSpread to react to or veto spreading: returning false from the handler prevents that particular voxel from igniting.
Deferred Voxel Writes
When a custom terrain or detail generator needs to place voxels into a chunk that may not exist yet (bridges, waterfalls, vegetation or trees that overflow into a neighbour chunk), do not call CreateChunk recursively. Queue the writes instead, and Voxel Play applies them on the main thread once the destination chunk is available.
// Single write
void VoxelPlaceDeferred(Vector3d position, int voxelIndex, VoxelDefinition voxelDefinition,
Color32 color, MicroVoxels microVoxels, DeferredVoxelWriteFlags flags,
byte waterLevel = 0);
// Batch overload: groups positions by chunk for you (no manual voxel index)
void VoxelPlaceDeferred(List<Vector3d> worldPositions, VoxelDefinition voxelDefinition,
Color32 color, MicroVoxels microVoxels, DeferredVoxelWriteFlags flags,
byte waterLevel = 0, List<byte> waterLevels = null);
position: any world position inside the destination chunk (the chunk is derived automatically).voxelIndex: local voxel index inside that chunk (0 .. chunk voxel count - 1).flags: write conditions (see below); combine with|.
How writes are applied: they are buffered per chunk and drained on the main thread every frame, within the chunk-creation time budget. A chunk's writes are applied once it is populated; with the ForceCreate flag the chunk is created so the writes can land. Writes survive save/load: if a saved chunk is restored later, its pending writes are applied on load. Call these from the main thread (detail-generator callbacks already run on the main thread).
public enum DeferredVoxelWriteFlags {
None = 0,
EmptyOnly = 1, // write only if the target voxel is empty
EmptyOrSame = 2, // write if empty or already the same type
NonSolidOrCutout = 4, // only overwrite non-solid or cutout voxels
TopHalf = 8, // half-voxel placement into the top half
MarkExterior = 16, // tag the voxel as exterior
MarkAboveSurface = 32, // tag the voxel as above the surface
DisableTrees = 64, // prevent tree population on the affected chunk
ForceCreate = 128, // create the destination chunk if it does not exist yet
SkipModified = 256, // skip chunks the player has already modified
BottomFill = 512, // also fill the voxel below
Clear = 1024, // clear (remove) the voxel at the target position
Colorize = 2048 // paint a colored shape onto the existing voxel's surface
}
Clear: removes the voxel at the target position once its chunk is available (deferred deletion) instead of writing one.Colorize: decal-style painting. Pass aMicroVoxelsshape whose colored cells are stamped flush onto the surface of the voxel that already occupies the target - the voxel is promoted to a full micro grid so its face cells can be tinted, only occupied cells are painted, and the chunk is never marked modified (so the write recycles like any deferred prop). The target voxel must support microvoxels. Handy for graffiti, stains or decals baked at generation time.
Pouring Liquids (VoxelPour)
VoxelPour pours a liquid (water or lava) from a source position as a deterministic, one-shot cascade painted through the deferred-write system: a falling column plus a tapered landing pool that spreads up to poolRadius (the level ramps from full at the centre to 1 at the rim) and re-spills at edges into lower tiers. The liquid is not enrolled in the runtime water flood (no spread simulation, no chunk-modified flag), so the result is deterministic and never bloats the save file. It is bounded by maxVoxels, so it is safe to call from a detail generator or on demand.
void VoxelPour(Vector3d source, VoxelDefinition liquid,
int poolRadius = 8, int maxVoxels = 2000,
System.Func<Vector3d, bool> isSolid = null);
source: world position where the liquid originates.liquid: theVoxelDefinitionof the liquid to pour (a water or lava voxel).poolRadius(default 8): maximum radius of each landing pool; the level tapers from full at the centre to 1 at the rim.maxVoxels(default 2000): upper bound on the number of voxels painted; caps the cost of the cascade.isSolid: predicate that returnstruewhere the liquid is blocked. Pass a pure positional predicate (terrain density, your own carved geometry) for deterministic generation. Leave itnullto test the actual voxel data viaGetVoxel- which force-creates chunks at generation time, so during generation callVoxelPourdiscretionarily (once, guarded), not unconditionally per chunk.
If the falling column meets an existing pool or the sea it merges into it instead of stacking a new pool (the existing water owns that tier). The cascade is painted via VoxelPlaceDeferred, so it lands correctly even across chunks that do not exist yet.
Deferred Torch Placement
For torch-heavy scenes you can register torches without instantiating them up front and let the lighting manager materialize and recycle them by proximity, so only the torches near the camera exist as live objects at any moment.
// Register a torch to be materialized on demand (does not instantiate yet)
void TorchAttachDeferred(Vector3d worldPos, Vector3 normal, ItemDefinition torchDefinition);
// Clear all deferred torches recorded for a chunk (e.g. before re-recording it)
void TorchClearDeferred(Vector3d chunkWorldPos);
// Materialize/recycle deferred torches around an observer (called by the lighting manager)
void ProcessDeferredTorches(Vector3 observerPos);
Use TorchAttachDeferred while generating or decorating the world to record where torches should appear. The lighting manager calls ProcessDeferredTorches as the camera moves, spawning the nearest torches and despawning distant ones, so prefab count, animation and light updates stay bounded regardless of how many torches the world contains.
Voxel Reactions
Voxel reactions are data-driven - the rules live in VoxelReactionSet assets assigned to the World Definition - but you can hook the runtime from code. A World Definition can hold several sets in reactionSets and their rules are combined; any voxel type joins a rule by listing a matching entry in its VoxelDefinition.reactionTags, without editing the rules.
Events
// Raised before the outcome is applied. Return false to cancel the reaction
// (the liquids then act as barriers). Set suppressEffects = true to apply the
// outcome but skip the built-in vapor/sound so you can play your own.
public delegate bool VoxelReactionBeforeEvent(VoxelChunk chunkA, int voxelIndexA,
VoxelChunk chunkB, int voxelIndexB,
VoxelReactionRule rule, ref bool suppressEffects);
// Raised after the outcome is applied.
public delegate void VoxelReactionEvent(VoxelChunk chunkA, int voxelIndexA,
VoxelChunk chunkB, int voxelIndexB,
VoxelReactionRule rule);
event VoxelReactionBeforeEvent OnVoxelReactionBefore;
event VoxelReactionEvent OnVoxelReaction;
Methods
// Manually attempt a reaction between two touching voxels. Returns true if a rule fired.
bool TryVoxelReaction(VoxelChunk chunk1, int voxelIndex1, VoxelChunk chunk2, int voxelIndex2);
// Spawn the same vapor puff burst reactions use, anywhere you like.
void CreateSteamEffect(Vector3d position, int amount = 8, float scale = 0.15f,
float duration = 1.5f, Color32 color = default);
Use OnVoxelReactionBefore to veto specific reactions or to swap the default puffs for your own effect:
env.OnVoxelReactionBefore += (VoxelChunk a, int ia, VoxelChunk b, int ib,
VoxelReactionRule rule, ref bool suppressEffects) => {
Vector3d pos = env.GetVoxelPosition(a, ia);
suppressEffects = true; // skip the built-in vapor, play our own
env.CreateSteamEffect(pos, amount: 16, scale: 0.2f, color: new Color32(230, 230, 235, 255));
return true; // let the reaction proceed
};
Underwater Screen Effect on Any Camera
The underwater overlay and caustics no longer require a character controller. Voxel Play attaches a VoxelPlayUnderwaterEffect to the main camera automatically when Enable Underwater Effect is on, and you can add the same component to any other camera (spectator, cinematic, split-screen) to get the effect there too.
// Add to any Camera (RequireComponent(typeof(Camera)))
public class VoxelPlayUnderwaterEffect : MonoBehaviour {
public bool isUnderwater { get; } // camera below the water surface
public bool isSwimming { get; } // camera in the wading band near the surface
public bool isInWater { get; } // underwater || swimming
}
// That is all - the overlay and caustics now render for this camera
spectatorCamera.gameObject.AddComponent<VoxelPlayUnderwaterEffect>();
To query water state for an arbitrary camera without adding the overlay, call:
bool GetCameraWaterInfo(Camera cam, out bool underwater, out bool swimming,
out float waterLevelTop, out float causticsLevelTop,
out Color waterColor, out int cameraWaterLevel);
Returns true when the camera is in or under water, and fills the current water surface height, caustics height, tint color and the water level of the voxel the camera sits in.
Runtime Tint Repaint
Voxels bake their tint color when they are created, so changing a VoxelDefinition.tintColor at runtime does not affect voxels already in the world. These two calls re-apply the current tint colors to loaded voxels and redraw the affected chunks - handy for recoloring a material live or previewing a full palette swap. Both require Enable Tinting.
// Repaint every loaded voxel of one type with its VoxelDefinition.tintColor
void RefreshTintColor(VoxelDefinition vd);
// Repaint every loaded voxel with its current tint color (full palette preview)
void RepaintWorld();
grass.tintColor = new Color32(180, 120, 60, 255); // autumn palette
env.RefreshTintColor(grass); // existing grass turns brown at once
Public Properties (41.0)
New serialized properties added in 41.0, grouped by area. Each is also available in the corresponding inspector.
Rendering (VoxelPlayEnvironment)
bool enableChunkOcclusionCulling; // default false
float smoothLightingAOStrength; // 0-1, default 1
enableChunkOcclusionCulling: skips drawing chunks that are sealed off from the camera by solid blocks. Best for caves, tunnels and enclosed interiors; little effect on open terrain. See Chunk Occlusion Culling.smoothLightingAOStrength: strength of the corner darkening (ambient occlusion) baked by smooth lighting - 1 = classic look, 0 = no corner darkening. Exposed as AO Strength under Smooth Lighting. Note: the former Obscurance Mode option is now labeled Sunlight Curve in the inspector (sameobscuranceModeproperty: it shapes the sun light response, not the baked AO).
Torch and Fire Lights (TorchLightAnimator)
float flickerSpeed; // default 2
float flickerCrackle; // 0-1, default 0
flickerSpeed controls the smooth base flicker of the point light; flickerCrackle adds harsh firelight on top: random stepped jumps with occasional bright pops and short ember dips (0 = classic smooth pulse). Torches default to the classic pulse; voxel fires use crackle.
Water (WorldDefinition)
bool enableWaterFlood; // default true
enableWaterFlood: lets water voxels spread/flow at runtime. Disable it for static water bodies to avoid runtime re-meshing.
Clouds (WorldDefinition)
VoxelPlayCloudStyle cloudStyle; // Chunks (default) | Mesh
// Mesh-style parameters:
float cloudMeshMaxHeight;
float cloudMeshHeightVariation;
float cloudMeshAltitudeSpread;
float cloudMeshCoverageMax;
float cloudMeshCoverageSoftness;
float cloudMeshCoverageSpeed;
float cloudMeshSunScatter;
float cloudMeshRounded; // 0 = flat-lit cubes (silhouette stays voxel), 1 = soft rounded puffs
Set cloudStyle = VoxelPlayCloudStyle.Mesh to render clouds as a dedicated mesh with smooth coverage transitions and volume; the cloudMesh* fields tune its height, coverage and sun scattering. Chunks keeps the classic voxel clouds.
Rendering (VoxelDefinition)
bool allowsTextureRotation; // default true ("Can Rotate" in the inspector)
Controls whether this voxel's textures may be rotated. Side faces rotate by reassigning their texture index; top and bottom faces rotate their UVs. Set to false to lock a voxel's texture orientation.
Biomes (VoxelPlayEnvironment)
bool smartBiomeSurface; // default true
bool enableBiomeTinting; // default false
float biomeTransitionWidth; // 0.001-0.5, default 0.05
When enabled, dirt voxels left exposed at the surface are rendered using the biome's surface voxel, so terrain carved or edited at runtime keeps a consistent surface look.
enableBiomeTinting blends each biome's Terrain Tint Color across biome borders by tinting the surface voxels, giving smooth color transitions instead of hard seams (this replaces the older Biome Mixing). biomeTransitionWidth sets the width of that blend band (higher = wider, softer). Both require Enable Tinting.
Super Chunks (VoxelPlayEnvironment)
bool enableSuperChunkTrees;
Renders distant, visual-only tree LOD meshes within super chunks. These are rendering-only: they have no real voxels, colliders or gameplay events.
Structural Collapse
The structural collapse system raises events as structures fall and exposes an API to query, damage and manage debris from your own code. See the feature page for the concept and the inspector settings.
Events
All events are on VoxelPlayEnvironment:
| Event | Signature and when it fires |
|---|---|
OnVoxelCollapseBefore | (List<VoxelIndex> indices, ref bool cancel) - fires with the voxels that are about to fall, before any debris spawns. Set cancel = true to keep the structure in place. |
OnVoxelCollapse | (List<VoxelIndex> indices) - the voxels have collapsed and left the grid. |
OnCollapseDebrisSpawned | (VoxelCollapseDebris debris) - a debris body was created. |
OnCollapseDebrisImpact | (VoxelCollapseDebris debris, Collision collision, float impactSpeed) - the body hit the world or another body (same speed and cooldown gates as the impact dust). Use it for crush damage or impact SFX. |
OnCollapseDebrisDamaged | (VoxelCollapseDebris debris, Vector3 hitPosition, int damage, bool cellDestroyed) - a body took damage; cellDestroyed is true when the hit removed a cell. |
OnCollapseDebrisSplit | (VoxelCollapseDebris source, VoxelCollapseDebris fragment) - a fragment broke off a damaged body. |
OnCollapseDebrisRemoved | (VoxelCollapseDebris debris, DebrisRemovalReason reason) - a body left the scene. reason is Destroyed, Sunk, SmartRemoved or FellOffWorld. |
API
// Pure what-if: would removing the voxel at this position bring anything down?
// Runs the full solver with the cell treated as air. Nothing spawns or changes.
bool WouldCollapse(Vector3d position, List<VoxelIndex> affectedVoxels = null);
// Enumerate the live debris bodies (self-pruning registry). Returns the count.
int GetCollapseDebris(List<VoxelCollapseDebris> results);
// Apply damage to a debris body from a custom weapon; returns true if a cell was destroyed.
bool CollapseDebrisDamage(VoxelCollapseDebris debris, Vector3d hitPoint, int damage, bool addParticles = true);
// Remove a debris body programmatically.
void CollapseDebrisRemove(VoxelCollapseDebris debris, bool addParticles = false);
// Manually trigger a structural collapse around a position (also called internally on destruction).
void VoxelCollapse(Vector3d position, int budget, List<VoxelIndex> voxelIndices = null, float debrisLifetime = 0);
// Blow up an area: damages every voxel within radius and throws a fraction of the destroyed voxels
// outwards as debris pieces (destructible, dust on impact, honoring the world debris removal mode).
// Returns the number of damaged voxels.
int VoxelExplode(Vector3d origin, int damage, int radius, float debrisAmount = 0.5f, float debrisForce = 9f,
bool attenuateDamageWithDistance = true, bool addParticles = true, bool playSound = false,
bool canAddRecoverableVoxel = false, List<VoxelIndex> damagedVoxels = null);
WouldCollapse is handy for build-mode warnings ("removing this will drop the roof") or for AI that avoids undermining itself: it treats the target cell as empty and reports whether anything would fall, without spawning debris or firing events.
VoxelExplode is a one-call way to blow up a region: it applies radial damage and turns a fraction of the rubble into flying debris that behaves exactly like collapse debris (you can shoot it apart, it raises dust on impact and it honors the world debris removal mode). Voxel types with Max Debris Size 0 caught in the blast shatter into particles instead of flying off as pieces.
Per-voxel collapse settings (VoxelDefinition)
VoxelCollapseBehavior collapseBehavior; // Auto | Anchored | Tension
int maxSupportDistance; // 0-64, 0 = unlimited (connectivity only)
int maxDebrisSize; // 0-64: max falling piece length; 0 = shatters (fragile), 64 = falls whole
collapseBehavior: Auto solid blocks fall when disconnected from a support; Anchored never falls and supports others (terrain-like); Tension hanging elements such as cables that carry no support and drop as a whole run when they keep fewer than two separate supports.maxSupportDistance: how far (weighted) a voxel of this type may sit from a support before it falls - steps up are free, lateral steps cost 1, hanging steps cost 2.0means unlimited (pure connectivity). Applies to Auto types.maxDebrisSize: max length in voxels of a falling piece along any axis - larger groups are cut into grid-aligned pieces of at most this size as they fall.0shatters the type into particles instead of joining a debris body (fragile: foliage, glass, brittle props);64means unlimited (the piece falls whole). Default3.
Suggest an improvement
Help us improve this documentation page.