Not able to see the roughness on the non-metallic parts of the model, it looks correct in don mccurdy gltf viewer. What am I missing?

I have a model with some parts of it being metallic and others non-metallic. I have applied the environment map to get the correct reflections from the metallic parts of the model but the non metallic parts look equally reflective.

What should I do to make the non-metallic parts to appear less reflective and more rough as they are created. The model looks perfect in the Don Muccurdy’s gltf-viewer.

Please tell me what parameters do I need to change to get it right?

Left is my rendered model and right is the gltf viewer rendered model.

It’s kinda hard to say - technically the only thing you’d need to set is roughnessMap, but why it may not be working can depend on the way you’re loading and setting up the model (also maybe texture encoding.)

Could you please share the code you’re using to load the model and create its’ materials?

I have defined the pmremGenerated environment map outside this code and using it with this renderer. This is more or less the renderer, scene and light setup.

            const scene = new THREE.Scene();

            modalCamera = new THREE.PerspectiveCamera( 75, modalCanHolder.width() / 
            modalCanHolder.height(), 0.001, 100 );
            var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );

            scene.add( light );

            var light = new THREE.AmbientLight( 0x808080 ); 

            scene.add( light );
           
            var directionalLight = new THREE.DirectionalLight( 0xffffff, .3 );

            directionalLight.position.set(0,10,10)

            scene.add( directionalLight );


            modalRenderer = new THREE.WebGLRenderer({antialias: true, alpha:true});

            modalRenderer.gammaOutput = true;

            modalRenderer.gammaFactor = 2.2;

            modalRenderer.physicallyCorrectLights=true;

            modalRenderer.outputEncoding = THREE.sRGBEncoding; 

            modalRenderer.physicallyCorrectLights = true;

            modalRenderer.setSize( modalCanHolder.width(), modalCanHolder.height() );

            modalRenderer.setPixelRatio( window.devicePixelRatio );

            modalCanHolder.append( modalRenderer.domElement );

            modalRenderer.domElement.id = 'modalCanvas';

            

            cubeGenerator.update( modalRenderer );

            pmremGenerator.update( modalRenderer );

            pmremCubeUVPacker.update( modalRenderer );

            var controls = new THREE.OrbitControls( modalCamera, modalRenderer.domElement );



           var prod=products.filter((e)=>{if(e.name.split('-')[3] == selProdId)return e;})[0];


          prod.material.envMap=envMap;

          scene.add(prod);

           


            controls.update();


            const animate = function () {

                subAnimation=requestAnimationFrame( animate );

                 controls.update();

                modalRenderer.render( scene, modalCamera );

            };

            animate();

I don’t think model loading / material setup is in this code :thinking:

The model with all other assets is loaded in a different function and this model is stored in an array which is picked dynamically to show in a modal window. While loading the assets I am only setting the environment map property of the material.

     var rgbeLoader= new THREE.RGBELoader()

        .setType( THREE.UnsignedByteType )

        .setPath( 'textures/equirectangular/' )

        .load( 'pedestrian_overpass_2k.hdr', function ( texture ) {

                    cubeGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 1024 } );

                    cubeGenerator.update( renderer );

                    pmremGenerator = new THREE.PMREMGenerator( cubeGenerator.renderTarget.texture );

                    pmremGenerator.update( renderer );

                    pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods );

                    pmremCubeUVPacker.update( renderer );

                    envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture;

        var loader = new THREE.GLTFLoader();

        // loader.load( 'tfsProject3.glb', function ( gltf ) {

        loader.load( 'tfsProject4.glb', function ( gltf ) {
        scene.add(gltf.scene);
 		gltf.scene.traverse((e)=>{
              e.material.envMap=envMap;
         });

This is just a simplified code, not the exact code…

I understand, but could you please share only the part (and not simplified / modified) that load and sets the material on the object? The issue is probably in the way you’re handling it, so it’s hard to help without seeing that actual part of the code. :neutral_face:

I am not changing any material property programmatically, the model has all the embedded textures maps. I am simply loading the mesh and setting the environment map…Do you still need the code?

If you are sure it is not caused by the code - try downloading this .glb model and adding it to your application. It should look like this:


(credit Bell model by saikohq)

The app this screenshot is from does not modify the materials (just loads them), so in your case it should look similar. If it does look different, you must be modifying the materials somewhere in your code.

This is how it appears with my code. I am not changing any material properties but I might be missing some mandatory property modifications required to render the roughness correctly.

Hm, it does seem to look alright. Could you then share the model you were testing in the first post (with it’s roughness / metalness maps) ?

This is the model file.

trial2.glb (1.3 MB)

It also looks alright.

One last thing I could imagine affecting the material is the environment map or some wild lights on the scene - though I don’t think either should be causing the rough plastic part to look shiny (@donmccurdy’s gltf viewer also doesn’t do any magic besides loading the model, the envmaps there are quite similar to pedestrian_overpass_2k. :neutral_face:)

I am not defining any encoding method or roughness map programmatically, do you think that could cause this issue.

When I have not added the environment map the non-metallic parts looked perfect and the metallic parts looked black. Which called for adding the environment map to the model material, but adding that made the entire model shiny and lose the roughness that was there before.

Tried removing all the lights from the scene makes no change to the rendering. It appears as after adding the environment map to the model, it doesn’t need lights at all in the scene.

Could you try setting the environment map only globally instead on each element separately? Ie.:

scene.environment = environmentHDRITexture;

And remove all occurrences of:

someMaterial.envMap = environmentHDRITexture;

Tried. If I don’t set the environment map on the model, I get black texture on the metallic parts of the model.

That’s a sign of environment texture not loading properly (metal surfaces reflect the environment map clearly - and if the texture is not loaded, they reflect just black color.) Could you share how you set scene.environment ?

rgbeLoader.setType( THREE.UnsignedByteType )

.setPath( 'textures/equirectangular/' )

.load( 'pedestrian_overpass_2k.hdr', function ( texture ) {

cubeGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 1024 } );

cubeGenerator.update( renderer );

pmremGenerator = new THREE.PMREMGenerator( cubeGenerator.renderTarget.texture );

pmremGenerator.update( renderer );

pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( 
pmremGenerator.cubeLods );

pmremCubeUVPacker.update( renderer );

envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture;

scene.environment = envMap;

Assuming you’re using a 32-bit HDRI (from hdrihaven or similar), try replacing all that with just:

new THREE.RGBELoader()
.setDataType(THREE.UnsignedByteType)
.setPath('textures/equirectangular/')
.load('pedestrian_overpass_2k.hdr', (hdri) => {
  const pmremGenerator = new THREE.PMREMGenerator(renderer); 
  pmremGenerator.compileEquirectangularShader();

  const hdrCubeRenderTarget = pmremGenerator.fromEquirectangular(hdri);
  hdri.dispose();

  scene.environment = hdrCubeRenderTarget.texture;
});

(You don’t need to manually convert equirectangular maps to cubemaps, PMREM generator does exactly that.)

Getting error as

(index):319 Uncaught TypeError: Cannot read property ‘fromEquirectangular’ of undefined
at (index):319
at onLoadCallback (RGBELoader.js:515)
at Object.onLoad (three.js:35247)
at XMLHttpRequest. (three.js:34856)

I am using three.js release 106, maybe in that version of the scripts the properties are defined differently.

Release 106 is 2 years old. :pensive: