islaApocalypse/Core/Scripts/MATH_MARCHING_CUBES.md
beezm 783ee8b016 docs: fix MATH_MARCHING_CUBES §4 polarity + dims
Task 17 corrected the density sign convention in §1-§2 but left §4's worked
example on the old inverted convention, so the doc contradicted itself. §4 now
matches: negative is underground, positive is air. Also corrects a stale
16x16x64 chunk reference to 24x24x256.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 21:32:51 -04:00

3.6 KiB
Raw Permalink Blame History

📐 The Math of Marching Cubes (Smooth Voxels)

Overview

In a standard blocky game like Minecraft (Greedy Meshing), if a coordinate has a block, you draw a square. If it doesn't, you draw nothing.

In a smooth voxel game like 7 Days to Die, we use an algorithm called Marching Cubes. Instead of looking at a single block, the algorithm looks at the 8 corners of an invisible 3D grid cell (a cube) and asks: "Which of these 8 corners are underground, and which are in the air?"

Based on the answer, it draws a specific set of triangles through the invisible cube to create a smooth surface.


🔑 Key Concepts

1. Density (The "Float" Value)

In smooth voxels, a point in space isn't just "Solid" (1) or "Empty" (0). It has a continuous Density value.

Mind the sign — this project's convention is the opposite of many tutorials. Density here is essentially "how far above the surface am I?", computed as (y surfaceY) normalised by the local slope. So it counts upward, not downward:

  • 1.0 = High in the sky (Empty Space).
  • 0.5 = Slightly above ground (Air).
  • 0.0 = The exact surface of the ground.
  • -0.5 = Slightly underground (Dirt).
  • -1.0 = Deep underground (Solid Rock).

2. The Iso-Level (The Threshold)

The Iso-Level is the exact density value where the "skin" of the world is drawn. Here it is 0.0 (Constants.ISO_LEVEL).

  • If a corner's density is less than 0.0, it is "Inside" the terrain.
  • If a corner's density is greater than 0.0, it is "Outside" in the air.

This matches the code: MarchingCubes.GenerateMesh sets a corner's bit when cornerDensities[i] < isolevel. Getting this backwards inverts every surface normal and makes the world render inside-out — which is a real bug this project has hit before.

3. The Triangulation Table (The Magic Array)

A cube has 8 corners. Each corner can either be Inside or Outside. That means there are 2^8 = 256 possible combinations.

Instead of writing 256 if/else statements, the algorithm uses a hardcoded Lookup Table (an array of integers).

  • Example: If corner 0 is inside, but corners 1-7 are outside, the table instantly says: "Draw a single small triangle slicing off corner 0."
  • Example: If corners 0, 1, 2, and 3 are inside (the whole bottom half), the table says: "Draw a flat quad (two triangles) straight across the middle of the cube."

4. Linear Interpolation (Why it looks Smooth)

If the algorithm just drew triangles exactly halfway between the inside and outside corners, the terrain would still look a bit jagged (like a low-poly PS1 game).

To make it perfectly smooth, we Interpolate. Remember the sign convention from §1 — negative is underground, positive is air:

  • Corner A has a density of -1.0 (deep underground, very solid).
  • Corner B has a density of 0.1 (just barely up in the air).
  • Because 0.1 is much closer to our 0.0 Iso-Level than -1.0 is, the algorithm slides the triangle vertex much closer to Corner B. This creates gentle slopes and sharp cliffs dynamically.

⚙️ The Execution Loop (What our C# Script will do)

When the Server tells the Client to render a 24x24x256 chunk, the mesher does this:

  1. Loops through every X, Y, Z coordinate in the chunk.
  2. Checks the 8 corners of the current voxel.
  3. Creates an 8-bit integer (a byte) based on which corners are solid (e.g., 00001111).
  4. Plugs that byte into the Triangulation Table.
  5. The table spits out a list of edges.
  6. The script calculates the exact interpolated point on those edges.
  7. It connects those points into triangles and adds them to Godot's ArrayMesh.
  8. It Marches to the next cube and repeats.