FAQ
beginner faqVoxel Play 3 · Troubleshooting & FAQ
Is this asset compatible with Unity 6?
Yes. All Kronnect assets are fully compatible with Unity 6. The minimum supported version is Unity 2022.3 LTS, and this includes Unity 6 and any newer releases.
Starting with an Empty World
If you don't want to use any terrain generator feature, just follow these steps:
1.- Create a new scene and add VoxelPlayEnvironment (menu GameObject -> Voxel Play -> Create Voxel Play Environment).
2.- Create a new World Definition (right-click on your project panel, select Create -> Voxel Play -> World Definition).
3.- Assign the World Definition to the VoxelPlayEnvironment inspector's "World" field.
Run the scene. You will get a fully functional voxel engine with no predefined terrain.
Creating a Flat World
Instead of creating everything from scratch and if you want to reuse the voxel definitions included in the sample world, you can follow these steps to modify the terrain generator and biomes to produce a nice flat world in 1 minute:
Limit Playable Area
For example, say you want to limit the playable area to a 200x200x200 box around zero world position (0,0,0):
1. Select FPSController and disable "Start On Flat". By default, this option will spawn the player on a flat and random position. The random position depends on the world seed. So it will only change if you change the seed. Note that Voxel Play will always spawn the player on top of the surface.
2. Move the FPSController position to (0,0,0) using the transform position fields in the inspector.
3. Scroll down and tick the "Limit Bounds Enabled" checkbox and enter the playable area size in the Limit Bounds fields.
That's it!
Step by step video:
Also, if you don't want to render any chunk beyond the extents area, you have 2 options:
1. Recommended: uncheck the "Infinite" toggle in the World Definition fields and set World Extents to 200x200x200 in World Definition:

2. Or you can add this script to FPSController gameobject which basically overrides the chunk contents with empty voxels:
using UnityEngine;
using VoxelPlay;
public class LimitArea : MonoBehaviour {
VoxelPlayEnvironment env;
void Start () {
env = VoxelPlayEnvironment.instance;
env.OnChunkBeforeCreate += (Vector3d chunkCenter, out bool overrideDefaultContents, VoxelChunk chunk, out bool isAboveSurface) => {
const float MAX_DISTANCE = 100;
float dx = Mathf.Abs (chunkCenter.x);
float dy = Mathf.Abs (chunkCenter.y);
float dz = Mathf.Abs (chunkCenter.z);
if (dx > MAX_DISTANCE || dy > MAX_DISTANCE || dz > MAX_DISTANCE) {
overrideDefaultContents = true;
/* Here you could provide your own voxels setting the chunk.voxels array for the chunk which is 16x16x16. If you don't provide any voxels, the chunk will be empty */
} else {
overrideDefaultContents = false;
}
isAboveSurface = true;
};
}
}
Import Qubicle Models
Watch this video to learn how to import Qubicle models in Unity using Voxel Play:
Mobile Support
Mobile support has been included since beta 12 with integrated touch controls.
Please note that due to limited memory capability, both chunks pool size and visible distance should be kept reasonably low when running on mobile.
If you experiment issues on your mobile device, select Voxel Play Environment and click "Fastest" settings.
iOS (iPhone 7+) and Android (Note2 and Galaxy S6) have been tested using Fastest settings and provide smooth gameplay.
Notes:
- Touch input UI is only rendered on the mobile devices. To try it, make a build for your mobile device and run it.
- The default touch input UI can be customized editing the prefab CanvasTouch located in VoxelPlay/Resources/VoxelPlay/Defaults/UI folder.
- The default input manager for touch interface is in file DualTouchController.cs located in VoxelPlay/Scripts/Private/Input folder.
Check out this page to learn how to create your own input managers using Voxel Play framework (or you can completely use your own character controllers).
Profile GC Spikes in Editor
When running the game in Unity Editor, some garbage collection (GC) spikes can show up. This behavior is due to the chunks pool not fully reserved when playing the game inside the Unity Editor to provide a faster starting up experience during development. In a build, the entire chunk pool is reserved during start up, so GC spikes should not occur.
Custom Voxel Definitions (Design Time)
Starting beta 13 it's possible to create new voxel definitions that represent real game objects. This feature is called "Model-In-Voxel" and allows you to treat normal gameobjects as voxels inside chunks, so they can be hit, destroyed or collected.
Watch the video below to learn how to create custom voxel definitions:
Voxel Definitions at Runtime
Tthe following code adds a new voxel definition at runtime (playmode).
First, it creates a new instance of VoxelDefinition and populates basic fields like name "Brick", the render type (in this case full opaque voxel) and the textures to be used.
Then, it places a new voxel of the new type just over the crosshair (this part is optional and provided to complete the example).
VoxelDefinition vd = env.GetVoxelDefinition ("Brick");
if (vd == null) {
vd = ScriptableObject.CreateInstance<VoxelDefinition> ();
vd.name = "Brick";
vd.renderType = RenderType.Opaque;
vd.textureTop = texture;
vd.textureSide = texture;
vd.textureBottom = texture;
env.AddVoxelDefinition (vd);
}
VoxelPlayFirstPersonController fpsController = VoxelPlayFirstPersonController.instance;
if (fpsController.crosshairOnBlock) {
Vector3 pos = fpsController.crosshairHitInfo.voxelCenter + fpsController.crosshairHitInfo.normal;
env.VoxelPlace (pos, vd);
}
Converting Unity Terrains
Voxel Play includes a special terrain generator called "UnityTerrainGenerator" that translates terrain heightmap and its resources (splatmaps, trees and vegetations) to voxel definitions and models (for trees) with a few clicks.
To convert an existing terrain (eg. generated by Gaia or any other terrain generator tool), please watch the video below:
Unity Terrain Generator options

- Terrain Data: drop here the TerrainData object used by your terrain.
- Sea Level: adjust the sea altitude level.
- Thumbnail Size: size for the texture thumbnails below - just useful for presentation in this window.
Terrain Textures
Each terrain texture will produce a Voxel Definition.
In Voxel Play, terrain voxel definitions are composed of two voxel definitions: one for the surface voxel and another for the underground voxel. The surface voxel uses 3 different textures (one for the top side, a second one for the side textures and a third for the bottom side) while the underground voxel usually uses the same texture around the cube.
- Texture Size: the size of the generated textures that will be used in the new voxel definitions for each terrain texture.
- Voxel Top: this property links to the voxel definition for the surface voxel (once it's generated).
- Smooth: blurs the original texture. Some textures present too much noise when reduced. In the screenshot above, the Texture Size is set to 16 pixels (16x16) which can result in lot of noise so applying smooth can help produce a better looking result.
- Dirt With: specify the second texture used to mix with to produce the side texture for the surface voxel. Most surface voxels have a side texture that blends between the top texture and the bottom texture.
- Blend Power: the intensity of the blend between the top and "Dirt With" texture. A value of 0 will result in using only the top texture for the sides of the surface voxel.
- Voxel Dirt: this is the voxel definition used for the underground voxel (once generated). It uses the texture pointed by the Dirt With option.
- Action: Create / Assigned or Ignored. Create will generate the two voxel definitions (top and dirt or underground). Assigned means the voxel definitions have been generated and will be used. Ignored means this terrain texture will not produce any voxel definition.
Trees

Each tree will produce a Model Definition which contains a collection of voxels of different types. The converter will produce on voxel definition per each material included in the tree prefab.
- Texture Size: the size of the generated textures that will be used by the new voxel definitions used in the tree model definition.
- Frond Density: the "opacity" of the frond textures. Frond or leaves textures use CutOut shaders so the density related to the amount of "holes" in these textures. A lower value means less density hence more holes.
- Tree Scale: an optional scale that's applied to the tree prefab before converting it to voxels (the original tree prefab is not modified).
- Model Definition: the resulting model definition.
- Smooth: blurs the original texture. Some textures present too much noise when reduced so smoothing the texture can help produce a better looking result.
- Action: Create / Assigned or Ignored. Create will generate the tree model definition. Assigned means the model definition has been generated and will be used. Ignored means this tree will not produce any model and won't be used.
Vegetation
Similarly to terrain voxels, the converter creates one voxel definition for each vegetation texture used in the terrain.

- Vegetation Density: the probability to place a vegetation of this type on the proper terrain position. A value of 1 will match the vegetation density of the original terrain. Reducing this value will produce clear areas.
- Texture Size: the size of the generated textures that will be used in the new voxel definition.
- Voxel Definition: the voxel definition for this grass texture, once it's been generated.
- Action: Create / Assigned or Ignored. Create will generate the vegetation voxel definition. Assigned means the voxel definition has been generated and will be used. Ignored means this vegetation will not produce any voxel definition and won't be used.
Please note that the UnityTerrainGenerator tries to approximate the look of the original terrain. The elements to consider are:
- Heightmap: the original heightmap will be used so no differences here.
- Sea Level: you need to adjust the water level in the Terrain Generator field, just under TerrainData field (shown above).
- Textures: the textures generated by the converter can be fully replaced by you. Just select the voxel definitions generated by the generator and assign or supply your own textures to match your style and preferences.
Place Models at Runtime
The code below creates an array of voxel definitions and populates it with the voxel definition #1. Then uses the method ModelPlace to add the content to the scene in front of the camera.
Note that you can use your own voxel definitions defined at runtime as well.
int sizeX = 12, sizeY = 12, sizeZ = 12;
VoxelDefinition[,,] model = new VoxelDefinition[sizeY, sizeZ, sizeX];
VoxelDefinition vd = env.GetVoxelDefinition (1);
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
for (int x = 0; x < sizeX; x++) {
model [y, z, x] = vd;
}
}
}
VoxelPlayFirstPersonController fpsController = VoxelPlayFirstPersonController.instance;
env.ModelPlace (Camera.main.transform.position + Camera.main.transform.forward * 100, model);
Rotated Voxels
There're two ways to rotate voxels in Voxel Play
Native / Texture Rotation
This option is only available for voxels defined as Opaque 6-Textures (check the Voxel Definition):

Voxels of this type can be rotated using VoxelSetTexturesRotation or VoxelRotateTextures method. This method modifies custom flags in the voxel inside the chunks array which are recognised by the renderer and the appropriate side texture is applied depending on the current rotation.
This is the preferred way to rotate a voxel.
Free Voxel Rotation
Any voxel can be rotated with arbitrary rotations using VoxelRotate or VoxelSetRotation methods. These methods will convert the voxel to Dynamic which means an independent gameobject with an unique transform is created at the voxel position replacing it visually. All dynamic voxels use the same material so they batch dynamically. Call VoxelGetDynamic to get the GameObject for any voxel.
By creating voxel definitions of type "Custom" you can define arbitrary rotations, translations and scales for each of them.
Check out this video to learn how to create a second voxel definition that includes a 90º rotation around the y-axis:
Customize World & Save as Static Map
Editing/customizing the world and saving it as a static map is similar to save your game and using the saved game as your world map (as Minecraft does).
In Voxel Play, enter playmode in Unity Editor, edit/place your voxels and save your game as described here.
Then use that saved game as your starting world.
If loadSavedGame is set to true, the saved game specified by savedFilename property will be loaded when game starts.

Own Character Controllers
Voxel Play is a modular system in which the provided character controllers are optional.
For example, if you just want Voxel Play to render the world and interact with it using your own logic and character controllers, simply setup Voxel Play Environment in your scene but do not add any character controller - Voxel Play will pick your main camera (or the camera you assign to Voxel Play Environment inspector) to compute what's visible in the world and update the view accordingly and automatically.
Check this video for an example:
Excluding Areas from Rendering
Use the OnChunkBeforeCreate event to specify if a chunk can be rendered or not.
The following code produces an empty box centered at 0,100,0.
env.OnChunkBeforeCreate += (Vector3 chunkCenter, out bool overrideDefaultContents, Voxel[] voxels, out bool isAboveSurface) => {
Bounds exclusionBox = new Bounds();
exclusionBox.center = new Vector3(0,100,0);
exclusionBox.size = new Vector3(80,80,80);
if (exclusionBox.Contains(chunkCenter)) {
overrideDefaultContents = true;
} else {
overrideDefaultContents = false;
}
isAboveSurface = true;
};
Custom Input Controller
Please refer to this section for information about how to provide your own UI or controllers.
Get Biome at Player Position
Use the GetBiome method to get the biome at any given position or based on altitude / moisture levels:
public BiomeDefinition GetBiome (float altitude, float moisture);
public BiomeDefinition GetBiome(Vector3d position);
Additionally, the method GetTerrainInfo can be used to get information about terrain at any position:
public HeightMapInfo GetTerrainInfo (Vector3 position);
This method returns a HeightMapInfo struct with the data associated to the position:
public struct HeightMapInfo {
public float moisture;
public int groundLevel;
public BiomeDefinition biome;
}- moisture: a value in the 0..1 range.
- groundLevel: an integer value that represents the altitude of the terrain in world space.
- biome: the biome found at that position.
Example code:
VoxelPlayEnvironment env = VoxelPlayEnvironment.instance;
Vector3 playerPosition = VoxelPlayPlayer.instance.GetTransform().position;
HeightMapInfo terrainInfo = env.GetTerrainInfo (playerPosition);
Debug.Log ("Current biome is " + terrainInfo.biome.name);
Get GameObject from Custom Voxel
When placing a custom voxel, it's possible to get the gameobject created. Note that if you enable the GPU Instancing option in the voxel definition you will also need to enable the "Create GameObject" checkbox (when using GPU Instancing, Voxel Play does not create gameobjects by default; if GPU instancing is not enabled for the custom voxel, then it will always create a gameobject).
Use this code to select the gameobject created when placing a custom voxel:
// Get the gameobject in the scene placed in "placePos" position VoxelChunk theChunk; int theIndex; VoxelPlayEnvironment env = VoxelPlayEnvironment.instance; env.GetVoxelIndex (placePos, out theChunk, out theIndex); VoxelPlaceholder placeholder = env.GetVoxelPlaceholder (theChunk, theIndex); // Select it in the Editor placeholder.transform.SetParent(null); UnityEditor.Selection.activeGameObject = placeholder.gameObject;(edited)
where placePos is the location of the voxel.
The last two lines are just for showing the voxel in the inspector. When you place a custom voxel, a voxel placeholder gameobject is created in the scene but because it's parented to the chunk it's hidden in the hierarchy therefore it needs to be unparent it in order to visualize it in the hierarchy (only for illustration purposes).
Read Triangles from Chunk
When using Geometry Shaders option, the generated mesh for the chunks' MeshFilter component has a POINT topology. This means that you cannot get the triangles from the MeshFilter mesh property as they are generated in the shader itself.
However you can get the triangles from the collider.sharedMesh as Voxel Play does generate a normal mesh for collider purposes
Sample code:
if (env.RayCast (ray, out hit, 500f, 15)) {Voxel voxel = env.GetVoxel (hit.voxelCenter);Debug.Log ("There's a voxel at " + hit.point.ToString("F6") + " of type " + voxel.type.name);Debug.Log ("Chunk triangles: " + hit.chunk.mc.sharedMesh.triangles.Length);}
Use Own Character Controller
Yes! Voxel Play can work with just a simple camera and no controllers.
However, there're a lot of features you can get for free by using the provided character controllers.
Both first person and third person controllers scripts included with Voxel Play can detect if you're using another solution instead of the standard Unity character controller. In this case, those controllers will shut down any character or camera rotation/movement functionality and limit their usage to aiming (crosshair) and checking collisions with the voxel world.
- To add Voxel Play controller features to your own first person controller, just add the VoxelPlayFirstPersonController script to your character. Once you do this, you will see a reduced set of options in the inspector that allows you to configure the cross-hair appearance and highlighting.
- To add Voxel Play controller features to your own third person controller, add the VoxelPlayThirdPersonController script to your character and enable the option "Use Third Party Controller" in the inspector. This will disable any camera/character movement functionality but will allow you to customize the cross-hair and voxel highlighting options.
You can still use the API to implement usual actions like hitting/destroying and placing voxels.
Custom Splash / Loading Screen
It's possible to modify the default "Loading" screen with your own splash screen.
The Voxel Play UI Canvas prefab located inside VoxelPlay/Resources/VoxelPlay/Defaults/UI folder contains a child element called "InitPanel" which is shown during asset initialization and chunk loading.
You can duplicate the "Voxel Play UI Canvas" prefab and modify the "InitPanel" child element (or add custom images, text, etc. under it). Assign the new prefab to the "UI Canvas Prefab" field in Voxel Play Environment inspector.

Custom Material / Shaders
Voxel Play supports two groups of voxels in terms of rendering features:
- Default/basic types: opaque, cutout, vegetation, water, transparent and opaque with no AO are predefined render types which come with optimized shaders.
- Custom voxel type: for custom geometry, they use materials which supports instancing (more info about custom voxels here).
Custom voxels allow you to use any material derived from VP Model* materials provided by Voxel Play. However, custom voxels although very fast produce independent geometries. They don't benefit from chunk-related shader features provided by the default types like face occlusion, integrated AO, POM and other effects.
Starting v4.0 Voxel Play allows you to provide a customized material/shader for any of the default types (opaque, cutout, water, ...). This means you can duplicate the default material and shader provided by Voxel Play for any of the default types, customize it and assign the new material to the voxel definition:

The Override Material option shown in the screenshot allows you to specify a customized material/shader for this render type.
Currently up to 12 additional custom material/shaders can be assigned to voxel definitions for a total of 16 different materials per chunk. Note that this count does not limit the number of different textures. The same material can use hundreds of different textures in Voxel Play because all materials support texture arrays. A material here is to be understood as a different shader or rendering type.
A "Locate Original" button is provided for convenience, so you can quickly locate the default material used by Voxel Play for the selected render type.
The "Textures By Material" option specifies that the material/shader uses specific textures assigned to the material and that VP should not pass the global texture array to the material.
Shadows Flicker Problem
Shadows flicker in Scene View:
This is due to the near/far clip of the SceneView camera using wrong values which cause precision issues in the depth buffer.
To fix this just select any object in SceneView and press "F" to focus the camera on it. This will reset the near/far clip values of the SceneView camera.
Shadows flicker in Game View:
Similar to the SceneView, this could be related to a depth precision issue. Try increasing the camera's near clip plane to 0.3 or even more.
Here's a good explanation on how the near clip plane determines the precision of the depth buffer.
Change Default Player Items
You can define which items can have the player at start in two ways:
1) Specify them in the Items array of the Voxel Play Player component:

2) Use scripting. Call VoxelPlayPlayer.instance.AddInventoryItem method to add a number of items of certain type to player inventory. This method can be called when Voxel Play is initialized (check DemoEarth.cs script file from demo scene 1 for full example):
VoxelPlayEnvironment env;
void Start () {
env = VoxelPlayEnvironment.instance;
// When Voxel Play is ready, do some stuff...
env.OnInitialized += OnInitialized;
}
void OnInitialized () {
// Item definitions are stored in Items folder within the world name folder
// Add 3 torches to initial player inventory
VoxelPlayPlayer.instance.AddInventoryItem (env.GetItemDefinition (ItemCategory.Torch), 3);
// Add a shovel (no need to specify quantity it's 1 unit)
VoxelPlayPlayer.instance.AddInventoryItem (env.GetItemDefinition ("Shovel"));
// Add a sword
VoxelPlayPlayer.instance.AddInventoryItem (env.GetItemDefinition ("Sword"));
}
Implement Own Inventory / UI
Voxel Play comes with a default UI which includes a debug window, a command console and inventory UI.
These components are part of the "Optional Game Features" that are included in Voxel Play for demonstration purposes (because the focus of Voxel Play is the generation, rendering and managing of the voxel world).

If you want to replace one of these components, please refer to this article for more information.
Note that the inventory and console UI are just a front-end for the Voxel Play C# API so you can completely rewrite them or use third-party assets if you wish.
Spawn Mobs Safely
When spawning a mob (or object) it's important to ensure the chunk under the mob is generated and rendered. Please note that if the chunk is generated but it's not rendered, the chunk collider nor the NavMesh won't be available therefore the mob could fall below the terrain.
The following code ensures the chunk is ready (collider and NavMesh is generated) before spawning a gameobject:
VoxelPlayEnvironment env = VoxelPlayEnvironment.instance; if (!env.initialized) return;
Vector3 position = new Vector3 (Random.value * 50 - 25, 51f, 70); StartCoroutine(Spawn(position));
...
IEnumerator Spawn(Vector3 position) {
VoxelChunk chunk = null;
while (chunk == null || !env.ChunkHasNavMeshReady (chunk)) {
env.GetChunk (position, out chunk, true);
yield return null;
}
// now it's safe to create the gameobject at position
...
}
If you're not using AI (NavMesh) and just want to check the chunk's collider is generated you can simply replace env.ChunkHasNavMeshRead(chunk) in the code above by chunk.isRendered.
Smaller Voxel Size
Voxel Play supports voxels of 1m in size for the world grid (ie. terrain generation and voxel address is based on the 1x1x1 scale). It uses many optimizations and occlusion algorithms to reduce vertex count, and this calculations assume voxels have a size of 1x1x1.
We think this base resolution is fine for most projects since using a smaller voxel size as the base resolution for the entire world would increase dramatically the memory requirements or would limit the world size.
However Voxel Play provides two main ways to use smaller voxels or custom shapes which are described:
- You can use custom voxel types of any shape for vegetation, trees, custom objects and items, etc. Anything that's thought as an individual element can be of any shape and size. Because custom voxel types use prefabs, you can use any geometry for these objects, and even you can have complex hierarchies or scripts in those prefabs. Check out the Custom Voxel Types page for more info.
- In Voxel Play 3 we introduced Microvoxels which allows you to define a custom mesh/shape for regular voxels. Check them in the documentation. Microvoxels can be up to 1/16th the default voxel size. When using microvoxels, the rendering voxel uses a different mesh, instead of the regular 1x1x1 cube mesh, but still occupies a 1x1x1 space.
If you really need smaller voxels in general for world or the terrain, an alternative is to make anything else bigger! Make your character/NPCs/items use a greater scale and adjust the camera distance appropriately. The effect, like in cinema, will be that terrain voxels look smaller.
URP Support
Voxel Play includes dedicated shaders for both the built-in pipeline and URP (Universal Render Pipeline). The system automatically detects which pipeline is in use and applies the necessary adjustments when the scene loads - no manual configuration needed.
Make sure you have a proper URP asset assigned in Project Settings / Graphics with "Depth Texture" enabled for proper water rendering.
If you have any question regarding URP or general pipeline setup, feel free to contact us on Discord.
Custom Water Shaders
Voxel Play includes its own water rendering system integrated into the terrain shader. You cannot directly replace it with a third-party water asset like Stylized Water.
However, you can place a third-party water asset as an independent GameObject in the scene (e.g. a water plane at your desired water level). Keep in mind that this water object will be completely independent from Voxel Play - it won't interact with voxel destruction, raycasting, or any other VP system. It's purely a visual addition.
If you just want to customize the water appearance, check the Realistic Water settings in your World Definition where you can adjust colors, transparency, and other visual properties.
Custom Voxel Drops (Loot)
When a voxel is destroyed, you can make it drop a different voxel or item. There are two approaches:
Inspector (no code): Open your VoxelDefinition asset and set the dropItem field to the ItemDefinition you want to drop. You can also configure dropProbability (0-1), dropItemScale, and dropItemLifeTime.
Via code: Subscribe to the OnVoxelDestroyed event and use CreateRecoverableVoxel() to spawn a collectible voxel at the destroyed position:
env.OnVoxelDestroyed += (chunk, voxelIndex) => {
VoxelDefinition droppedVoxel = cobblestoneVd;
Vector3d pos = env.GetVoxelPosition(chunk, voxelIndex);
env.CreateRecoverableVoxel(pos, droppedVoxel, Misc.color32White);
};
You can also use VoxelThrow() to launch the dropped voxel in a direction with physics, or ItemSpawn() to spawn an item by name.
Related events: OnVoxelBeforeDropItem (allows cancellation) and OnVoxelAfterDropItem (gives you the spawned GameObject).
Water Not Transparent in URP
In URP (Universal Rendering Pipeline), the following settings must be used in order to the water to be transparent:
1) In URP asset, enable the Depth Texture and Opaque Texture settings.
2) In Voxel Play Environment, disable "Shadows on Water".
3) In World Definition, under the Realistic Water section, modify the alpha values of Water and Underwater Fog colors to make the water more or less transparent.
Avoid Character Fall Below Terrain
There're a few situations where your character or some other mob fall under the terrain:
1) Voxel Play environment has not finished creating the initial terrain.
Solution: wait until Voxel Play finish initialization using the event OnInitialized or check the flag env.initialized.
2) The chunk below the mob is not yet rendered (collider is missing).
Solution: check if the chunk is ready at the mob position with GetChunk(position) method.
3) Mob still fall under terrain sometimes:
Solution: add Voxel Play Behavior component to your mob and enable the option "forceUnstuck". It's also recommended to enable the "Check Chunk Area" option.
How to Hide Voxels
Voxels can be hidden using the VoxelSetHidden methods. Use VoxelIsHidden to determine voxel visibility (check API section for full list of public methods).
Hiding voxels is useful when you need the player to see through certain voxel layers or areas. In fact, the see-through system included in Voxel Play makes use internally of these methods.
The code below will hide voxels around player camera when pressing T and returned to normal when pressing Y.
Note that voxels are not removed, they simply are not rendered (colliders and navmesh data is not affected).
using System.Collections.Generic;
using UnityEngine;
using VoxelPlay;
public class HideVoxels : MonoBehaviour
{
VoxelPlayEnvironment env;
List<VoxelIndex> indices = new List<VoxelIndex> ();
void Start()
{
env = VoxelPlayEnvironment.instance;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.T)) {
Vector3 min = Camera.main.transform.position - new Vector3 (50, 0, 50);
Vector3 max = Camera.main.transform.position + new Vector3 (50, 20, 50);
env.GetVoxelIndices (min, max, indices);
env.VoxelSetHidden (indices, true);
}
if (Input.GetKeyDown (KeyCode.Y)) {
Vector3 min = Camera.main.transform.position - new Vector3 (50, 0, 50);
Vector3 max = Camera.main.transform.position + new Vector3 (50, 20, 50);
env.GetVoxelIndices (min, max, indices);
env.VoxelSetHidden (indices, false);
}
}
}
Integration with Highlight Plus
It's possible to use Highlight Plus to replace the default highlighter included in Voxel Play.
To do so, follow these steps:
1.- Download and import Highlight Plus from the Asset Store.
2.- Locate and double click the "VoxelHighlight" script to open it (use the Search box in Project Panel to locate the script):

3.- Uncomment the first line to enable the integration and save the changes:

4.- Now, Voxel Play will use Highlight Plus as highlighting system.
5.- You can customize the highlight effect as well using a Highlight Plus Profile. Locate the VoxelHighlightEdges prefab, open it and notice there's a Highlight Profile field in the Voxel Highlight component. Assign your profile to this field and save the changes to the prefab.

How Chunks Load
A chunk is loaded by Voxel Play when:
- Any API tries to access its contents, for example:
(position).GetVoxelIndex - When the chunk boundaries are within camera frustum (based on Chunk Visible Distance option in Voxel Play inspector).
- When the chunk is near the player (based on Force Chunk Distance value in Voxel Play inspector)
- When some observer requires it. An observer can be any gameobject that has the Voxel Play Behavior script attached. Mobs should have a Voxel Play Behavior script attached to ensure the immediate terrain around them is created.
Once a chunk is required, Voxel Play will invoke the terrain generator if it's new. If the chunk contents are ready but the mesh data is pending, it will add the chunk to the meshing queue and finally it will update its representation in the scene. Check the chunk lifecycle for more details.
Exclusive Control of Input
Just call:
VoxelPlayEnvironment.instance.input.enabled = false
to stop any input from being recorded by Voxel Play input controllers. This useful to get control of mouse, keyboard or touches when displaying a pause or menu interface.
Render Chunk Regardless of Distance
Voxel Play separates chunk generation from rendering so when you call:
VoxelChunk chunk = env.GetChunk (position, forceCreation: true);
It will generate the chunk at that position. However, it's not guaranteed that the chunk will be rendered unless it gets within the visible distance or camera frustum (parameters that can be configured in the Voxel Play Environment).
Now, let's assume that for any reason we want to generate a remote chunk but also want to render it (make it visible).
In this case, add ths following code to force its rendering:
chunk.ignoreFrustum = true; env.ChunkCheckArea (position, Vector3.zero, renderChunks: true);
Regular Lights in Voxel Play
Voxel Play renders lights in different ways.
Custom Point Light rendering
Use the "Bright Point Lights" in the Voxel Play Environment to render point lights in the voxel world. In built-in pipeline, Voxel Play is limited to point lights using this option (with no shadows). For URP, read the section dedicated to URP below.
When this option is enabled, Voxel Play shaders support up to 32 simultaneous point lights in a single pass. The Voxel Play Light Manager script attached to the camera is responsible for keeping the internal buffer of light data updated as the character moves around, picking the 32 nearest point lights to the camera while also feeding shaders with data as light color, intensity and range.
Voxel shaders are compatible with this kind of light rendering. If you want to get this light applied to your character models, make sure you use one of the factory Voxel Play materials.
To avoid checking for new lights continuously, attach the script VoxelPlayLight to the point light gameobject. This script takes care of registering/unregistering the light with Voxel Play automatically.
Each point light can have a different color, range and intensity of course. However, there're two global settings that can modify how point lights look in the scene. These settings can be found in your World Definition:

The Light Scattering is a multiplier to the point light range.
The LIght Intensity Multiplier affects the point light intensity.
If you want point lights to look like in regular Unity scenes, make sure both values are set to 1.
Note that in Voxel Play there's also voxel global illumination (also called smooth lighting) which means light spreads across empty spaces in the voxel world. For example, when you place a torch it has both a point light and also emits voxel light. To avoid burning effect (too much light due to both light contributions), Voxel Play uses a very short Light Scattering value so the point light only is visible at the point light position while the rest of the area is illuminated by the voxel light spread. This provides the best look since the voxel lighting can bounce around corners while point lights not.
Increasing the maximum number of active point lights
If you need to use more than 32 point lights active in the scene, you can increase this number by modifying the limits defined in VoxelPlayLightManager.cs script and VPCommonOptions.cginc shader file.
Virtual Point Lights
You can also add the VoxelPlayLight component to an empty gameobject and enable the checkbox "Virtual Light". This will add a light with the desired color, intensity and range even if there's no light component attached. This option is more performant than adding a real point light to the scene, however, it will only illuminate objects that use Voxel Play shaders.
As you can see, this feature is just an extension to the existing point light support but that doesn't require a Light component since properties like light color, intensity or range are provided by the user.
Universal Rendering Pipeline native light support
In URP and if "Bright Point Lights" and "Enable URP Native Lights" options are selected in the VoxelPlay Environment inspector, Voxel Play will render point lights and spot lights as you would expect, including shadows.
Make sure that the URP asset used in Project Settings / Graphics or Project Settings / Quality has the "Additional Lights" set to "Per Pixel" and also enable the shadows option there.
In this case, limitations and options related to URP lighting applies, including the maximum 8 lights per object (as of URP 12 or below). This means that you can't have more than 8 lights illuminating the same chunk.
Also, no additional setup is required. This means that when this mode is used, you don't need to add a VoxelPlayLight script to your lights.
Note: URP native lights require Voxel Play 2 (v10.0 or later).
Get Custom Voxel GameObject Ref
Use the following code to get a reference to the instantiated gameobject:
GameObject voxelGameObject = env.GetVoxelGameObject(position);
An instantiated gameobject is a regular gameobject created by Voxel Play based on the custom voxel definition.
Notes:
1) If the custom voxel definition has GPU Instancing enabled, there's no gameobject in the scene (unless it's marked to be created explicitly in the voxel definition).
2) To change the material of this gameobject, just use GetComponentInChildren<Renderer>() on the returned gameobject and use the .material property to ensure you only modify a self copy of the material used by all instances of this same voxel definition in the scene.
Show the Cursor
Sometimes you want to show the cursor and pause the camera control in Voxel Play (so user can use some in-game menu or execute a drag&drop operation in inventory, etc.).
You can use the following code:
Cursor.visible = true; Cursor.lockState = CursorLockMode.None; env.input.enabled = false; // pause camera control
(where "env" is just VoxelPlayEnvironment.instance).
Avoid Random Spawn Position
Select your character controller and expand the Voxel Play First Person Controller script.
Disable the "Start On Flat" option:

The Start On Flat option will sample the terrain at random positions (in this case, 10 samples) and will use the position with lower height for the starting position of the character.
Get Neighbor of a Voxel
Using the API, call this method:
public bool GetVoxelIndex (VoxelChunk chunk, int voxelIndex, int offsetX, int offsetY, int offsetZ, out VoxelChunk otherChunk, out int otherVoxelIndex, bool createChunkIfNotExists = false)
For example, to get the right neighbor of a voxel, pass the chunk and voxelIndex value of that voxel and offsetX = 1. The method will provide the chunk and voxelIndex of the neighbor voxel in otherChunk and otherVoxelIndex return parameters.
Use "createChunkIfNotExists" to force the creation of a chunk if it doesn't exist at the time of calling this method.
Using Shader Graph
You can use Shader Graph to create your own overriding materials in Voxel Play.
Please check "Override Materials" feature for more details about how to use your own shaders with the render types included with Voxel Play (like Opaque-3 textures, CutOut, etc.)
UV coordinates
When using greedy meshing, UV coordinates can exceed the usual 0..1 range. For this reason, make sure the texture assigned to the material has the tiling set to Repeat and not Clamp.
Normal Maps
It's important to know that cube geometry generated by Voxel Play doesn't include tangents. This means that normals must be provided in world space:
In the Graph Inspector, set Fragment Normal Space to World. Then, use the Normal Unpack node to decompress your normal map texture as shown in the screenshot below:

Now, assuming that your voxel definition has the correct setup to override the default material ...

... you should see your shader graph material in the generated voxels:

Forward+ Support in URP
Unity 2022 (URP 14) includes forward+ which allows you to render more than 8 lights per pixel.
To enable this feature, check:
- The URP Universal Renderer must be set to "Forward+".
- In Voxel Play Environment, the options "Enable URP Support", "Enable Bright Point Lights" and "Enable URP Native Lights" must be selected.
Now, you can place as many lights (and of any type) in the voxel world. Voxel Play 2 will render them as expected.
Modify Shaders for Custom Effects
Note: this is an advanced topic. It assumes you have a deep understanding of shaders.
Voxel Play shaders are a collection of custom, hand-made, optimized shaders able to render lot of visual features in the most performant way. To make it easier to read, each Voxel Play shader makes use of macros which encapsulate the shader code involved.
To customize or add effects to the opaque voxel shaders, you can edit the VPVoxelTriangleOpaquePass.cginc file. This file contains both the vertex and fragment shaders. The fragment shader looks like this:
fixed4 frag (v2f i) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
VOXELPLAY_COMPUTE_SCREEN_UV(i);
VOXELPLAY_APPLY_PARALLAX(i);
VOXELPLAY_COMPUTE_BEVEL(i);
// Diffuse
fixed4 color = VOXELPLAY_GET_TEXEL_DD(i.uv.xyz);
#if defined(VP_CUTOUT)
clip(color.a - _CutOff);
#endif
VOXELPLAY_APPLY_BEVEL(i);
VOXELPLAY_APPLY_FRESNEL(color, i.norm, i.wpos);
VOXELPLAY_COMPUTE_EMISSION(color)
VOXELPLAY_APPLY_BUMPMAP(i);
VOXELPLAY_APPLY_TINTCOLOR(color, i);
VOXELPLAY_APPLY_OUTLINE_SIMPLE(color, i);
VOXELPLAY_APPLY_SPECULAR(color, i.norm, i.wpos);
#if defined(IS_CLOUD)
VOXELPLAY_APPLY_LIGHTING(color, i);
#else
VOXELPLAY_APPLY_LIGHTING_AO_AND_GI(color, i);
#endif
VOXELPLAY_ADD_EMISSION(color)
VOXELPLAY_APPLY_FOG(color, i);
return color;
}
You can insert any code in-between any of these macros to change the color value.
The i.wpos contains the world space position of the "pixel" while the i.norm contains the normal in world space as well.
How Lighting Works
Voxel Play handles two kind of lighting systems:
- Voxel lighting
- Unity lighting
Voxel lighting is baked in runtime into the chunk structure per voxel. This voxel lighting represent the Sun light and also any emissive voxels or torches.
On the other hand, Unity lighting refers to the usual directional, point and spot lights.
Voxel Lighting
Voxel light propagation is handled in two distinct passes: one for Sun lighting and another for emissive lighting, such as that from torches. If no emissive sources (like torches) are present, no emissive lighting propagation occurs.
Lighting values are stored per voxel using a single byte. The upper four bits represent the emissive lighting intensity, while the lower four bits represent the Sun lighting intensity. Both intensities range from 0 to 15, where 0 indicates no lighting, and 15 indicates full lighting.
The Sun lighting value represents the maximum intensity of sunlight a voxel receives. This value is combined with the Sun's altitude in the sky—where 1 corresponds to the Sun directly overhead, and 0 corresponds to the Sun at the horizon or below—to determine the final light intensity applied to the voxel's color.
Sun lighting propagates using a breadth-first search (BFS) algorithm, spreading light from one voxel to its neighbors. For chunks below the terrain surface, the sunlight intensity decreases by 1 (or by an amount specified in the world settings) with each step. This models the concept that sunlight above the terrain is "infinite," while its intensity diminishes underground.
Emissive lighting propagates in a similar manner but always decreases by 1 per step, regardless of the chunk's altitude. This reflects the finite nature of emissive lighting sources, such as torches.
When a chunk is modified (ie. a voxel is destroyed), the lighting for the affected chunks is recalculated. Otherwise, the lighting data doesn't change, even if the Sun rotates since the altitude of the Sun in the sky is used to calculate the final lighting in the shader itself.
The Ambient Occlusion (Obscurance) option in Voxel Play is computed per-voxel during mesh generation and baked into vertex colors, then combined with the stored voxel light data. This makes it very lightweight compared to screen-space AO (SSAO). It requires Smooth Lighting to be enabled. You can control the AO style via the Obscurance Mode setting in the Environment inspector: Faster (default, subtle), Custom (adjustable intensity via slider, 0-3), or Lineal (raw values). To increase the AO effect, switch to Custom mode and raise the Intensity. Per-voxel control is also available through Voxel Definition render types (Opaque No AO disables it) and per-face Occlusion Strength multipliers.
Unity Lighting
Check this other article to learn more about how Voxel Play handles normal Unity lights, such as point lights.
Disabling Crosshair
To disable the crosshair of the first person controller you can do it in the First Person Controller inspector (Crosshair section or using scripting:
VoxelPlayFirstPersonController firstPersonController = VoxelPlayFirstPersonController.instance; firstPersonController.enableCrosshair = false;
Does the Pirates of Voxel Play asset include player data persistence for inventories and game state?
Pirates of Voxel Play does not include saving game state or inventory data because it is designed as a battle royale game with one-shot sessions that are not persisted between play sessions.
How does the bevel modifier work in Voxel Play 3, and what visual effect should it produce?
The bevel modifier in VP3 is a subtle effect that smooths borders through shadow and normal adjustments rather than changing the actual geometry. The effect depends on lighting and may not be immediately obvious. For more pronounced rounded edges, use custom voxels with connected voxel rules instead.
How can I fix shadow artifacts (black stripes) appearing on voxel edges?
This is a rasterization artifact inherent to how shadows are rendered in Unity. Adjusting Depth Bias and Normal Bias in shadow settings can move the artifact but may not completely eliminate it. The artifact appears regardless of render pipeline (Built-in or URP) and shadow configuration. Raytracing is a potential alternative to avoid this limitation entirely.
Why is the Voxel Play terrain not affected by fog, and how can it be fixed?
Voxel Play shaders do not use Unity's default fog system because it doesn't affect the skybox and produces poor visual results. Instead, VP uses its own fog system that blends correctly with the VP skybox. If you need additional fog effects, you can use post-processing based solutions like Dynamic Fog & Mist or Volumetric Fog & Mist assets.
Does the OnVoxelBeforePlace event fire during world generation or only when a player manually places a voxel?
OnVoxelBeforePlace only fires when a player places a voxel, not during world generation. Calling an event per generated voxel during terrain generation is not viable because Voxel Play generates millions of voxels.
What is the recommended way to change voxel color within the OnVoxelBeforePlace event?
Use the ref tintColor parameter directly instead of calling VoxelSetColor from the event, as this is more efficient.
Does the Decal renderer feature in URP work with voxel-play?
The Decal renderer feature causes visual glitches (blue glitch) on trees in voxel-play, so it cannot be used together with the asset.
How can I create a fake cube representation of a destroyed voxel using a normal cube with the same texture?
Use the VoxelGetDynamic method, which converts a voxel into a regular gameobject that can be used as a replacement representation.
How are regular voxels rendered in Voxel Play - are they individual GameObjects or optimized meshes?
Regular voxels (anything except custom voxels) are meshed into the same chunk sharing materials. There are no individual voxels as separate GameObjects in the scene - only optimized meshes within chunks. Chunks themselves are GameObjects but only serve to hold the meshes and renderers. There is no per-voxel layering since voxels are not distinguished as individual GameObjects.
When using Biome vegetation or tree generation to spawn custom Prefab voxel Definitions, will the VoxelDamage() method work on these prefabs?
VoxelDamage should work on custom prefab voxel definitions spawned through Biome vegetation or tree generation. However, you must pass the exact position where the custom voxel was spawned, regardless of the prefab size. The RayHit method should also work for this purpose.
How does the IgnorePlayer collider type work in RayCast() - does it use a layer mask?
IgnorePlayer is a bitwise mask option that compares the hit gameobject with the VP character controller and ignores any hits that touch the player gameobject. If you're using a custom character controller instead of VP's built-in one, use the layerMask parameter instead, which allows you to specify which layers to ignore.
How can I prevent raycasts from being obstructed by a custom character controller collider?
Use the layerMask parameter in the RayCast() function to ignore the layer(s) that your custom character controller uses. The IgnorePlayer option only works with VP's built-in character controller.
How do I fix the 'Index was outside the bounds of the array' error in NoiseTools.GetNoiseValueBilinear when generating chunks with a custom heightmap texture?
Ensure the heightmap texture has sRGB disabled in its import settings. Untick the sRGB option in the texture's properties to resolve the index out of bounds error that occurs when new chunks load.
How do the top, middle, and bottom slices work in connected voxels for custom prefabs?
The slices work like a Rubik's cube - each entry corresponds to a position in a 3x3x3 array centered on a given voxel. The action defined for each entry specifies what to do when the neighbors of a voxel match that rule.
How can I get the terrain size via script in Voxel Play?
Use VoxelPlayEnvironment.instance.world.extents to access the terrain dimensions.
Why is Voxel Play causing garbage collection lag during gameplay?
VP only issues GC.Collect when loading or disposing the world, not during gameplay. If you experience GC lag, check if you have custom voxels with the 'Create GameObject' option enabled, as this can cause additional garbage collection.
Does Voxel Play 2 include a sword weapon system that can be swung and used in combat?
Voxel Play 2 does not include a weapon or combat system. The asset focuses on the voxel engine. The sword included is an example of the voxelizer tool, which demonstrates how to create 3D objects from textures. Other systems like inventory and UI are provided as examples of how to use the API, but you can modify, replace, or implement your own systems.
Can Compass Navigator Pro 2 and Terrain Grid System 2 be used with Voxel Play 2?
Compass Navigator Pro 2 is compatible with Voxel Play 2. Terrain Grid System 2 might not work well due to the cubic world shapes and holes inherent to voxel-based terrain.
How can I disable voxel lighting to improve performance and use Unity's default lighting instead?
You can disable Global Illumination in the Voxel Play Environment inspector. This will disable Voxel Play's lighting system and allow you to use Unity's default lighting.
Why is chunk mesh generation happening on the main thread instead of using multithreading?
If the Multithreading option is disabled in settings, the asset will use GenerateChunkMeshDataInMainThread, which processes all voxel mesh generation on a single thread. Enable the Multithreading option to distribute this work across multiple threads for better performance.
Does Voxel Play 2 apply ambient occlusion (AO) to both models and terrain?
The integrated AO in Voxel Play 2 only applies to voxels/terrain, not to models. To apply AO to models, you need to use other options (refer to available video documentation for alternatives). For terrain AO, set Obscurance Mode to custom and adjust the slider.
How can I set up Voxel Play with just a camera without automatically adding player controllers?
Use the first Voxel Play scene setup shortcut, which doesn't add any default controllers. Alternatively, if you've already added the Voxel Play Environment, you can remove the input controllers from the Voxel Play Environment inspector settings.
How do I disable the sun in the voxel-play environment when setting it to 'None' still shows warnings and the sun appears in the sky?
Change the Skybox setting to 'User Defined' in the World Definition and add your own custom skybox instead of trying to set the Sun to None.
Why aren't caves spawning in the first chunks that are loaded?
By default, the cave generator only operates on unmodified chunks. If chunks are already stored in the savegame file, the cave generator will not generate caves in them. Ensure chunks are not being pre-saved before cave generation should occur.
Where is the UI prefab for Android mobile controls located in Voxel Play?
The documentation references VoxelPlay/Resources/VoxelPlay/Defaults/UI, but this folder may not exist in all versions. The mobile UI elements are part of the Voxel Play UI Canvas prefab. The first person controller example in demo scene 1 demonstrates mobile controls with touch/drag input on the left and right sides of the screen for rotation and movement. Note that third person controllers are not designed for mobile. These controllers are provided as examples and can be modified or replaced with your own systems.
How does greedy meshing work with microvoxels in Voxel Play?
Microvoxels greedy meshing is performed per voxel, allowing them to be used as a foundation for replacing custom non-voxel items like chairs and tables.
The terrain raise/lower tool in the world editor doesn't work and the grid is not visible in the scene view. How do I fix this?
Enable gizmos in the scene view. The grid and terrain editing tools require gizmos to be visible and functional.
How should custom 3D models from asset packs like Synty be integrated into Voxel Play terrain generation, and why are they sometimes floating, overlapping, or misaligned with the ground?
Custom 3D models should be added as vegetation rather than using Tree Definitions (which are designed for voxel-based trees). Create a custom voxel definition with size x,y,z set to 1 (since the model occupies only 1 voxel space), then add it as vegetation to the biome. This allows the terrain generator to place the model correctly without floating or overlapping issues. Alternatively, if using a voxel definition approach, ensure the size is set to 1,1,1 to account for the fact that even-sized grids (like 16x16x16) have offset centers that affect placement calculations.
How can I make a character model receive dynamic lighting from the voxel terrain based on its position?
Add the Voxel Play Behaviour component to the character gameobject. This component will automatically match the surrounding voxel lighting to the character's location.
How can I get a reference to a group of voxels in a model definition when a script is attached to a single voxel?
Voxel Play uses a high-performance design where all voxel definitions are converted into optimized meshes rather than individual scene objects. To access voxel group information, use events instead. There is an event triggered when a model is placed that provides the model and position references, which gives you access to the voxel data (bytes) you need to work with the entire group.
Why can't I add scripts directly to individual voxels like I would with regular GameObjects?
Voxel Play follows a high-performance design philosophy. All voxel definitions are converted into optimized meshes rather than individual GameObjects in the scene. This allows the engine to handle millions of voxels efficiently. If you need custom functionality, use the event system (triggered when models are placed) rather than individual voxel scripts.
Why doesn't RayCast with ColliderTypes.OnlyVoxels hit custom prefab voxels?
Custom voxels occupy an entry in the chunk.voxels array but are not physical by default since they represent prefabs. The prefab itself must carry the collider. ColliderTypes.OnlyVoxels only hits if the cubic voxel position is filled, which doesn't work properly with custom shaped objects. Use ColliderTypes.AnyCollider instead for custom voxels with colliders.
In server mode, are custom voxels instantiated as GameObjects, or does the server skip all instantiation for performance?
In server mode, custom voxels are still instantiated as GameObjects. The only thing that gets removed when server mode is enabled is the mesh rendering of chunks. Colliders and navmesh are also still generated.
How do custom voxel materials handle daylight shadow attenuation compared to regular voxels?
Custom voxels use a prefab with a material that has its own independent Daylight Shadow Atten setting, not synced with the global setting. This allows finer customization of item appearance. If you change the global Daylight Shadow Atten value, you must also change the prefab material value to ensure custom voxels and regular voxels are affected by shadows consistently.
How do I set up the input controller for Voxel Play if the automatic setup doesn't work?
Manually drag and drop the 'Voxel Play PC Input Controller' prefab into the 'Input Prefab (PC)' property on the 'Voxel Play Environment' gameObject in the Default Assets section. This should normally happen automatically during setup, but if it doesn't, this manual assignment will resolve the issue.
Does the OnVoxelAfterPlace event fire when voxels are instantiated from a save game file, or only when placing new voxels via API?
OnVoxelAfterPlace only fires when using the API to place voxels. There are no individual voxel events triggered when loading a savegame file. However, chunk events (OnChunkAfterCreate, OnChunkAfterFirstRender, etc.) are triggered when loading, and only modified chunks are stored in savegame files.
What is the best approach to detect and handle voxels with custom data when they become active in the game world as the player moves around?
Use the OnChunkAfterFirstRender event to iterate through voxels in chunks as they are rendered. This event triggers when a chunk is first rendered. Alternatively, use custom voxel prefabs with scripts attached - the script's Start() method will execute once when the voxel is rendered, which is more efficient than iterating through all voxels in a chunk.
How should scripts be attached to voxels to execute custom logic when they are instantiated?
Scripts must be attached to custom voxel prefabs. Regular voxels don't exist as individual objects, so you cannot add components to them directly. You must create a custom voxel definition with a prefab that has the script attached. Custom voxels can still store properties using the property system.
Why might voxel property data not be available in a custom voxel's Start() method, even though it exists when checked later?
Voxel Play may not have finished initialization when Start() is called. Wait for the OnInitialized event before accessing voxel properties. This ensures the environment is fully initialized and all voxel data is properly loaded before attempting to retrieve property strings.
Why would GetVoxelIndex(hitInfo.voxelCenter) return a different result than hitInfo.voxelIndex?
When a ray hits a custom voxel, hitInfo.voxelIndex returns the index of that voxel entry in the chunk.voxels array, while hitInfo.voxelCenter is the world position of the prefab. If the prefab size differs from a standard cube, the voxel center can be positioned outside the natural voxel grid position, causing GetVoxelIndex(voxelCenter) to return a different index.
How do I spawn models like trees at a specific height using a detail generator?
The detail generator AddDetail method receives the chunk object. Use chunk.position, which contains the world space position of the chunk, as a reference to decide where to place trees at your desired height.
How do I fix the error where Unity can't access the selection box in the Model Capture tool?
Click 'Remove Grid', switch to a different tool, then select the Model Capture tool again. This will recreate the selection box.
How is the voxel array in a chunk constructed - what is the index order (X, Y, Z)?
The array is indexed as Y/Z/X, so the formula is: index = Y * (16 * 16) + Z * 16 + X
How do I get the world position of a chunk to calculate block coordinates?
Use chunk.position to get the chunk's center position in world space. You can then offset by CHUNK_HALF_SIZE to get the corner position and calculate individual block world coordinates from there.
How can I generate smoother terrain with microvoxels like stairs or half slabs instead of full voxels?
There are two approaches: (a) Have the terrain generator place appropriate voxels based on the shape at each position, or (b) Use connected voxels rules to replace terrain edge voxels with other voxel definitions that use micro-voxels. For example, if the terrain fractional height is between 0 and 0.5, use a voxel definition with micro-voxels filling only the bottom half (like 'forestHalf') instead of a full voxel ('forestFull').
How can I add randomness to voxel definitions, such as placing trees with leaves in different positions?
You can add multiple tree definitions to the biomes and set probability weights for each. The system will randomly select and place these different tree variants based on the seed.
Is it better to use separate textures for each voxel definition or a single texture atlas with texture arrays?
Using texture arrays is the better approach for performance. Voxel Play internally converts all textures into texture arrays regardless of input method, so organizing your workflow around texture arrays is more efficient than managing many separate texture files.
Why do voxels with high metallic and smoothness values appear almost black in Unity 6 with URP Forward+, even though probe-based reflections should work with the new PBR support?
Increase the Ambient Light slider in the Voxel Play Environment inspector under Shader Features. This controls the ambient contribution to reflections on voxels.
How should voxel definition files be organized in the project folder structure?
Voxel definitions must be placed in a folder with the same name as your world asset. For example, if your world asset is named 'NewWorld' and is located under Resources/Worlds, create a folder named 'NewWorld' and place all voxel definitions there. The default voxel will only appear if the voxel definition is missing or not registered.
How do I adjust the far camera clip distance for chunk rendering in Voxel Play?
Check the Voxel Play Environment inspector under Voxel Generation section. There's an option to adjust far camera clip automatically based on the chunk distance.
Is it possible to use smooth voxels on the edge of terrain in Voxel Play, similar to rounded edge tiles created with rule tiles?
Voxel Play does not support smooth terrains like marching cubes. However, some users have achieved rounded edges by using connected voxels with custom voxels and prefabs.
How can I combine multiple voxel rigid bodies that break off (like from felled trees) so they fall together as a single body instead of individually?
You need to introduce runtime mesh combining to your scene. You can use a free Mesh Combiner asset from the Unity Asset Store (or create your own script). After combining the target voxel blocks, add a RigidBody component to the final GameObject and configure it with your desired gravity, mass, and other physics settings.
How can I raycast against only opaque voxels, allowing raycasts to pass through transparent voxels like glass while still detecting solid blocks?
Use the optional minOpaque parameter in the raycast method and set it to FULL_OPAQUE or 15. This will filter raycasts to only hit fully opaque voxels while allowing them to pass through transparent or semi-transparent voxels.
Why does the isAboveSurface flag produce inconsistent lighting results when destroying terrain smaller than a chunk size?
The isAboveSurface flag operates on a chunk-by-chunk basis, so small grooves or destroyed areas smaller than a chunk size may not trigger the flag update. Additionally, changing the flag requires recomputing the lightmap on neighboring chunks due to Sun light propagating across chunk boundaries.
How can I make a custom character controller interact with water voxels, such as taking damage or being slowed down?
Use env.GetVoxelUnder(position) to detect the voxel under your character's position, then check its type and implement your own logic based on the voxel properties. The built-in Trigger Enter Event and Walk Event only work with the default character controllers.
How do I access the player damage value from a voxel definition in my custom character controller?
Get the voxel using env.GetVoxelUnder(position, includeWater: true), then access the damage value with voxel.type.playerDamage. You can then use this value in your own damage logic.
How can I place the Voxel Play Character Controller at a custom starting position instead of on flat ground?
Disable the 'Start on flat' setting in the Character Controller inspector. This allows you to place the character anywhere. To find suitable cave positions, you can start the scene to let caves/tunnels generate, then use the Default Cave Generator code to identify coordinates for your desired starting position.
What is the best approach for generating caves in a flat voxel world with multiple layers and biomes for a top-down game?
Use a custom detail generator script similar to the Cave Default Generator provided with Voxel Play. The detail generator receives the position being generated, allowing you to identify the biome at that location and place cave models accordingly. This approach allows models to override existing voxels and be spawned conditionally based on biome and height. See the detail generators documentation for implementation details.
Is there a performance impact when using tree models from the HQForest sample world in Voxel Play?
There is no performance hit. Model definitions like trees, once placed, become part of the voxel world, and you can place as many as needed without performance degradation.
How can I build terrain with custom voxel types instead of being limited to the biome's default voxelTop/voxelDirt?
Use these workarounds: (1) Floor (Struct) or Box selection + Fill (Sculpt) - select your voxel type, then place/fill at the desired Y level, building bottom-up so each layer uses the correct type. (2) Paint (Sculpt) tool - set the Voxel Definition and Brush Size (up to 32), then paint over existing terrain to control where rock vs dirt goes without relying on biome/height rules.
How do I create caves without exposing bedrock on the interior faces?
Use the Remove tool to carve out the cave shape, then use the Paint tool (or Build) to paint the visible interior faces with stone or dirt voxels to cover the bedrock.
How to improve world loading/initialization performance?
On PC, the engine creates 2000 mesh jobs split across your CPU threads (cores - 1) at startup. Each job pre-allocates several large Lists (vertices, uvs, normals, colors at 15,000 capacity each). To reduce this startup spike:
- Enable Low Memory Mode in the VoxelPlay Environment inspector. This changes all those 15,000-capacity lists to start at capacity 4, cutting initial allocation dramatically. They grow on demand during gameplay instead.
- Disable Enable Colliders if your game doesn't need physics collision with voxels. Each mesh job also allocates collider vertex/index buffers which add up across 2000 jobs.
- Lower Visible Chunks Distance (default 10). This controls how many chunks render and directly affects the chunk pool size.
- Lower Max Chunks (default 16,000) to match your actual needs. Each chunk pre-allocates a 32x32x32 voxel array.
- Reduce Force Chunk Distance (default 3, range 1-8). This is how far chunks must fully render before the game starts - lowering it lets the game start sooner.
- Enable Delayed Initialization if you have a loading screen. This lets you call Init() manually after the loading UI is visible, so the player sees progress instead of a freeze.
Suggest an improvement
Help us improve this documentation page.