From ffb5fe980014ad3376120d8dc8e20263b1f136ec Mon Sep 17 00:00:00 2001 From: superstar54 Date: Thu, 14 Nov 2024 22:34:30 +0100 Subject: [PATCH] Add green color for cap --- demo/demo.js | 4 +- src/atoms/plugins/isosurface.js | 67 ++++++++++++++++++++++----------- src/geometry/marchingCubes.js | 47 +++++++++++++++++++---- 3 files changed, 86 insertions(+), 32 deletions(-) diff --git a/demo/demo.js b/demo/demo.js index 90a3a25..42680a0 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -155,8 +155,8 @@ async function updateAtoms(filename, fileContent = null) { editor.avr.isosurfaceManager.volumetricData = cubeData.volumetricData; // editor.avr.isosurfaceManager.addSetting(0.0002); editor.avr.isosurfaceManager.fromSettings({ - positive: { isovalue: 0.00001, mode: 1, step_size: 1 }, - negative: { isovalue: -0.00001, color: "#ff0000", mode: 1 }, + positive: { isovalue: 0.00002, mode: 1, step_size: 1 }, + negative: { isovalue: -0.00002, color: "#ff0000", mode: 1 }, }); editor.avr.isosurfaceManager.drawIsosurfaces(); editor.instancedMeshPrimitive.fromSettings([]); // Clear mesh primitives diff --git a/src/atoms/plugins/isosurface.js b/src/atoms/plugins/isosurface.js index 76a1899..401a9b6 100644 --- a/src/atoms/plugins/isosurface.js +++ b/src/atoms/plugins/isosurface.js @@ -152,25 +152,29 @@ export class Isosurface { return [x, y, z]; }); - let geometry = createGeometryFromMarchingCubesOutput(isoData.positions, isoData.cells); - // Create material - // const material = new THREE.MeshBasicMaterial({ - // color: setting.color, - // transparent: true, // Make it transparent - // opacity: 0.8, // Set the transparency level (0.0 to 1.0) - // side: THREE.DoubleSide, // Render both sides - // }); - const material = new THREE.MeshStandardMaterial({ - color: colors[i], - metalness: 0.1, - roughness: 0.01, - transparent: true, // Make it transparent - opacity: 0.8, - side: THREE.DoubleSide, // Render both sides - }); + let geometry = createGeometryFromMarchingCubesOutput(isoData.positions, isoData.cells, isoData.faceMaterials); + // Create materials + const materials = [ + new THREE.MeshStandardMaterial({ + color: colors[i], + metalness: 0.1, + roughness: 0.01, + transparent: true, // Make it transparent + opacity: 0.8, + side: THREE.DoubleSide, // Render both sides + }), + new THREE.MeshStandardMaterial({ + color: "#c2f542", + metalness: 0.1, + roughness: 0.01, + transparent: true, // Make it transparent + opacity: 1, + side: THREE.DoubleSide, // Render both sides + }), + ]; // Create mesh - var mesh = new THREE.Mesh(geometry, material); + var mesh = new THREE.Mesh(geometry, materials); mesh.geometry.computeVertexNormals(); mesh.material.flatShading = false; // mesh.position.copy(setting.center); @@ -189,20 +193,39 @@ export class Isosurface { } } -function createGeometryFromMarchingCubesOutput(positions, cells) { +function createGeometryFromMarchingCubesOutput(positions, cells, faceMaterials) { /* Create a geometry from the output of the marching cubes algorithm */ var geometry = new THREE.BufferGeometry(); var vertices = []; - console.log("cells: ", cells); + var indices = []; + var indicesByMaterial = [[], []]; // Two materials: internal (0) and boundary (1) - // Convert positions and cells to vertices and indices arrays + // Convert positions to vertices array positions.forEach(function (pos) { vertices.push(pos[0], pos[1], pos[2]); }); - // Add vertices and indices to the geometry + // Add vertices to the geometry geometry.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3)); - geometry.setIndex(cells); + + // Process cells and faceMaterials to create index arrays per material + for (let i = 0; i < cells.length; i += 3) { + const materialIndex = faceMaterials[i / 3]; + indicesByMaterial[materialIndex].push(cells[i], cells[i + 1], cells[i + 2]); + } + + // Concatenate indices and set up groups + var allIndices = []; + var groupStart = 0; + for (let materialIndex = 0; materialIndex <= 1; materialIndex++) { + const indicesForMaterial = indicesByMaterial[materialIndex]; + const count = indicesForMaterial.length; + geometry.addGroup(groupStart, count, materialIndex); + allIndices = allIndices.concat(indicesForMaterial); + groupStart += count; + } + + geometry.setIndex(allIndices); // Compute normals for the lighting geometry.computeVertexNormals(); diff --git a/src/geometry/marchingCubes.js b/src/geometry/marchingCubes.js index ce442c1..6139afc 100644 --- a/src/geometry/marchingCubes.js +++ b/src/geometry/marchingCubes.js @@ -322,9 +322,12 @@ export function marchingCubes(dims, volume, bounds, isovalue, step_size = 1) { const vertices = [], faces = [], + faceMaterials = [], grid = new Array(8), edges = new Array(12), - x = [0, 0, 0]; + x = [0, 0, 0], + boundaryVertices = [], + vertexMap = new Map(); // Map to store vertex index and its boundary status // Use a default scalar value that is guaranteed to be less than the isovalue, regardless of its sign const defaultScalar = isovalue - Math.sign(isovalue || 1) * Number.MAX_VALUE; @@ -338,10 +341,9 @@ export function marchingCubes(dims, volume, bounds, isovalue, step_size = 1) { } } - // Adjust loop bounds to include boundary cubes - for (x[0] = 0; x[0] < dims[0] + step_size; x[0] += step_size) - for (x[1] = 0; x[1] < dims[1] + step_size; x[1] += step_size) - for (x[2] = 0; x[2] < dims[2] + step_size; x[2] += step_size) { + for (x[0] = -step_size; x[0] < dims[0] + step_size; x[0] += step_size) + for (x[1] = -step_size; x[1] < dims[1] + step_size; x[1] += step_size) + for (x[2] = -step_size; x[2] < dims[2] + step_size; x[2] += step_size) { let cube_index = 0; for (let i = 0; i < 8; ++i) { const v = cubeVerts[i]; @@ -359,6 +361,12 @@ export function marchingCubes(dims, volume, bounds, isovalue, step_size = 1) { for (let i = 0; i < 12; ++i) { if ((edge_mask & (1 << i)) === 0) continue; + const key = `${x[0]}_${x[1]}_${x[2]}_${i}`; + if (vertexMap.has(key)) { + edges[i] = vertexMap.get(key).index; + continue; + } + edges[i] = vertices.length; const nv = [0, 0, 0], e = edgeIndex[i], @@ -369,17 +377,40 @@ export function marchingCubes(dims, volume, bounds, isovalue, step_size = 1) { d = b - a, t = Math.abs(d) > 1e-6 ? (isovalue - a) / d : 0; + const gridPos = [0, 0, 0]; + let onBoundary = false; for (let j = 0; j < 3; ++j) { - nv[j] = scale[j] * (x[j] + p0[j] * step_size + t * (p1[j] - p0[j]) * step_size) + shift[j]; + gridPos[j] = x[j] + p0[j] * step_size + t * (p1[j] - p0[j]) * step_size; + + // Adjust the position to lie exactly on the boundary if necessary + if (gridPos[j] <= 0) { + gridPos[j] = 0; + onBoundary = true; + } + if (gridPos[j] >= dims[j] - 1) { + gridPos[j] = dims[j] - 1; + onBoundary = true; + } + + nv[j] = scale[j] * gridPos[j] + shift[j]; } vertices.push(nv); + boundaryVertices.push(onBoundary); + vertexMap.set(key, { index: edges[i], onBoundary }); } // Add faces const f = triTable[cube_index]; for (let i = 0; i < f.length; i += 3) { - faces.push(edges[f[i]], edges[f[i + 1]], edges[f[i + 2]]); + const v0 = edges[f[i]]; + const v1 = edges[f[i + 1]]; + const v2 = edges[f[i + 2]]; + faces.push(v0, v1, v2); + + // Determine if face is on the boundary + const isFaceOnBoundary = boundaryVertices[v0] && boundaryVertices[v1] && boundaryVertices[v2]; + faceMaterials.push(isFaceOnBoundary ? 1 : 0); } } - return { positions: vertices, cells: faces }; + return { positions: vertices, cells: faces, faceMaterials }; }