Frederic Perron
Frederic Perron

Reputation: 798

ThreeJS: Add Two Materials on an Mesh Object

In ThreeJS, it is possible to add more than one material to an Object3D/Mesh according to its documentation. We can use a single Material or use an array of Material:

Mesh typescript file class declaration and contructor (from ThreeJS src code):

export class Mesh<
    TGeometry extends BufferGeometry = BufferGeometry,
    TMaterial extends Material | Material[] = Material | Material[] // ### Here: Material[] ###
> extends Object3D {
    constructor(geometry?: TGeometry, material?: TMaterial);

Here is my problem which I can't seem to be able to solve... When I use a single Material, my Mesh is displayed. However, when I use two materials as an array, my Mesh won't display. I also don't have any error print out in the console when rendering the scene.

My ultimate goal here is to be able to have to separate materials for the inner and the outer part of my object. Representation of my object (using only one material)


Here is my code:

export function init(radius: number = 18.0, innerColor: number = 0xFFFFFF, outerColor: number = 0x444444) {
    var obj = new Object3D();
    loader.load(
        objPath, 
        function(object){
            obj = object;
            const mesh = obj.children[0] as Mesh;
            // WORKING:
            mesh.material = new MeshPhongMaterial({color: outerColor});
            // NOT WORKING: Using two materials
            // mesh.material = new Array<Material>(new MeshPhongMaterial({color: outerColor}), new MeshPhongMaterial({color:innerColor}));
            mesh.scale.setLength(radius)
            scene.add(mesh);
        },
        function (error){
            console.log(error)
        }
    );
}

Why can't I manage to see my object when using two materials ?

I known there was the MeshFaceMaterial in previous version and the material array acceptance of the contructor is supposed to be a replacement for that in some sens.


ThreeJS version: r128

Any help would be appreciated !

Upvotes: 0

Views: 1212

Answers (1)

M -
M -

Reputation: 28482

The easiest way is to clone your mesh and assign two separate materials, one for the inside, another for the outside:

const meshOuter = obj.children[0] as THREE.Mesh;
const meshInner = meshOuter.clone();

// Outer mesh shows front side
meshOuter.material = new THREE.MeshPhongMaterial({
    color: outerColor,
    side: THREE.FrontSide
});
// Inner mesh shows back side
meshInner.material = new THREE.MeshPhongMaterial({
    color: innerColor,
    side: THREE.BackSide
});

// Scale inner mesh down just a bit to avoid z-fighting
meshInner.scale.multiplyScalar(0.99);

Upvotes: 1

Related Questions