Issue
I am using three-csg (import CSG from '../../csg/three-csg') to perform Boolean unions on multiple meshes (created by extrude geometries). However, when I generate edges using THREE.EdgesGeometry, the final mesh still contains edges from the original meshes instead of showing only the correct outer edges of the unioned mesh.
Example Workflow:
1. Mesh1, Mesh2, Mesh3 → Three separate meshes
2. Union Step 1
const goodMesh1 = CSG.union(mesh1, mesh2);
Union Step 2:
const finalMesh = CSG.union(goodMesh1, mesh3);
4. Generating Edges:
const edges = new THREE.EdgesGeometry(finalMesh.geometry);
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
const edgeLines = new THREE.LineSegments(edges, lineMaterial);
scene.add(edgeLines);
Problem: The generated edges include those of mesh1 and mesh2, instead of showing only the correct outer edges of finalMesh.
Thing we tried
Custom OutlinePass (library)
Increased threshold values for angle detection in EdgesGeometry.
Converted geometry to non-indexed (geometry.toNonIndexed()).
4.Tested with async function to wait for complete union operations
Use mergeVertices
used finalMesh.geometry.computeVertexNormals();
Question:
How can I ensure that EdgesGeometry only generates the correct external edges after a CSG.union() operation using three-csg? Is there a way to remove internal faces before generating edges?
Any insights would be appreciated! Thanks
When you did mergeVertices, did you remove the uv and normal attributes first?
jaxx_sparrow:
three-csg
Before you get too deep into three-csg , try to use Manifold - the most fast/robust CSG JS library.
Not long ago I explored all JS CSG solutions for my present GemDesign project and found that Manifold is the best.
Here is example how to use it from Three.js: Manifold - three.js Example
Hi Manthrax, tried this solution still no difference.
the line is still visible.
below is the code for reference
handleAngleBlunt(edge, opposingEdge, part) {
const { edgeOutwardNormal, opposingEdgeOutwardNormal, angleBetween } = this.determineAngleBetweenEdgesCoreGeometry(edge, opposingEdge)
const angleValidation = (180 - angleBetween) < 89 || (180 - angleBetween) > 91
let bspCornerNext = null
let opposingNextEdge = null
let opposingNextEdgeCore = null
const cornerVertices= this.createCorner(edge, opposingEdge, edgeOutwardNormal, opposingEdgeOutwardNormal, part.inputOrientationUI[0])
const cornerGeom = new THREE.ExtrudeGeometry(new THREE.Shape(cornerVertices), { bevelEnabled: false, depth: edge.layerOccupation.height })
if(opposingEdge.nextEdge && opposingEdge.nextEdge.originalgeometry) {
const nextCorner = this.createCornerGeometry(opposingEdge,opposingEdge.nextEdge, part)
const cornerMeshNext = this.createMesh(nextCorner)
const opposingNext =this.createTransformedMesh(opposingEdge.nextEdge.originalgeometry,opposingEdge.nextEdge.originalMatrix, opposingEdge.nextEdge.originalgeometry.isCsg)
const opposingNextCore =this.createTransformedMesh(opposingEdge.nextEdge.coreGeometry,opposingEdge.nextEdge.coreMatrix, opposingEdge.nextEdge.coreGeometry.isCsg)
bspCornerNext = CSG.fromMesh(cornerMeshNext)
opposingNextEdge = CSG.fromMesh(opposingNext)
opposingNextEdgeCore = CSG.fromMesh(opposingNextCore)
opposingEdge.nextEdge.originalgeometry.isCsg = true
opposingEdge.nextEdge.coreGeometry.isCsg = true
}
const cornerMesh = this.createMesh(cornerGeom)
const edgeMesh = this.createTransformedMesh(edge.coreGeometry,edge.coreMatrix,edge.coreGeometry.isCsg)
const oppEdgeMesh =this.createTransformedMesh(opposingEdge.originalgeometry,opposingEdge.originalMatrix, opposingEdge.originalgeometry.isCsg)
const extendedEdgeMesh =this.createTransformedMesh(opposingEdge.coreGeometry,opposingEdge.coreMatrix,opposingEdge.coreGeometry.isCsg)
const extendedEdgeMeshWithoutCSG =this.createTransformedMesh(opposingEdge.originalgeometryWithoutCsg, opposingEdge.coreMatrix, true)
const bspCornerMesh = CSG.fromMesh(cornerMesh)
const bspEdgeMesh = CSG.fromMesh(edgeMesh)
const bspOppEdgeMesh = CSG.fromMesh(oppEdgeMesh)
const bspExtendedEdgeMesh = CSG.fromMesh(extendedEdgeMesh)
const bspExtendedEdgeMeshWithoutCSG = CSG.fromMesh(extendedEdgeMeshWithoutCSG)
opposingEdge.originalgeometry.isCsg = true
if ((180 - angleBetween) > 91 ) {
// find intersector with next edge and current edge
const bspIntersector = bspMeshNext.intersect(bspEdgeMesh)
const finalMesh = bspIntersector.union(bspCornerMesh)
let bspUnion = finalMesh.union(bspOppEdgeMesh)
let finalMeshNextEdge = bspUnion
const nextEdge = this.convertToMesh(finalMeshNextEdge)
const currentEdge = this.convertToMesh(finalMeshCurrentEdge)
nextEdge.geometry.deleteAttribute('uv');
nextEdge.geometry.deleteAttribute('normal');
// currentEdge.geometry.deleteAttribute('uv');
//currentEdge.geometry.deleteAttribute('normal');
mergeVertices(nextEdge.geometry);
mergeVertices(currentEdge.geometry);
// Recompute normals for better shading
nextEdge.geometry.computeVertexNormals();
currentEdge.geometry.computeVertexNormals();
// Update opposingEdge's coreGeometry
const opposingGeometry = nextEdge.geometry
opposingEdge.coreGeometry = opposingGeometry
// Update currentEdge's coreGeometry
const edgeGeometry = currentEdge.geometry
edge.coreGeometry = edgeGeometry
}
}
createTransformedMesh(geometry, matrix, isCsg = false) {
const mesh = this.createMesh(geometry)
if(!isCsg) mesh.geometry.applyMatrix4(matrix)
return mesh
}
createMesh(geometry) {
return new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: new THREE.Color('green') }))
}
Thanks yesbird for you time will try this and get back to you .
I had the similar issue and increasing subdivision was the cure, then I switched to Manifold to increase performance, details are here:
I am trying to apply wireframe on result of CSG subtract operation, library is THREE-CSGMesh by @manthrax (btw, many thanks for this port).
Doing it this way I am getting strange artifact (please see attached image).
wireframe = new THREE.LineSegments(
new THREE.EdgesGeometry( mesh.geometry, 1 ),
new THREE.LineBasicMaterial( { color: 0x888888, linewidth: 2 } ) );
scene.add(wireframe);
[image]
Examining this mesh in console I found nothing special, so I am completely sta…
mergeVertices returns a new geometry.. it doesn’t merge in place.
And you need to mergeVertices Before you do the CSG.. to make the mesh more watertight/manifold, which is the whole point.
(Not saying its guaranteed to work… but doing it after the fact, and not using the result definitely won’t work. )
I suspect you will have the same issues with manifold or mesh-bvh-csg unless you clean up the input meshes.