Vertices missing on csg intersection

Hi, i can create a mesh on overlaped areas between different models, but still some vertices are missing on the created mesh, as i used three-mesh-bvh library and inbuilt INTERSECTION operation in it. If we consider two meshes, slightly touched (not overlaped) areas are not creating a intersecting mesh. how can i increase accuracy and what specific factors to be considered.

Input meshes need to be manifold and watertight. ( not strictly a requirement but strongly advised )

( and even then there is no guarantee that CSG will work in all cases. It’s a complex algorithm with numerous edge cases. Some implementations are more or less robust, but the more robust ones are generally much slower. )

    if (models.length < 2) return;

    const evaluator = new Evaluator();
    const Intersectionmeshes = [];
    const nonIntersectionMeshes = [];

    for (let i = 0; i < meshModels.length; i++) {
        for (let j = i + 1; j < meshModels.length; j++) {
            const meshA = meshModels[i];
            const meshB = meshModels[j];
            let geometryA = meshA.geometry.clone();
            let geometryB = meshB.geometry.clone();

      
            geometryA = weldVertices(geometryA);
            geometryB = weldVertices(geometryB);

            if (!geometryA.attributes.uv) {
                const uvArray = new Float32Array(geometryA.attributes.position.count * 2);
                geometryA.setAttribute('uv', new THREE.BufferAttribute(uvArray, 2));
            }
            geometryA.computeVertexNormals();

            if (!geometryB.attributes.uv) {
                const uvArray = new Float32Array(geometryB.attributes.position.count * 2);
                geometryB.setAttribute('uv', new THREE.BufferAttribute(uvArray, 2));
            }
            geometryB.computeVertexNormals();

            if (!geometryA || !geometryB) {
                console.error("Invalid geometry for intersection.");
                continue;
            }

            (geometryA as any).computeBoundsTree();
            (geometryB as any).computeBoundsTree();

            const brushA = new Brush(geometryA);
            const brushB = new Brush(geometryB);

           
            const resultBrush = evaluator.evaluate(brushA, brushB, INTERSECTION);
            if (!resultBrush) {
                console.error("CSG operation returned a null or undefined result.");
                return;
            }

            if (resultBrush.geometry && resultBrush.geometry.attributes.position.count > 0) {
                const parentPriorityA = getParentPriority(meshA.name);
                const parentPriorityB = getParentPriority(meshB.name);

                let chosenColor;
                if (parentPriorityA < parentPriorityB) {
                    chosenColor = meshA.material.color.getHex();
                } else {
                    chosenColor = meshB.material.color.getHex();
                }

                const material = new THREE.MeshStandardMaterial({
                    color: chosenColor,
                    transparent: true,
                    depthTest: false,
                    depthWrite: false,
                    side: THREE.DoubleSide,
                    clippingPlanes: clippingPlanes,
                });

                const resultMesh = new Mesh(resultBrush.geometry, material);
                Intersectionmeshes.push(resultMesh);

               
                const edgesGeometry = new THREE.EdgesGeometry(resultBrush.geometry);
                const edgesMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
                const edges = new THREE.LineSegments(edgesGeometry, edgesMaterial);
                groupRef.current?.add(edges); 

                const nonIntersectBrushA = evaluator.evaluate(brushA, resultBrush, SUBTRACTION);
                const nonIntersectBrushB = evaluator.evaluate(brushB, resultBrush, SUBTRACTION);

                if (nonIntersectBrushA.geometry && nonIntersectBrushA.geometry.attributes.position.count > 0) {
                    const nonIntersectMaterialA = new THREE.MeshStandardMaterial({
                        color: 0x808080,
                    });
                    const nonIntersectMeshA = new THREE.Mesh(nonIntersectBrushA.geometry, nonIntersectMaterialA);
                    nonIntersectionMeshes.push(nonIntersectMeshA);
                }

                if (nonIntersectBrushB.geometry && nonIntersectBrushB.geometry.attributes.position.count > 0) {
                    const nonIntersectMaterialB = new THREE.MeshStandardMaterial({
                        color: 0x808080,
                    });
                    const nonIntersectMeshB = new THREE.Mesh(nonIntersectBrushB.geometry, nonIntersectMaterialB);
                    nonIntersectionMeshes.push(nonIntersectMeshB);
                }
            } else {
                console.warn(`Empty or invalid result geometry after intersection between models ${i} and ${j}.`);
            }
        }
    }

    if (Intersectionmeshes.length > 0) {
        Intersectionmeshes.forEach(mesh => groupRef.current?.add(mesh));
        setEdgeIntersections(Intersectionmeshes);
        nonIntersectionMeshes.forEach(mesh => groupRef.current?.add(mesh));
        setnonIntersectionMesh(nonIntersectionMeshes);
    }
   



function weldVertices(geometry: THREE.BufferGeometry): THREE.BufferGeometry {
  
    geometry = geometry.toNonIndexed();
    const positionAttribute = geometry.attributes.position as THREE.BufferAttribute;
    const vertexMap: Record<string, number[]> = {};

    for (let i = 0; i < positionAttribute.count; i++) {
        const vertex = new THREE.Vector3(
            positionAttribute.getX(i),
            positionAttribute.getY(i),
            positionAttribute.getZ(i)
        );
        const key = `${vertex.x.toFixed(5)}_${vertex.y.toFixed(5)}_${vertex.z.toFixed(5)}`;

        if (!vertexMap[key]) {
            vertexMap[key] = [];
        }
        vertexMap[key].push(i);
    }

    Object.values(vertexMap).forEach((indices: number[]) => {
        if (indices.length > 1) {
            const averageVertex = new THREE.Vector3();
            indices.forEach(index => {
                averageVertex.add(new THREE.Vector3(
                    positionAttribute.getX(index),
                    positionAttribute.getY(index),
                    positionAttribute.getZ(index)
                ));
            });
            averageVertex.divideScalar(indices.length);
            indices.forEach(index => {
                positionAttribute.setXYZ(index, averageVertex.x, averageVertex.y, averageVertex.z);
            });
        }
    });

    geometry.computeVertexNormals();

    return geometry;
}

This what i have done for csg intersection, still needs some optimization. Should i need to use GitHub - elalish/manifold: Geometry library for topological robustness for manifold and watertight

Oooh cool… I haven’t seen that library before. Sounds promising especially if it’s used in openscad, etc. Probably worth a shot?

If i want to go with three.js, other than opencascade how can i proceed with manifold @manthrax

I only know of three-mesh-bvh-csg,
that new one you just posted,
and one that I maintain that is a bit old and creaky…
https://manthrax.github.io/THREE-CSGMesh/demos/CSGShinyDemo.html