How to use Terrain:WriteVoxels()?

Yes, I have read thdocs so DONT PASTE THEM, I need an example because whenever I change any value in the Example in the docs it errors. Please a short simple labelled example would be a great help!

Terrain:WriteVoxels() requires knowledge of Vector3s, Region3, 3D arrays, and voxels.

If you just want to fill a block of terrain, you can use:

Copy this code into a Script under ServerScriptStorage, then run the game.

local terrain = workspace.Terrain

local min = Vector3.new(0,0,0) --Minimum point of Region3
local max = Vector3.new(16,4,16) --Maximum point of Region3

--Region3 describes a 3D space based off two points, min and max.
local terrainRegion = Region3.new(min, max):ExpandToGrid(4)

--I create these parts to show you the area of the Region3 spanning from min to max. 
local minPointPart = Instance.new("Part")
minPointPart.Size = Vector3.new(1.5,1.5,1.5)
minPointPart.Anchored = true
minPointPart.Position = min 
minPointPart.Name = "minPointPart"
minPointPart.BrickColor = BrickColor.new("Really red")
minPointPart.Parent = workspace

local maxPointPart = Instance.new("Part")
maxPointPart.Size = Vector3.new(1.5,1.5,1.5)
maxPointPart.Anchored = true
maxPointPart.Position = max
maxPointPart.Name = "maxPointPart"
maxPointPart.BrickColor = BrickColor.new("Really blue")
maxPointPart.Parent = workspace

--[[
!!!Notice how our points span from 0,0,0 to 16,4,16. Divide this by 4 (resolution) to get the number into voxels
Therefore your 3D array will have a size of 4,1,4
]]

--4*1*4 3D array of materials
local materials = {
	{{Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier}},
	{{Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier}},
	{{Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier}},
	{{Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier, Enum.Material.Glacier}}
}

--4*1*4 3D array of occupancies (notice the generated terrain has a hole where the 0's are placed
local occupancies = {
	{{1, 1, 1, 1}},
	{{1, 0, 0, 1}},
	{{1, 0, 0, 1}},
	{{1, 1, 1, 1}}
}

--[[
--Paramaters--
Region3
Resolution: Must be set to a value of 4
3D array of materials
3D array of occupancies where 0 = an empty voxel, and 1 = a filled voxel
]]--
terrain:WriteVoxels(terrainRegion, 4, materials, occupancies)
3 Likes

I sill dont understand how do I make big sections of terrain?

Terrain:WriteVoxels() takes a region, the size of a terrain cell in studs (must be 4) and two 3-dimensional arrays. One contains material information for each terrain cell in the region. The other contains occupancy information for each terrain cell in the region.

Below is the structure of a 3-dimensional array and below that is some example code.

Structure of a material 3d array for a 4x2x3 cell region. What each array contains is listed with ‘-’:s below it.

array (indexes are X values)
  - array (indexes are Y values)
    - array (indexes are Z values)
      - material
      - material
      - material
    - array (indexes are Z values)
      - material
      - material
      - material
  - array (indexes are Y values)
    - array (indexes are Z values)
      - material
      - material
      - material
    - array (indexes are Z values)
      - material
      - material
      - material
  - array (indexes are Y values)
    - array (indexes are Z values)
      - material
      - material
      - material
    - array (indexes are Zvalues)
      - material
      - material
      - material
  - array (indexes are Y values)
    - array (indexes are Z values)
      - material
      - material
      - material
    - array (indexes are Z values)
      - material
      - material
      - material

Example code:

-- this should create rows of grass and ground. Grass voxels/cells are more full.

-- 11x1x5 voxel region
local r3 = Region3.new(
    Vector3.new(-16, 0, -12),
    Vector3.new(28, 4, 8)
)

local sizeAsVoxels = r3.Size/4
local xs, ys, zs = sizeAsVoxels.X, sizeAsVoxels.Y, sizeAsVoxels.Z

-- you could also use a three dimensional loop (y-loop inside x-loop, z-loop inside y-loop)
-- for creating the 3d array.
local function create3DArray(xs, ys, zs, defaultVal)
    local xIndexT = table.create(xs)
    for x = 1, xs do
        local yIndexT = table.create(ys)
        for y = 1, ys do
            yIndexT[y] = table.create(zSize, defaultVal)
        end
        xIndexT[x] = yIndexT
    end
    return xIndexT
end

local material3DArray = create3dArray(xs, ys, zs, Enum.Material.Air)
local occupancy3DArray = create3dArray(xs, ys, zs, 0)

local materials = {
    Enum.Material.Grass
    Enum.Material.Ground
}

local occupancies = {
    1
    .8
}
 
for x = 1, xs do
    for y = 1, ys do
        for z = 1, zs do
            local index = x%2+1
            occupancy3DArray[x][y][z] = occupancies[index]
            material3DArray[x][y][z] = materials[index]
        end
    end
end

workspace.Terrain:WriteVoxels(r3, 4, material3DArray, occupancy3DArray)

While wtiting this, I finally understood how the second parameter of table.create can be useful :smile:.

Edit: I realized that my 3d array creation code is not going to work properly, because it reuses the se table instead of creating a new one. Surprising that I didn’t realise that until now. I have now edited it.

2 Likes

You have to modify the 3D array and the region size relative to one another.

The region3 describes the size, in that size you can fit voxels. Voxels are 4x4x4 cubes in this case. If your size is Vector3.new(20,20,20). You can fit a cube of voxels that is of size 5x5x5, because 20/4 is 5.

Now as for the 3D arrays, the 3D arrays describes literally EACH voxels properties. You can make one voxel a different material from the others, etc…

If you don’t understand 3D arrays, here’s a good thread: