Super Chunks API
advanced scriptingVoxel Play 4 · Scripting / API
By default, Super Chunks read the distant terrain from the 3D Terrain Graph generator. If your world comes from your own data, for example a pre-baked map or terrain loaded from files, you can provide your own sampler so the distant terrain shows your data instead. This also works when the world has no terrain generator.
Assigning a Sampler
Assign a function to superChunkSamplerFactory on the Voxel Play Environment. The function receives the environment and returns a new object that implements ISuperChunkSampler:
env.superChunkSamplerFactory = e => new MySampler(myData);
Super Chunks are built on several background threads and the factory is called once for each thread, so it should return a new sampler every time. Assign it from the main thread. You can assign it at any time, and the distant terrain restarts with the new sampler on the next frame. Set it to null to go back to the built-in 3D Terrain Graph sampler.
The ISuperChunkSampler Interface
| Method | Description |
|---|---|
int SampleColumn (double x, double z, ColumnInterval[] intervals, out double waterY, out ushort waterTypeIndex) | Fills the solid intervals of the column at world position x, z from top to bottom and returns how many it wrote. It also returns the water level and the water voxel of the column. Return a waterTypeIndex of 0 when the column has no water. |
bool TryGetTree (double x, double z, double groundY, out SuperChunkTreeCandidate tree) | Returns the tree that grows on the ground of the column, if any. groundY is the top of the first interval. Return false if you do not need distant trees. |
Columns are sampled every few voxels depending on the Super Chunks Quality, so the distant terrain is a coarse version of your data.
Column Intervals
Each ColumnInterval is a solid part of the column. A column with flat ground needs one interval, while a column with an overhang or a floating island needs one interval for each solid part, ordered from the highest to the lowest.
| Field | Description |
|---|---|
yTop | Top of the solid part, in world units. |
yBottom | Bottom of the solid part, in world units. |
topTypeIndex | Voxel used for the top face. |
sideTypeIndex | Voxel used for the walls. 0 uses the top voxel. |
bottomTypeIndex | Voxel used for the bottom face. |
The voxel values are the index of voxel definitions registered in the environment, for example env.GetVoxelDefinition("VoxelGrass").index.
When the column has water, the intervals whose top is at or above the water level are drawn as land and the rest are drawn as seafloor under the water. The water surface is only drawn on columns that have no land. The intervals array has room for 16 entries, and the distant terrain keeps up to 8 land intervals and 8 seafloor intervals per column.
Distant Trees
When Include Trees and Enable Trees are on, TryGetTree is called for columns that have land. Fill the SuperChunkTreeCandidate with the position where the tree stands on the ground, the tree model definition and a rotation from 0 to 3 in quarter turns.
Rules
SampleColumnandTryGetTreerun on background threads, so they should only read data that is safe to access from other threads and should not call the Unity API. Copy what you need, such as the heights of a texture, into regular arrays on the main thread before assigning the factory.- Keep your terrain between the
minHeightandmaxHeightof the world's terrain generator, which is -255 to 255 when no generator is assigned. The distant terrain uses this range to refresh after voxel edits, and it does not draw the bottom face of intervals that reachminHeight. - When a voxel changes, the Super Chunks over that chunk are rebuilt with the data your sampler returns, so you should also update your data if you want edits to stay visible once the player moves away.
Example
This script shows a baked heightmap in the distant terrain. The texture must be readable, and each pixel is one voxel starting at world position 0, 0.
using UnityEngine;
using VoxelPlay;
// Shows a baked heightmap in the distant terrain
public class BakedDistantTerrain : MonoBehaviour {
public Texture2D heightmap;
public float maxTerrainHeight = 100;
public float waterLevel = 20;
public VoxelDefinition grass, dirt, water;
void Start () {
// Copy the heights on the main thread
Color[] pixels = heightmap.GetPixels();
float[] heights = new float[pixels.Length];
for (int k = 0; k < pixels.Length; k++) {
heights[k] = Mathf.Round(pixels[k].r * maxTerrainHeight);
}
int width = heightmap.width;
int height = heightmap.height;
VoxelPlayEnvironment env = VoxelPlayEnvironment.instance;
env.superChunkSamplerFactory = e => new BakedSampler(heights, width, height, grass.index, dirt.index, water.index, waterLevel, e.world.terrainGenerator.minHeight);
}
}
class BakedSampler : ISuperChunkSampler {
readonly float[] heights;
readonly int width, height;
readonly ushort grass, dirt, water;
readonly double waterLevel, bottom;
public BakedSampler (float[] heights, int width, int height, ushort grass, ushort dirt, ushort water, double waterLevel, double bottom) {
this.heights = heights;
this.width = width;
this.height = height;
this.grass = grass;
this.dirt = dirt;
this.water = water;
this.waterLevel = waterLevel;
this.bottom = bottom;
}
public int SampleColumn (double x, double z, ColumnInterval[] intervals, out double waterY, out ushort waterTypeIndex) {
waterY = waterLevel;
waterTypeIndex = 0;
int px = (int)System.Math.Floor(x);
int pz = (int)System.Math.Floor(z);
if (px < 0 || pz < 0 || px >= width || pz >= height) return 0;
double top = heights[pz * width + px];
intervals[0] = new ColumnInterval {
yTop = top,
yBottom = bottom,
topTypeIndex = grass,
sideTypeIndex = dirt,
bottomTypeIndex = dirt
};
if (top < waterLevel) waterTypeIndex = water;
return 1;
}
public bool TryGetTree (double x, double z, double groundY, out SuperChunkTreeCandidate tree) {
tree = default;
return false;
}
}
See Also
- Super Chunks - settings, quality presets and distant trees
- Environment & Terrain - other environment properties and methods
Suggest an improvement
Help us improve this documentation page.