Penguinator
Penguinator

Reputation: 641

Three.js removing inner faces

I am merging multiple cubes into different block shapes with three.js using THREE.GeometryUtils.merge. I want to make these block shapes transparent, but when it's transparent you can see that it's multiple cubes stuck together like this:

merged cubes

How do I make my merged cubes transparent without rendering the inside edges? (how do I remove the inner faces?)

My code that merges the cubes:

geometry = new THREE.CubeGeometry(STEP_SIZE, STEP_SIZE, STEP_SIZE);
for (i = 0; i < shape.length; i++) {
    tmpGeometry =  new THREE.Mesh(new THREE.CubeGeometry(STEP_SIZE, STEP_SIZE, STEP_SIZE));
    tmpGeometry.position.x = STEP_SIZE * shape[i].x;
    tmpGeometry.position.y = STEP_SIZE * shape[i].y;
    THREE.GeometryUtils.merge(geometry, tmpGeometry);
}

block = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 0x0000ff, opacity: 0.5, transparent: true }));

Upvotes: 2

Views: 3939

Answers (2)

Penguinator
Penguinator

Reputation: 641

After some experimenting I finally got what I wanted. Hope this will help other people.

I go through each face of the block and raycast the block itself using the face's centroid and inverted normal (so that the normal points inward). If it intersects with another face that's part of the block, we know that that face is an inner face and we can go ahead and remove it.

// block is a Three.Mesh object
function removeInternalFaces(block) {
    var geometry = block.geometry;
    var face;
    var toDelete = [];
    var blockRaycaster = new THREE.Raycaster();

    // raycast itself from the center of each face (negated normal), and whichever face gets intersected
    // is an inner face
    for (i = 0; i < geometry.faces.length; i++) {
        face = geometry.faces[i];
        if (face) {
            normal = face.normal.clone();
            normal.negate();
            blockRaycaster.set(face.centroid, normal);
            intersects = blockRaycaster.intersectObject(block);
            for (j = 0; j < intersects.length; j++) {
                toDelete.push(intersects[j].faceIndex);
            }
        }
    }

    // actually delete them
    for (i = 0; i < toDelete.length; i++) {
        delete geometry.faces[toDelete[i]];
    }
    geometry.faces = geometry.faces.filter( function(v) { return v; });
    geometry.elementsNeedUpdate = true; // update faces
}

Upvotes: 4

Shiva
Shiva

Reputation: 6887

You can actually initialize cube's each face material separately and individually set the opacity of the inner faces to 0. The Code will be something like this.

    var materialArray = [];

        materialArray.push(new THREE.MeshLambertMaterial({
            opacity:0,
            color:0x0000FF,
            transparent: true
        }));// assuming you want this face to be transparent 
        materialArray.push(new THREE.MeshLambertMaterial({
            opacity:0,
            color:0x0000FF,
            transparent: true
        }));// assuming you want this face to be transparent
        materialArray.push(new THREE.MeshLambertMaterial({
            opacity:0.5,
            color:0x0000FF,
            transparent: true
        }));
        materialArray.push(new THREE.MeshLambertMaterial({
            opacity:0.5,
            color:0x0000FF,
            transparent: true
        }));
        materialArray.push(new THREE.MeshLambertMaterial({
            opacity:0.5,
            color:0x0000FF,
        transparent: true
        }));
        materialArray.push(new THREE.MeshLambertMaterial({
            opacity:0.5,
            color:0x0000FF,
            transparent: true
        }));
        var CubeMat = new THREE.MeshFaceMaterial(materialArray);

and pass this to your cube mesh something like this.

block = new THREE.Mesh(geometry,CubeMat )

check this JsFiddle for a demo

Upvotes: 1

Related Questions