Skip to content

Instantly share code, notes, and snippets.

@Vercidium
Last active September 27, 2025 00:00
Show Gist options
  • Select an option

  • Save Vercidium/a3002bd083cce2bc854c9ff8f0118d33 to your computer and use it in GitHub Desktop.

Select an option

Save Vercidium/a3002bd083cce2bc854c9ff8f0118d33 to your computer and use it in GitHub Desktop.

Revisions

  1. Vercidium revised this gist Feb 2, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    // Code ported from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/

    // Note this implemenetation does not support different block types or block normals
    // Note this implementation does not support different block types or block normals
    // The original author describes how to do this here: https://0fps.net/2012/07/07/meshing-minecraft-part-2/


  2. Vercidium revised this gist Aug 4, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -38,8 +38,8 @@ public void GreedyMesh()
    // q determines the direction (X, Y or Z) that we are searching
    // m.IsBlockAt(x,y,z) takes global map positions and returns true if a block exists there

    bool blockCurrent = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCompare = x[d] < CHUNK_SIZE - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;
    bool blockCurrent = 0 <= x[d] ? IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCompare = x[d] < CHUNK_SIZE - 1 ? IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;

    // The mask is set to true if there is a visible face between two blocks,
    // i.e. both aren't empty and both aren't blocks
  3. Vercidium revised this gist Aug 4, 2019. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -3,9 +3,11 @@
    // Note this implemenetation does not support different block types or block normals
    // The original author describes how to do this here: https://0fps.net/2012/07/07/meshing-minecraft-part-2/



    const int CHUNK_SIZE = 32;

    // These store the location of the chunk in the world, e.g. (0,0,0), (32,0,0), (64,0,0)
    // These variables store the location of the chunk in the world, e.g. (0,0,0), (32,0,0), (64,0,0)
    int chunkPosX = 0;
    int chunkPosY = 0;
    int chunkPosZ = 0;
  4. Vercidium revised this gist Aug 4, 2019. 1 changed file with 7 additions and 7 deletions.
    14 changes: 7 additions & 7 deletions greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,8 @@
    // Code ported from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/

    // Note this implemenetation does not support different block types or block normals
    // The original author describes how to do this here: https://0fps.net/2012/07/07/meshing-minecraft-part-2/

    const int CHUNK_SIZE = 32;

    // These store the location of the chunk in the world, e.g. (0,0,0), (32,0,0), (64,0,0)
    @@ -29,18 +32,15 @@ public void GreedyMesh()
    for (x[v] = 0; x[v] < CHUNK_SIZE; ++x[v])
    {
    for (x[u] = 0; x[u] < CHUNK_SIZE; ++x[u])
    {
    // Note this implemenetation does not support different block types or block normals
    // The original author describes how to do this here: https://0fps.net/2012/07/07/meshing-minecraft-part-2/

    {
    // q determines the direction (X, Y or Z) that we are searching
    // m.IsBlockAt(x,y,z) takes global map positions and returns true if a block exists there

    bool blockCurrent = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCompare = x[d] < CHUNK_SIZE - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;

    // The mask is set to true if there is a visible face between two blocks
    // i.e. both aren't empty and both aren't blocks
    // The mask is set to true if there is a visible face between two blocks,
    // i.e. both aren't empty and both aren't blocks
    mask[n++] = blockCurrent != blockCompare;
    }
    }
    @@ -50,7 +50,7 @@ public void GreedyMesh()
    n = 0;

    // Generate a mesh from the mask using lexicographic ordering,
    // by looping over each block in this slice of the chunk
    // by looping over each block in this slice of the chunk
    for (j = 0; j < CHUNK_SIZE; ++j)
    {
    for (i = 0; i < CHUNK_SIZE;)
  5. Vercidium revised this gist Aug 4, 2019. 1 changed file with 10 additions and 11 deletions.
    21 changes: 10 additions & 11 deletions greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -49,31 +49,30 @@ public void GreedyMesh()

    n = 0;

    // Generate a mesh from the mask using lexicographic ordering by
    // looping over each block in this slice of the chunk
    // Generate a mesh from the mask using lexicographic ordering,
    // by looping over each block in this slice of the chunk
    for (j = 0; j < CHUNK_SIZE; ++j)
    {
    for (i = 0; i < CHUNK_SIZE;)
    {
    if (mask[n])
    {
    // Compute the width of this quad and store it in w

    // This is done by searching along the current axis until mask[n + w] is false
    // Compute the width of this quad and store it in w
    // This is done by searching along the current axis until mask[n + w] is false
    for (w = 1; i + w < CHUNK_SIZE && mask[n + w]; w++) { }

    // Compute the height of this quad and store it in h

    // This is done by checking if every block next to this row (range 0 to w) is also part of the mask.
    // For example, if w is 5, we currently have a quad of dimensions 1x5.
    // In this loop, we attempt to expand this quad out to 32x5, but stop
    // if we reach a hole in the mesh
    // Compute the height of this quad and store it in h
    // This is done by checking if every block next to this row (range 0 to w) is also part of the mask.
    // For example, if w is 5 we currently have a quad of dimensions 1 x 5. To reduce triangle count,
    // greedy meshing will attempt to expand this quad out to CHUNK_SIZE x 5, but will stop if it reaches a hole in the mask

    var done = false;
    for (h = 1; j + h < CHUNK_SIZE; h++)
    {
    // Check each block next to this quad
    for (k = 0; k < w; ++k)
    {
    // If there's a hole in the mask, exit
    if (!mask[n + k + h * CHUNK_SIZE])
    {
    done = true;
  6. Vercidium revised this gist Aug 4, 2019. 1 changed file with 14 additions and 3 deletions.
    17 changes: 14 additions & 3 deletions greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -21,6 +21,7 @@ public void GreedyMesh()
    var mask = new bool[CHUNK_SIZE * CHUNK_SIZE];
    q[d] = 1;

    // Check each slice of the chunk one at a time
    for (x[d] = -1; x[d] < CHUNK_SIZE;)
    {
    // Compute the mask
    @@ -46,18 +47,28 @@ public void GreedyMesh()

    ++x[d];

    // Generate a mesh from the mask using lexicographic ordering
    n = 0;

    // Generate a mesh from the mask using lexicographic ordering by
    // looping over each block in this slice of the chunk
    for (j = 0; j < CHUNK_SIZE; ++j)
    {
    for (i = 0; i < CHUNK_SIZE;)
    {
    if (mask[n])
    {
    // Compute the width of this quad and store it in w

    // This is done by searching along the current axis until mask[n + w] is false
    for (w = 1; i + w < CHUNK_SIZE && mask[n + w]; w++) { }

    // Compute the height of this quad and store it in h

    // This is done by checking if every block next to this row (range 0 to w) is also part of the mask.
    // For example, if w is 5, we currently have a quad of dimensions 1x5.
    // In this loop, we attempt to expand this quad out to 32x5, but stop
    // if we reach a hole in the mesh

    var done = false;
    for (h = 1; j + h < CHUNK_SIZE; h++)
    {
    @@ -77,7 +88,7 @@ public void GreedyMesh()
    x[u] = i;
    x[v] = j;

    // du and dv determine the size and orientation of the face
    // du and dv determine the size and orientation of this face
    var du = new int[3];
    du[u] = w;

    @@ -91,7 +102,7 @@ public void GreedyMesh()
    new Int3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]) // Bottom right vertice position
    );

    // Reset the mask
    // Clear this part of the mask, so we don't add duplicate faces
    for (l = 0; l < h; ++l)
    for (k = 0; k < w; ++k)
    mask[n + k + l * CHUNK_SIZE] = false;
  7. Vercidium revised this gist Aug 4, 2019. 1 changed file with 11 additions and 10 deletions.
    21 changes: 11 additions & 10 deletions greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -23,29 +23,30 @@ public void GreedyMesh()

    for (x[d] = -1; x[d] < CHUNK_SIZE;)
    {
    // Compute mask
    // Compute the mask
    var n = 0;
    for (x[v] = 0; x[v] < CHUNK_SIZE; ++x[v])
    {
    for (x[u] = 0; x[u] < CHUNK_SIZE; ++x[u])
    {
    // Note this implemenetation does not support different block types or block normals
    // The original author describes how to do this here: https://0fps.net/2012/07/07/meshing-minecraft-part-2/

    // The mask is set to true if there is a visible face between two blocks.
    // q determines the direction that we are searching
    // q determines the direction (X, Y or Z) that we are searching
    // m.IsBlockAt(x,y,z) takes global map positions and returns true if a block exists there
    // chunkPosX, chunkPosY and chunkPosZ store the location of this chunk in the world

    bool blockEmpty = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCovered = x[d] < CHUNK_SIZE - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;
    bool blockCurrent = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCompare = x[d] < CHUNK_SIZE - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;

    mask[n++] = blockEmpty != blockCovered;
    // The mask is set to true if there is a visible face between two blocks
    // i.e. both aren't empty and both aren't blocks
    mask[n++] = blockCurrent != blockCompare;
    }
    }

    ++x[d];

    // Generate mesh from the mask using lexicographic ordering
    // Generate a mesh from the mask using lexicographic ordering
    n = 0;
    for (j = 0; j < CHUNK_SIZE; ++j)
    {
    @@ -56,7 +57,7 @@ public void GreedyMesh()
    // Compute the width of this quad and store it in w
    for (w = 1; i + w < CHUNK_SIZE && mask[n + w]; w++) { }

    // Compute height of this quad and store it in h
    // Compute the height of this quad and store it in h
    var done = false;
    for (h = 1; j + h < CHUNK_SIZE; h++)
    {
    @@ -95,7 +96,7 @@ public void GreedyMesh()
    for (k = 0; k < w; ++k)
    mask[n + k + l * CHUNK_SIZE] = false;

    //Increment counters and continue
    // Increment counters and continue
    i += w;
    n += w;
    }
  8. Vercidium renamed this gist Aug 4, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.txt → greedyvoxelmeshing
    Original file line number Diff line number Diff line change
    @@ -36,7 +36,7 @@ public void GreedyMesh()
    // m.IsBlockAt(x,y,z) takes global map positions and returns true if a block exists there
    // chunkPosX, chunkPosY and chunkPosZ store the location of this chunk in the world

    bool blockEmpty = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockEmpty = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCovered = x[d] < CHUNK_SIZE - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;

    mask[n++] = blockEmpty != blockCovered;
  9. Vercidium revised this gist Aug 4, 2019. 1 changed file with 20 additions and 12 deletions.
    32 changes: 20 additions & 12 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,12 @@
    // Code ported from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/

    const int CHUNK_SIZE = 32;

    // These store the location of the chunk in the world, e.g. (0,0,0), (32,0,0), (64,0,0)
    int chunkPosX = 0;
    int chunkPosY = 0;
    int chunkPosZ = 0;

    public void GreedyMesh()
    {
    // Sweep over each axis (X, Y and Z)
    @@ -11,25 +18,26 @@ public void GreedyMesh()
    var x = new int[3];
    var q = new int[3];

    var mask = new bool[Constants.ChunkSize * Constants.ChunkSize];
    var mask = new bool[CHUNK_SIZE * CHUNK_SIZE];
    q[d] = 1;

    for (x[d] = -1; x[d] < Constants.ChunkSize;)
    for (x[d] = -1; x[d] < CHUNK_SIZE;)
    {
    // Compute mask
    var n = 0;
    for (x[v] = 0; x[v] < Constants.ChunkSize; ++x[v])
    for (x[v] = 0; x[v] < CHUNK_SIZE; ++x[v])
    {
    for (x[u] = 0; x[u] < Constants.ChunkSize; ++x[u])
    for (x[u] = 0; x[u] < CHUNK_SIZE; ++x[u])
    {
    // Note this implemenetation does not support different block types or block normals

    // The mask is set to true if there is a visible face between two blocks.
    // q determines the direction that we are searching
    // m.IsBlockAt(x,y,z) takes global map positions and returns true if a block exists there
    // chunkPosX, chunkPosY and chunkPosZ store the location of this chunk in the world

    bool blockEmpty = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCovered = x[d] < Constants.ChunkSize - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;
    bool blockCovered = x[d] < CHUNK_SIZE - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;

    mask[n++] = blockEmpty != blockCovered;
    }
    @@ -39,22 +47,22 @@ public void GreedyMesh()

    // Generate mesh from the mask using lexicographic ordering
    n = 0;
    for (j = 0; j < Constants.ChunkSize; ++j)
    for (j = 0; j < CHUNK_SIZE; ++j)
    {
    for (i = 0; i < Constants.ChunkSize;)
    for (i = 0; i < CHUNK_SIZE;)
    {
    if (mask[n])
    {
    // Compute the width of this quad and store it in w
    for (w = 1; i + w < Constants.ChunkSize && mask[n + w]; w++) { }
    for (w = 1; i + w < CHUNK_SIZE && mask[n + w]; w++) { }

    // Compute height of this quad and store it in h
    var done = false;
    for (h = 1; j + h < Constants.ChunkSize; h++)
    for (h = 1; j + h < CHUNK_SIZE; h++)
    {
    for (k = 0; k < w; ++k)
    {
    if (!mask[n + k + h * Constants.ChunkSize])
    if (!mask[n + k + h * CHUNK_SIZE])
    {
    done = true;
    break;
    @@ -75,7 +83,7 @@ public void GreedyMesh()
    var dv = new int[3];
    dv[v] = h;

    // Create a quad for this face. No colour, normal or texture is stored in this block vertex format.
    // Create a quad for this face. Colour, normal or textures are not stored in this block vertex format.
    BlockVertex.AppendQuad(new Int3(x[0], x[1], x[2]), // Top-left vertice position
    new Int3(x[0] + du[0], x[1] + du[1], x[2] + du[2]), // Top right vertice position
    new Int3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]), // Bottom left vertice position
    @@ -85,7 +93,7 @@ public void GreedyMesh()
    // Reset the mask
    for (l = 0; l < h; ++l)
    for (k = 0; k < w; ++k)
    mask[n + k + l * Constants.ChunkSize] = false;
    mask[n + k + l * CHUNK_SIZE] = false;

    //Increment counters and continue
    i += w;
  10. Vercidium created this gist Aug 4, 2019.
    103 changes: 103 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,103 @@
    // Code ported from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/

    public void GreedyMesh()
    {
    // Sweep over each axis (X, Y and Z)
    for (var d = 0; d < 3; ++d)
    {
    int i, j, k, l, w, h;
    int u = (d + 1) % 3;
    int v = (d + 2) % 3;
    var x = new int[3];
    var q = new int[3];

    var mask = new bool[Constants.ChunkSize * Constants.ChunkSize];
    q[d] = 1;

    for (x[d] = -1; x[d] < Constants.ChunkSize;)
    {
    // Compute mask
    var n = 0;
    for (x[v] = 0; x[v] < Constants.ChunkSize; ++x[v])
    {
    for (x[u] = 0; x[u] < Constants.ChunkSize; ++x[u])
    {
    // Note this implemenetation does not support different block types or block normals

    // The mask is set to true if there is a visible face between two blocks.
    // q determines the direction that we are searching
    // m.IsBlockAt(x,y,z) takes global map positions and returns true if a block exists there

    bool blockEmpty = 0 <= x[d] ? m.IsBlockAt(x[0] + chunkPosX, x[1] + chunkPosY, x[2] + chunkPosZ) : true;
    bool blockCovered = x[d] < Constants.ChunkSize - 1 ? m.IsBlockAt(x[0] + q[0] + chunkPosX, x[1] + q[1] + chunkPosY, x[2] + q[2] + chunkPosZ) : true;

    mask[n++] = blockEmpty != blockCovered;
    }
    }

    ++x[d];

    // Generate mesh from the mask using lexicographic ordering
    n = 0;
    for (j = 0; j < Constants.ChunkSize; ++j)
    {
    for (i = 0; i < Constants.ChunkSize;)
    {
    if (mask[n])
    {
    // Compute the width of this quad and store it in w
    for (w = 1; i + w < Constants.ChunkSize && mask[n + w]; w++) { }

    // Compute height of this quad and store it in h
    var done = false;
    for (h = 1; j + h < Constants.ChunkSize; h++)
    {
    for (k = 0; k < w; ++k)
    {
    if (!mask[n + k + h * Constants.ChunkSize])
    {
    done = true;
    break;
    }
    }

    if (done)
    break;
    }

    x[u] = i;
    x[v] = j;

    // du and dv determine the size and orientation of the face
    var du = new int[3];
    du[u] = w;

    var dv = new int[3];
    dv[v] = h;

    // Create a quad for this face. No colour, normal or texture is stored in this block vertex format.
    BlockVertex.AppendQuad(new Int3(x[0], x[1], x[2]), // Top-left vertice position
    new Int3(x[0] + du[0], x[1] + du[1], x[2] + du[2]), // Top right vertice position
    new Int3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]), // Bottom left vertice position
    new Int3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]) // Bottom right vertice position
    );

    // Reset the mask
    for (l = 0; l < h; ++l)
    for (k = 0; k < w; ++k)
    mask[n + k + l * Constants.ChunkSize] = false;

    //Increment counters and continue
    i += w;
    n += w;
    }
    else
    {
    i++;
    n++;
    }
    }
    }
    }
    }
    }