//========================================= // ===== BASICS BOTH FUNCTIONS NEED ===== //========================================= function getCubeIndex(x, y, z) { let cubeIndex = 0; if (grid[x][y][z]) cubeIndex |= 1; if (grid[x + 1][y][z]) cubeIndex |= 2; if (grid[x + 1][y][z + 1]) cubeIndex |= 4; if (grid[x][y][z + 1]) cubeIndex |= 8; if (grid[x][y + 1][z]) cubeIndex |= 16; if (grid[x + 1][y + 1][z]) cubeIndex |= 32; if (grid[x + 1][y + 1][z + 1]) cubeIndex |= 64; if (grid[x][y + 1][z + 1]) cubeIndex |= 128; return cubeIndex; } function getEdgeVertices(x, y, z, edgeIndex) { const edgeOffsets = EDGE_OFFSETS[edgeIndex]; const v1 = [x + edgeOffsets[0], y + edgeOffsets[1], z + edgeOffsets[2]]; const v2 = [x + edgeOffsets[3], y + edgeOffsets[4], z + edgeOffsets[5]]; return [v1, v2]; } function interpolateVertex(v1, v2, threshold, val1, val2) { const t = (threshold - val1) / (val2 - val1); const x = v1[0] + (v2[0] - v1[0]) * t; const y = v1[1] + (v2[1] - v1[1]) * t; const z = v1[2] + (v2[2] - v1[2]) * t; return [x, y, z]; } const EDGE_OFFSETS = [ [0, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 1], [0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 1], [0, 1, 0, 1, 1, 0], [1, 1, 0, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 1, 1], [0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 1, 0], [1, 0, 1, 1, 1, 1], [0, 0, 1, 0, 1, 1] ]; const TRIANGLE_TABLE = [ [-1], [0, 8, 3, -1], [0, 1, 9, -1], [1, 8, 3, 9, 8, 1, -1], [1, 2, 10, -1], [0, 8, 3, 1, 2, 10, -1], [9, 2, 10, 0, 2, 9, -1], [2, 8, 3, 2, 10, 8, 10, 9, 8, -1], [3, 11, 2, -1], [0, 11, 2, 8, 11, 0, -1], [1, 9, 0, 2, 3, 11, -1], [1, 11, 2, 1, 9, 11, 9, 8, 11, -1], [3, 10, 1, 11, 10, 3, -1], [0, 10, 1, 0, 8, 10, 8, 11, 10, -1], [3, 9, 0, 3, 11, 9, 11, 10, 9, -1], [9, 8, 10, 10, 8, 11, -1], [4, 7, 8, -1], [4, 3, 0, 7, 3, 4, -1], [0, 1, 9, 8, 4, 7, -1], [4, 1, 9, 4, 7, 1, 7, 3, 1, -1], [1, 2, 10, 8, 4, 7, -1], [3, 4, 7, 3, 0, 4, 1, 2, 10, -1], [9, 2, 10, 9, 0, 2, 8, 4, 7, -1], [2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1], [8, 4, 7, 3, 11, 2, -1], [11, 4, 7, 11, 2, 4, 2, 0, 4, -1], [9, 0, 1, 8, 4, 7, 2, 3, 11, -1], [4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1], [3, 10, 1, 3, 11, 10, 7, 8, 4, -1], [1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1], [4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1], [4, 7, 11, 4, 11, 9, 9, 11, 10, -1], [9, 5, 4, -1], [9, 5, 4, 0, 8, 3, -1], [0, 5, 4, 1, 5, 0, -1], [8, 5, 4, 8, 3, 5, 3, 1, 5, -1], [1, 2, 10, 9, 5, 4, -1], [3, 0, 8, 1, 2, 10, 4, 9, 5, -1], [5, 2, 10, 5, 4, 2, 4, 0, 2, -1], [2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1], [9, 5, 4, 2, 3, 11, -1], [0, 11, 2, 0, 8, 11, 4, 9, 5, -1], [0, 5, 4, 0, 1, 5, 2, 3, 11, -1], [2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1], [10, 3, 11, 10, 1, 3, 9, 5, 4, -1], [4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1], [5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1], [5, 4, 8, 5, 8, 10, 10, 8, 11, -1], [9, 5, 7, 9, 7, 8, -1], [0, 9, 5, 0, 5, 3, 3, 5, 7, -1], [8, 0, 7, 0, 1, 7, 1, 5, 7, -1], [1, 5, 3, 3, 5, 7, -1], [9, 5, 8, 8, 5, 7, 10, 1, 2, -1], [10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1], [8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1], [2, 10, 5, 2, 5, 3, 3, 5, 7, -1], [7, 9, 5, 7, 8, 9, 3, 11, 2, -1], [9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1], [2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1], [11, 2, 1, 11, 1, 7, 7, 1, 5, -1], [9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1], [5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, -1], [11, 0, 3, 11, 10, 0, 10, 9, 0, 10, 5, 9, 7, 11, 9, -1], [5, 7, 8, 5, 8, 10, 10, 8, 11, -1], [9, 5, 4, 4, 5, 7, 7, 5, 6, -1], [9, 5, 4, 9, 4, 6, 9, 6, 1, 6, 4, 7, -1], [1, 6, 4, 1, 4, 9, 1, 9, 2, 9, 4, 7, -1], [6, 4, 7, 1, 6, 7, 1, 7, 3, 3, 7, 9, -1], [4, 6, 8, 4, 7, 6, 0, 9, 5, -1], [0, 6, 8, 0, 7, 6, 0, 1, 7, 1, 6, 4, -1], [7, 6, 9, 7, 9, 4, 3, 11, 2, -1], [9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1], [6, 8, 4, 11, 6, 4, 11, 4, 1, 1, 4, 0, -1], [6, 7, 4, 1, 6, 4, 1, 4, 0, 0, 4, 8, -1], [7, 10, 6, 7, 8, 10, 8, 9, 10, -1], [0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1], [10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1], [10, 6, 7, 10, 7, 1, 1, 7, 3, -1], [1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1], [2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, -1], [7, 8, 0, 7, 0, 6, 6, 0, 2, -1], [7, 3, 2, 6, 7, 2, 6, 2, 8, 6, 8, 9, -1], [9, 2, 6, 9, 1, 2, 9, 0, 1, 8, 9, 6, 7, 9, -1], [6, 7, 10, 7, 1, 10, 7, 3, 1, -1], [6, 7, 10, 10, 7, 1, 10, 1, 0, -1], [6, 7, 10, 10, 7, 1, 10, 1, 0, 7, 3, 1, -1], [6, 7, 8, 8, 7, 0, -1], [7, 6, 0, 0, 6, 8, -1], [-1] ]; //========================================= //========================================= function marchingCubes1(data, threshold) { const vertices = []; const faces = []; const sizeX = data.length; const sizeY = data[0].length; const sizeZ = data[0][0].length; const grid = new Array(sizeX); for (let i = 0; i < sizeX; i++) { grid[i] = new Array(sizeY); for (let j = 0; j < sizeY; j++) { grid[i][j] = new Array(sizeZ); for (let k = 0; k < sizeZ; k++) { grid[i][j][k] = 0; } } } for (let x = 0; x < sizeX; x++) { for (let y = 0; y < sizeY; y++) { for (let z = 0; z < sizeZ; z++) { grid[x][y][z] = data[x][y][z] < threshold ? 0 : 1; } } } for (let x = 0; x < sizeX - 1; x++) { for (let y = 0; y < sizeY - 1; y++) { for (let z = 0; z < sizeZ - 1; z++) { const cubeIndex = getCubeIndex(x, y, z, grid); if (cubeIndex === 0 || cubeIndex === 255) { continue; } const edgeIndices = EDGE_TABLE[cubeIndex]; for (let i = 0; i < 16; i++) { if (edgeIndices & (1 << i)) { const [v1, v2] = getEdgeVertices(x, y, z, i); const interpolatedVertex = interpolateVertex( v1, v2, threshold, grid[x][y][z], grid[x + EDGE_OFFSETS[i][0]][y + EDGE_OFFSETS[i][1]][ z + EDGE_OFFSETS[i][2] ] ); vertices.push(interpolatedVertex); } } for (let i = 0; TRIANGLE_TABLE[cubeIndex][i] !== -1; i += 3) { const v1 = vertices.length - 3 - TRIANGLE_TABLE[cubeIndex][i + 2] * 3; const v2 = vertices.length - 3 - TRIANGLE_TABLE[cubeIndex][i + 1] * 3; const v3 = vertices.length - 3 - TRIANGLE_TABLE[cubeIndex][i] * 3; faces.push([v1, v2, v3]); } } } } return { vertices, faces }; } //==================================================================== function marchingCubes2(grid, threshold) { const triangles = []; const size = grid.length; for (let x = 0; x < size - 1; x++) { for (let y = 0; y < size - 1; y++) { for (let z = 0; z < size - 1; z++) { const cubeIndex = getCubeIndex(x, y, z, grid, threshold); if (cubeIndex === 0 || cubeIndex === 255) { continue; } const edgeIndices = EDGE_TABLE[cubeIndex]; for (let i = 0; i < edgeIndices.length; i += 3) { const edgeIndex1 = edgeIndices[i]; const edgeIndex2 = edgeIndices[i + 1]; const edgeIndex3 = edgeIndices[i + 2]; const v1 = getEdgeVertices(x, y, z, edgeIndex1); const v2 = getEdgeVertices(x, y, z, edgeIndex2); const v3 = getEdgeVertices(x, y, z, edgeIndex3); const val1 = grid[v1[0]][v1[1]][v1[2]]; const val2 = grid[v2[0]][v2[1]][v2[2]]; const val3 = grid[v3[0]][v3[1]][v3[2]]; const vertex1 = interpolateVertex(v1, v2, threshold, val1, val2); const vertex2 = interpolateVertex(v2, v3, threshold, val2, val3); const vertex3 = interpolateVertex(v3, v1, threshold, val3, val1); triangles.push(vertex1, vertex2, vertex3); } } } } return triangles; } //========================================================================= // Define and implement the getCubeIndex, getEdgeVertices, and interpolateVertex functions // Define and provide the EDGE_TABLE array /* The main difference between the `marchingCubes1` and `marchingCubes2` functions is how they handle the grid representation and how they store and return the resulting geometry. In `marchingCubes1`, the function takes a three-dimensional `data` array as input, where `data[x][y][z]` represents the value at position `(x, y, z)` in the grid. The function first creates a grid of the same size as the data array and initializes it with zeros. Then, it loops over each position in the data array and sets the corresponding value in the grid based on the threshold. Finally, it performs the marching cubes algorithm on the grid, extracting the vertices and faces, and returns them as separate arrays. In `marchingCubes2`, the function takes a pre-defined `grid` as input. The grid is already populated with values, and the function assumes that `grid[x][y][z]` represents the value at position `(x, y, z)` in the grid. The function directly performs the marching cubes algorithm on the provided grid, extracting the vertices and storing them in a single array called `triangles`. In terms of the resulting geometry, `marchingCubes1` returns the vertices and faces as separate arrays, while `marchingCubes2` returns a single array (`triangles`) that contains the vertices of the resulting triangles. Here are the main differences summarized: - `marchingCubes1` takes a three-dimensional `data` array as input, initializes a grid based on the data, and returns vertices and faces as separate arrays. - `marchingCubes2` takes a pre-defined `grid` as input and directly performs the marching cubes algorithm on the grid, returning a single array (`triangles`) containing the vertices of the resulting triangles. The choice between the two functions depends on how you represent and handle your grid data. If you have a pre-defined grid, `marchingCubes2` may be more suitable. If you have a data array and want to generate the grid within the function, `marchingCubes1` can be a better option. Let me know if you need further clarification! */