How can I get metal material of my model rendered properly?

Hi everyone here is my scene:

I have my first try on threejs recently, attempting to render some gltf2 models in my demo. However, the metal material in my models cannot be rendered properly simply by following examples on GitHub.

There are some websites that can get exactly the same model rendered properly. Here’s the screenshot.

https://gltf.insimo.com/ :

my demo screenshot:

As you can see, the mount part should have been rendered like stainless steel. Does anyone have any idea how can I fix this? thx :slight_smile:

I have tried to add env map to my model scene, but that didn’t work.

    // env and envMap
    const textureCube = new CubeTextureLoader().load(this.environment);
    textureCube.format = RGBFormat;
    this.scene.background = textureCube;
    this.scene.environment = textureCube;
    const geometry = new SphereBufferGeometry(400.0, 48, 24);
    const material = new MeshPhysicalMaterial({
        metalness: 1,
        clearcoat: 1.0,
        envMap: textureCube
    });
    const mesh = new Mesh(geometry, material);
    this.scene.add(mesh);

As for the model loading part, I did not do much programming though (the simplest way) :smiley:

    const loader = new GLTFLoader();

    loader.load(
        this.loadPath,
        (gltf) => {

            const scene = gltf.scene || gltf.scenes[0];
            const clips = gltf.animations || [];

            if (!scene) {

                // Valid, but not supported by this viewer.
                throw new Error(
                    'This model contains no scene, and cannot be viewed here. However,' +
                        ' it may contain individual 3D resources.'
                );

            }

            this.setContent(scene, clips);

        });
    setContent (object, clips) {
         .........

         this.controls.enabled = true;
         this.controls.saveState();

         this.scene.add(object);
         this.content = object;
    }

Before you get your hands on MeshPhysicalMaterial, please setup your scene like in this demo.

Meaning you use PMREMGenerator in order to preprocess the environment map before applying it Scene.environment and Scene.background. This is more or less mandatory when using a PBR material.

Thanks for the reply! Actually, I have tried to follow this demo, but it still doesn’t work ethier. :cry:

Here’s my functions:

 updateEnvironment () {

    const hdr = './common/assets/backgrouds/royal_esplanade_1k.hdr';

    this.getCubeMapTexture(hdr).then(({ envMap }) => {

        this.scene.environment = envMap;
        this.scene.background = envMap;
        const geometry = new SphereBufferGeometry(400.0, 48, 24);
        const material = new MeshPhysicalMaterial({
            metalness: 1,
            clearcoat: 1.0,
            envMap: hdr
        });
        const mesh = new Mesh(geometry, material);
        this.scene.add(mesh);
        this.renderer.render(this.scene, this.camera);

    });

}

getCubeMapTexture (path) {

    if (!path) return Promise.resolve({ envMap: null });

    return new Promise((resolve, reject) => {

        new RGBELoader()
            .setDataType(UnsignedByteType)
            .load(path, (texture) => {

                const envMap = this.pmremGenerator.fromEquirectangular(texture).texture;
                texture.dispose();
                this.pmremGenerator.dispose();

                resolve({ envMap });

            }, undefined, reject);

    });

}

Can you please describe in more detail what you mean with “does not work”? Are the reflections too dull similar to your screenshot?

It does not make sense to configure clearcoat if you are not using a respective normal map. Besides, you should not add hdr to MeshPhysicalMaterial.envMap if you configure Scene.environment.The texture hdr is wrong in any event since it is not preprocessed with PMREMGenerator. Try it with this material:

const material = new MeshStandardMaterial( {
    metalness: 1,
    roughness: 0
} );

Thanks Mugen.

Yes, I just want my model to be rendered more real like the first image, whose metal part is rendered exactly the way before it was exported from those modeling tools.

And I am trying to solve my problem through reflecting environment on my model. Not sure whether this is the right way through. :grinning:

Something’s not right when I try to do this rendering. I tried a few more ways today to improve my rendering result, including

transversely add envMap to the model materials
(hint from this link: Best practices to export and import GLB file to render metals and textures);

using different envMap which was built from a cube;

However, the mount part still looks aluminum-like rather than stainless-steel-like(pics bellow). What should I do now :crazy_face:


Now my code looks like this:

preConfig () {

    // create scene
    this.scene = new Scene();

    // camera setting
    // FOV means field of view
    const FOV = 0.8 * 180 / Math.PI;
    this.camera = new PerspectiveCamera(FOV, this.el.clientWidth / this.el.clientHeight, 0.01, 1000);
    this.scene.add(this.camera);

    // env and envMap
    const textureCube = new CubeTextureLoader().load(this.environment);
    textureCube.format = RGBFormat;
    this.envMap = textureCube;
    this.scene.background = textureCube;
    this.scene.environment = textureCube;
    const geometry = new SphereBufferGeometry(400.0, 48, 24);
    const material = new MeshStandardMaterial({
        metalness: 1,
        roughness: 0


 });

    .....
}
setContent() {
// do this in gltf loader callback
 object.traverse((node) => {

        if (node.material && (node.material.isMeshStandardMaterial ||
                              (node.material.isShaderMaterial && node.material.envMap !== undefined))) {

            node.material.envMap = this.envMap;
            node.material.envMapIntensity = 0.7;

        }

    });
}