Codea icon Voxels

Reference › Block worlds and voxel models in scenes and entities

Guides

Voxels, scenes and entities top ↑

Overview

Voxels build three-dimensional objects out of small blocks. Use them for terrain, editable worlds, or block-based models such as characters and props.

A voxel.world is a component: it must be attached to an entity in a scene. Create a scene, create an entity inside it, then add the voxel world with entity:add(voxel.world, ...). The entity positions, rotates, and scales the world; the scene supplies the camera, lighting, and rendering. Assign the scene to scene.main to display it.

If scenes and components are new to you, start with the Scenes & Entities guide. The examples below show how to add a voxel world to a scene, fill it with blocks, and generate terrain in chunks.

For smaller objects, voxel.model loads a voxel asset and exposes a mesh that you assign to an entity. A model is not a voxel-world component, but it still uses the scene and entity system to appear alongside the rest of your world.

Voxels

voxel top ↑

Module

Build worlds out of blocks. A voxel world is a component, add it to an entity and fill it with blocks such as grass, stone, water and glass

A small island

function setup()
   scene.main = scene.default3d()

   -- 2 x 1 x 2 chunks, each 16 x 128 x 16 blocks
   local island = scene.main:entity("island")
   world = island:add(voxel.world, vec3(2, 1, 2))

   world:box(vec3(0, 0, 0), vec3(31, 3, 31), "Water")
   world:sphere(vec3(16, 0, 16), 10, "Sand")
   world:line(vec3(16, 11, 16), vec3(16, 14, 16), "Wood")
   world:sphere(vec3(16, 18, 16), 3, "Leaves")

   island.position = vec3(-16, -4, -16)
   scene.main.camera:add(camera.rigs.orbit).distance = 40
end

Blocks are addressed by integer coordinates local to the world, from vec3(0, 0, 0) up to (but not including) voxel.world.size. Each block fills the unit cube from its coordinate to its coordinate plus one. Coordinates can always be given as a vec3 or as three numbers, and are rounded down to whole blocks

Blocks are named by their type: a block name ("Stone"), a voxel.block or nil for empty space. Any block can also be given a tint color which multiplies its texture

Changes are drawn on the next frame. The world is drawn by child entities of the world’s entity (one per chunk) which use the scene’s lighting and shadows

Large worlds can be generated as they are explored. voxel.world.generate() runs a function from one of your project’s tabs on background threads to fill each chunk as it comes within voxel.world.viewDistance of the camera, and unloads chunks again once they are far away

Endless hills (Main tab)

function setup()
   scene.main = scene.default3d()

   local terrain = scene.main:entity("terrain")
   world = terrain:add(voxel.world, vec3(64, 1, 64))
   world.viewDistance = 128
   world:generate(asset.Hills, "hills", { height = 12 })

   -- Look down on the middle of the world
   terrain.position = vec3(-512, -50, -512)
   scene.main.camera:add(camera.rigs.orbit).distance = 60
end

Endless hills (Hills tab)

function hills(chunk)
   for x = chunk.x, chunk.x + chunk.width - 1 do
      for z = chunk.z, chunk.z + chunk.depth - 1 do
         local top = math.floor(40 + noise(x / 50, z / 50) * params.height)
         chunk:box(x, 0, z, x, top - 1, z, "Dirt")
         chunk:set(x, top, z, "Grass")
      end
   end
end

Small voxel models, such as characters and props, are loaded from .cvox files (made with the Voxel Editor) or MagicaVoxel .vox files with voxel.model. Each model is drawn with a regular mesh, which any number of entities can share

A row of frogs

function setup()
   scene.main = scene.default3d()

   -- Frog.cvox from the Froggy example
   local frog = voxel.model(asset.Frog)

   -- Models are one unit per voxel, scale them down to fit the scene
   for i = 1, 3 do
      local e = scene.main:entity()
      e.mesh = frog.mesh
      e.scale = vec3(0.1, 0.1, 0.1)
      e.x = (i - 2) * 2 - 0.6
   end

   scene.main.camera:add(camera.rigs.orbit).distance = 8
end

Worlds and models are drawn with the voxel material, a lit material that shows each block’s texture and tint. Its roughness (0.9), metallic (0), reflectance (0.2), emissive (0, how brightly blocks glow in their own color) and occlusionStrength (0.45, how dark the corners between blocks are) can be changed through voxel.world.material or a model entity’s material. Block types can give their own roughness, metallic and emissive, which are used in place of the material’s

Shiny blocks and glowing ones

world.material.roughness = 0.6

world.blocks:add("Gold Block", { color = color(255, 200, 80), metallic = 1, roughness = 0.25 })
world.blocks:add("Lava", { texture = asset.builtin.Blocks.Lava, emissive = 2 })

Worlds and models can use any other material too. Shaders read the voxels they draw with these functions, which are available whenever a lit or unlit shader draws a world or model (HAS_VOXELS is defined then)

  • vec4 getVoxelColor() - the block’s texture tinted by its color. It discards the see-through pixels of cutout blocks and premultiplies translucent colors by their alpha
  • float getVoxelOcclusion() - how open the corner of the block is, from 0 (hemmed in by neighbouring blocks) to 1
  • float getVoxelRoughness(float fallback), float getVoxelMetallic(float fallback) and float getVoxelEmissive(float fallback) - the block type’s settings, or fallback for those it doesn’t give

Cutout and translucent blocks are drawn with copies of a world’s material, which follow any changes made to it

Blocks with stripes

stripes = shader.builder()
   :lit()
   :material
   [[
      #if defined(HAS_VOXELS)
      vec4 color = getVoxelColor();
      float stripe = step(0.5, fract(getWorldPosition().y * 2.0));
      color.rgb *= mix(0.4, 1.0, stripe) * mix(0.5, 1.0, getVoxelOcclusion());
      material.baseColor = color;
      material.roughness = getVoxelRoughness(0.8);
      material.metallic = getVoxelMetallic(0.0);
      material.emissive = vec4(color.rgb * getVoxelEmissive(0.0), 0.0);
      #endif
   ]]
   :build()

world.material = material(stripes)

voxel.world

Type

Syntax

voxel.world

A fixed size grid of blocks, divided into chunks

Create a world by adding it to an entity with entity:add(voxel.world, sizeInChunks[, chunkSize]). The world is made of sizeInChunks chunks, each chunkSize blocks in size (vec3(16, 128, 16) by default). It starts out empty, with the standard blocks available in voxel.world.blocks

Moving, rotating or scaling the entity moves, rotates or scales the world

local terrain = scene.main:entity("terrain")
world = terrain:add(voxel.world, vec3(4, 1, 4))

-- Smaller chunks for a 32 x 32 x 32 world
world = terrain:add(voxel.world, vec3(2, 2, 2), vec3(16, 16, 16))

-- Get the world back from its entity later
world = terrain:get(voxel.world)

voxel.world.size

Property

Syntax

voxel.world.size

The size of the world in blocks

voxel.world.chunkSize

Property

Syntax

voxel.world.chunkSize

The size of each chunk in blocks

voxel.world.blocks

Property

Syntax

voxel.world.blocks

The block types that can be used in this world

voxel.world:get(coord)

Method

Syntax

voxel.world:get(coord)

Gets the block at a coordinate

Parameters

coord vec3.

The coordinate of the block (or x, y, z)

Returns

voxel.block

The block type and its tint, or nil if the block is empty or outside of the world

color
local block, tint = world:get(10, 4, 10)
if block then
   print(block.name)
end

voxel.world:set(coord, block, tint)

Method

Syntax

voxel.world:set(coord, block, tint)

Sets the block at a coordinate. Coordinates outside of the world are ignored

Parameters

coord vec3.

The coordinate of the block (or x, y, z)

block string.

The block name, block type or nil for empty

tint color, optional.

A color to multiply the block’s texture by

world:set(10, 4, 10, "Stone")
world:set(vec3(10, 5, 10), "Solid", color(255, 0, 0))
world:set(10, 4, 10, nil) -- remove a block

voxel.world:box(min, max, block, tint)

Method

Syntax

voxel.world:box(min, max, block, tint)

Fills every block between two corners, including the corners themselves

Parameters

min vec3.

One corner of the box (or x, y, z)

max vec3.

The opposite corner of the box (or x, y, z)

block string.

The block name, block type or nil for empty

tint color, optional.

A color to multiply the block’s texture by

-- A 10 x 1 x 10 floor of grass
world:box(vec3(0, 0, 0), vec3(9, 0, 9), "Grass")

voxel.world:sphere(center, radius, block, tint)

Method

Syntax

voxel.world:sphere(center, radius, block, tint)

Fills every block within radius blocks of center

Parameters

center vec3.

The center of the sphere (or x, y, z)

radius number.

The radius of the sphere in blocks

block string.

The block name, block type or nil for empty

tint color, optional.

A color to multiply the block’s texture by

world:sphere(vec3(16, 8, 16), 6, "Stone")
world:sphere(vec3(16, 8, 16), 4, nil) -- hollow it out

voxel.world:line(start, end, block, tint)

Method

Syntax

voxel.world:line(start, end, block, tint)

Fills a line of blocks from start to end, including both ends

Parameters

start vec3.

The first block of the line (or x, y, z)

end vec3.

The last block of the line (or x, y, z)

block string.

The block name, block type or nil for empty

tint color, optional.

A color to multiply the block’s texture by

world:line(vec3(0, 10, 0), vec3(20, 15, 8), "Planks")

voxel.world.viewDistance

Property

Syntax

voxel.world.viewDistance

How far (in blocks) from the voxel.world.focus chunks are generated and drawn when the world has a generator. Chunks a little further away than this are unloaded. Defaults to 128

voxel.world.focus

Property

Syntax

voxel.world.focus

The point (in scene space) that chunks are generated around, such as the position of a player. When nil (the default) the scene’s camera is used

voxel.world.loading

Property

Syntax

voxel.world.loading

true while chunks within the view distance are still being generated or built, useful for showing a loading screen

voxel.world.material

Property

Syntax

voxel.world.material

The material blocks are drawn with, the voxel material unless it’s changed. Cutout and translucent blocks are drawn with copies of it, which follow any changes made to it. Set it to nil to go back to a new voxel material

world.material.roughness = 0.4

voxel.world:generate(tab, functionName, params)

Method

Syntax

voxel.world:generate(tab, functionName, params)

Fills the world using a generator function as chunks come within voxel.world.viewDistance of the voxel.world.focus. Chunks that move out of range are unloaded, unless they have been changed since they were generated. Calling generate again replaces the generator and starts generating from scratch

The function is called with a voxel.chunk to fill, on background threads so the game keeps running smoothly while the world is generated. Each thread runs the code from tab in its own Lua environment, so the function can use the code in that tab, the standard math, string and table libraries, noise, hash, color and print, but not globals or functions from your other tabs. Anything else it needs is passed in through params, which is copied and available to the generator as the global params

math.random is seeded for each chunk from its position (and params.seed when it is set), so a world generates the same way every time

hash(x[, y[, z]]) gives a number from 0 up to 1 for a position, which is always the same for that position (and params.seed), whichever chunk asks for it. Neighbouring chunks can use it to agree on things that cross the edges between them, where math.random would give each chunk different numbers. Coordinates are rounded down to whole numbers, and neighbouring positions give unrelated numbers (use noise for numbers that change smoothly). Give it an extra coordinate for more than one number at a position

Blocks can only be changed in chunks that have been generated, changes elsewhere are ignored

Parameters

tab asset.

The project tab containing the generator, such as asset.Generation

functionName string.

The name of the function in that tab to call for each chunk

params table, optional.

Values for the generator. Only numbers, strings, booleans and tables of these can be passed

-- One tree in some 16 x 16 block cells, placed the same way by every chunk that asks
function treeIn(cx, cz)
   if hash(cx, cz, 0) > 0.4 then return nil end
   local x = cx * 16 + math.floor(hash(cx, cz, 1) * 16)
   local z = cz * 16 + math.floor(hash(cx, cz, 2) * 16)
   return x, z
end
world:generate(asset.Generation, "generateTerrain", {
   seed = 42,
   rivers = true
})

voxel.world:clear()

Method

Syntax

voxel.world:clear()

Removes every block from the world, and stops generating

voxel.world:place(model, origin, block)

Method

Syntax

voxel.world:place(model, origin, block)

Copies a voxel.model into the world as blocks of one type, each tinted with its voxel’s color. The model’s voxel (0, 0, 0) goes at origin, and its empty voxels leave the world as it is. Placing with a nil block removes the blocks the model covers instead

Parameters

model voxel.model.

The model to place

origin vec3.

Where the model’s first voxel goes (or x, y, z)

block string.

The block name or voxel.block to build the model from, or nil to remove blocks

local house = voxel.model(asset.House)
world:place(house, vec3(40, 20, 12), "Planks")

voxel.world:save(asset)

Method

Syntax

voxel.world:save(asset)

Saves the world’s blocks to a .cvox file

A generated world only saves the chunks that have been changed since they were generated, as its generator can make the rest again. This keeps saves small, even for very large worlds

Parameters

asset asset.

Where to save the world, ending in .cvox

world:save(asset.documents .. "MyWorld.cvox")

voxel.world:load(asset)

Method

Syntax

voxel.world:load(asset)

Replaces the world’s blocks with those in a file saved by voxel.world.save()

Blocks are matched to the world’s block types by name. A block type the world doesn’t have yet is added without a texture, and can be given one afterwards with voxel.blocks.add(). The world must have the same chunk size as the one that was saved. Chunks beyond the world’s size are left out

To load a generated world, call voxel.world.generate() first and then load. Chunks in the file replace the generated ones, and the generator goes on making the rest

Parameters

asset asset.

The .cvox file to load

world:generate(asset.Generation, "generateTerrain", { seed = 42 })
world:load(asset.documents.MyWorld)

voxel.world:raycast(origin, direction, distance)

Method

Syntax

voxel.world:raycast(origin, direction, distance)

Finds the first block along a ray. The ray is in scene space (the same space as camera.screenToRay()), so it works however the world’s entity is moved, rotated or scaled

Parameters

origin vec3.

The start of the ray

direction vec3.

The direction of the ray

distance number, optional, default 1000.

The maximum distance to search

Returns

voxel.hit

The block that was hit, or nil if no block was found

function touched(touch)
   if touch.ended then
      local origin, dir = scene.main.camera:get(camera):screenToRay(touch.x, touch.y)
      local hit = world:raycast(origin, dir)
      if hit then
         -- Place a block on the face that was touched
         world:set(hit.coord + hit.normal, "Glass")
      end
   end
end

voxel.hit

Type

Syntax

voxel.hit

The result of voxel.world.raycast()

voxel.hit.coord

Property

Syntax

voxel.hit.coord

The coordinate of the block that was hit

voxel.hit.normal

Property

Syntax

voxel.hit.normal

The direction of the face that was hit, such as vec3(0, 1, 0) for the top of a block. coord + normal is the empty space in front of that face. vec3(0, 0, 0) when the ray starts inside a block

voxel.hit.block

Property

Syntax

voxel.hit.block

The type of block that was hit

voxel.hit.color

Property

Syntax

voxel.hit.color

The tint of the block that was hit

voxel.hit.point

Property

Syntax

voxel.hit.point

The point where the ray hit the block, in scene space

voxel.hit.distance

Property

Syntax

voxel.hit.distance

The distance from the ray’s origin to point

voxel.chunk

Type

Syntax

voxel.chunk

A chunk of the world being filled by a generator function (see voxel.world.generate()). Coordinates are world block coordinates, the same as voxel.world.set(), and anything outside of the chunk is ignored. Blocks are given by name or id, or nil for empty, and can be followed by a tint color like the world’s own functions. Coordinates are given as numbers, as vec3 isn’t available to generators

function generateTerrain(chunk)
   -- A layer of stone at the bottom of every chunk
   chunk:box(chunk.x, 0, chunk.z, chunk.x + chunk.width - 1, 3, chunk.z + chunk.depth - 1, "Stone")
end

voxel.chunk.x

Property

Syntax

voxel.chunk.x

The x coordinate of the first block in the chunk

voxel.chunk.y

Property

Syntax

voxel.chunk.y

The y coordinate of the first block in the chunk

voxel.chunk.z

Property

Syntax

voxel.chunk.z

The z coordinate of the first block in the chunk

voxel.chunk.width

Property

Syntax

voxel.chunk.width

The size of the chunk along the x axis

voxel.chunk.height

Property

Syntax

voxel.chunk.height

The size of the chunk along the y axis

voxel.chunk.depth

Property

Syntax

voxel.chunk.depth

The size of the chunk along the z axis

voxel.chunk:get(x, y, z)

Method

Syntax

voxel.chunk:get(x, y, z)

Gets the name and tint of a block in the chunk

Parameters

x integer.

Local voxel coordinate on the x axis.

y integer.

Local voxel coordinate on the y axis.

z integer.

Local voxel coordinate on the z axis.

Returns

string

The block name and its tint, or nil if the block is empty or outside of the chunk

color

voxel.chunk:set(x, y, z, block, tint)

Method

Syntax

voxel.chunk:set(x, y, z, block, tint)

Sets a block in the chunk

Parameters

x integer.

Local voxel coordinate on the x axis.

y integer.

Local voxel coordinate on the y axis.

z integer.

Local voxel coordinate on the z axis.

block string.

The block name or id, or nil for empty

tint color, optional.

A color to tint the block with

voxel.chunk:box(x1, y1, z1, x2, y2, z2, block, tint)

Method

Syntax

voxel.chunk:box(x1, y1, z1, x2, y2, z2, block, tint)

Fills every block between two corners, including the corners themselves

Parameters

x1 integer.

X coordinate of the start point.

y1 integer.

Y coordinate of the start point.

z1 integer.

Z coordinate of the start point.

x2 integer.

X coordinate of the end point.

y2 integer.

Y coordinate of the end point.

z2 integer.

Z coordinate of the end point.

block string.

The block name or id, or nil for empty

tint color, optional.

A color to tint the blocks with

voxel.chunk:sphere(x, y, z, radius, block, tint)

Method

Syntax

voxel.chunk:sphere(x, y, z, radius, block, tint)

Fills every block within radius blocks of a center block

Parameters

x integer.

Local voxel coordinate on the x axis.

y integer.

Local voxel coordinate on the y axis.

z integer.

Local voxel coordinate on the z axis.

radius number.

Sphere radius in voxel units.

block string.

The block name or id, or nil for empty

tint color, optional.

A color to tint the blocks with

voxel.chunk:line(x1, y1, z1, x2, y2, z2, block, tint)

Method

Syntax

voxel.chunk:line(x1, y1, z1, x2, y2, z2, block, tint)

Fills a line of blocks between two blocks, including the ends

Parameters

x1 integer.

X coordinate of the start point.

y1 integer.

Y coordinate of the start point.

z1 integer.

Z coordinate of the start point.

x2 integer.

X coordinate of the end point.

y2 integer.

Y coordinate of the end point.

z2 integer.

Z coordinate of the end point.

block string.

The block name or id, or nil for empty

tint color, optional.

A color to tint the blocks with

voxel.blocks

Type

Syntax

voxel.blocks

The block types available to a world. Every world starts with the standard blocks below, which use textures from the builtin Blocks asset pack

Grass, Dirt, Sand, Stone, Gravel, Snow, Ice, Bedrock, Water, Glass, Glass Frame, Red Brick, Brick, Coal Ore, Gold Ore, Diamond Ore, Redstone Ore, Planks, Wood, Leaves, Crafting Table and Solid (plain white, use it with a tint)

Block types can be looked up by name, world.blocks.Stone or world.blocks["Glass Frame"]

voxel.blocks:add(name, definition)

Method

Syntax

voxel.blocks:add(name, definition)

Adds a new block type, or changes the existing type with the same name. The definition table can contain:

  • texture - an image asset used for every face, or a table of assets by face
  • color - a tint for every face, or a table of colors by face
  • translucent - true for blended blocks like water and glass. Faces between translucent blocks of the same type are hidden
  • cutout - true for blocks with see-through holes like leaves, where pixels with less than half alpha are not drawn
  • roughness and metallic - from 0 to 1, used in place of the world material’s
  • emissive - how brightly the block glows in its own color, from 0 to 8, used in place of the world material’s

Faces are named all, sides, top, bottom, north, south, east and west (most specific wins). Blocks without a texture are plain white, tinted by their color

Any other values in the definition become custom properties of the block type

Parameters

name string.

The name of the block type

definition table, optional.

How the block looks, along with any custom properties

Returns

voxel.block

The block type

world.blocks:add("Cactus", {
   texture = {
      sides = asset.builtin.Blocks.Cactus_Side,
      top = asset.builtin.Blocks.Cactus_Top,
      bottom = asset.builtin.Blocks.Cactus_Inside
   },
   canDig = true
})

world.blocks:add("Tinted Glass", {
   texture = asset.builtin.Blocks.Glass,
   color = color(120, 200, 255, 160),
   translucent = true
})

voxel.blocks:get(name)

Method

Syntax

voxel.blocks:get(name)

Gets a block type by name or id

Parameters

name string.

The name or id of the block type

Returns

voxel.block

The block type, or nil if there isn’t one

voxel.blocks:all()

Method

Syntax

voxel.blocks:all()

Gets every block type, in the order they were added

Returns

table

A list of block types

for i, block in ipairs(world.blocks:all()) do
   print(i, block.name)
end

voxel.blocks:clear()

Method

Syntax

voxel.blocks:clear()

Removes every block type, including the standard blocks. Blocks already in the world using a removed type are no longer drawn

voxel.block

Type

Syntax

voxel.block

A type of block, such as Grass or Water

Custom values can be stored on a block type, either in its definition or by setting them directly

world.blocks.Bedrock.canDig = false

local hit = world:raycast(origin, dir)
if hit and hit.block.canDig ~= false then
   world:set(hit.coord, nil)
end

voxel.block.name

Property

Syntax

voxel.block.name

The name of this block type

voxel.block.id

Property

Syntax

voxel.block.id

A number identifying this block type within its world

voxel.block.translucent

Property

Syntax

voxel.block.translucent

Whether this block type is blended, like water and glass

voxel.block.cutout

Property

Syntax

voxel.block.cutout

Whether this block type has see-through holes, like leaves

voxel.block.roughness

Property

Syntax

voxel.block.roughness

The roughness of this block type, from 0 to 1, or nil to use the world material’s

voxel.block.metallic

Property

Syntax

voxel.block.metallic

How metallic this block type is, from 0 to 1, or nil to use the world material’s

voxel.block.emissive

Property

Syntax

voxel.block.emissive

How brightly this block type glows in its own color, from 0 to 8, or nil to use the world material’s

voxel.model

Type

Syntax

voxel.model

A small grid of colored voxels drawn as a single mesh, for things like characters, vehicles and props

Load a model from a .cvox or MagicaVoxel .vox file with voxel.model(asset.Name), or make an empty one with voxel.model(size). Voxels are addressed by integer coordinates from vec3(0, 0, 0) up to (but not including) voxel.model.size, and each one is either empty or filled with a color

MagicaVoxel scenes with several objects are combined into one model, using their positions and rotations. Hidden objects and layers are left out, and MagicaVoxel’s z-up axes are turned to match Codea’s y-up

car = voxel.model(asset.Car)

-- An empty model with a red voxel in its corner
gem = voxel.model(vec3(8, 8, 8))
gem:set(0, 0, 0, color(255, 0, 0))

voxel.model.size

Property

Syntax

voxel.model.size

The size of the model in voxels

voxel.model.mesh

Property

Syntax

voxel.model.mesh

A mesh that draws the model, with one unit per voxel and its origin at the corner of voxel (0, 0, 0). Faces between neighbouring voxels are left out and corners are shaded by ambient occlusion, like a voxel.world. It’s drawn with a new voxel material, or any other material given to its entity

The same mesh is returned until the model changes, so it can be shared by many entities. Changing a voxel makes a new mesh the next time this is read, entities already using the old mesh keep showing it

local tree = scene.main:entity()
tree.mesh = treeModel.mesh

-- Centered on the entity, standing on its origin
local bounds = treeModel.mesh.bounds
tree.position = -vec3(bounds.center.x, bounds.min.y, bounds.center.z)

voxel.model:get(coord)

Method

Syntax

voxel.model:get(coord)

Gets the color of a voxel

Parameters

coord vec3.

The coordinate of the voxel (or x, y, z)

Returns

color

The voxel’s color, or nil if it is empty or outside of the model

voxel.model:set(coord, color)

Method

Syntax

voxel.model:set(coord, color)

Sets the color of a voxel, or empties it. Coordinates outside of the model are ignored

Parameters

coord vec3.

The coordinate of the voxel (or x, y, z)

color color.

The voxel’s color, or nil for empty

model:set(2, 0, 3, color(255, 200, 0))
model:set(2, 0, 3, nil) -- remove a voxel

voxel.model:copy()

Method

Syntax

voxel.model:copy()

Makes a copy of the model. Changing either one leaves the other as it is, which makes copies useful for undo in an editor. The copy shares the model’s voxel.model.mesh until one of them changes, so a copy made after the mesh is read can be shown again without being meshed

Returns

voxel.model

A new model with the same size and voxels

-- After each edit
table.insert(undoSteps, model:copy())

voxel.model:assign(other)

Method

Syntax

voxel.model:assign(other)

Replaces the model’s size and voxels with another model’s, leaving the other model as it is. Entities keep showing the old mesh until they’re given voxel.model.mesh again

Parameters

other voxel.model.

The model to copy from

-- Undo, back to the previous step
table.remove(undoSteps)
model:assign(undoSteps[#undoSteps])
entity.mesh = model.mesh

voxel.model:save(asset)

Method

Syntax

voxel.model:save(asset)

Saves the model to a file. The file’s extension picks the format: .cvox for the Voxel Editor, or .vox for MagicaVoxel. MagicaVoxel files can hold at most 255 different colors and 256 voxels in each dimension, larger or more colorful models can be saved as .cvox

Parameters

asset asset.

Where to save the model, ending in .cvox or .vox

gem:save(asset.documents .. "Gem.vox")