[SOLVED] Glb model is very dark

SOLVED :grinning:
Hey, when I load a glb model into threejs it is very dark. The problem model is good_bush.glb. It’s near the bottom of the code. It looks fine when I upload it to https://gltf-viewer.donmccurdy.com/ but it behaves weird with me. I don’t know if this is a lighting issue or a renderer settings issue. Any help is appreciated.

import * as THREE from 'three';
import * as OrbitControls from './utils/three-orbit-controls';
import GLTFLoader from 'three-gltf-loader';
import * as Stats from 'stats.js';

var stats = new Stats();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
const loader = new GLTFLoader();
const controls = new OrbitControls(camera, renderer.domElement);
const modelScale = [1, 1, 1];
const medievalScale = [0.5, 0.5, 0.5];
const lightPosition = [75, 300, -75]
const ambientLight = new THREE.AmbientLight(0xaaaaaa);
const pointLight = new THREE.DirectionalLight(0xffffff, 0.5);
const sun = new THREE.Group();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio( window.devicePixelRatio );
renderer.gammaOutput = true;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;

document.body.appendChild(renderer.domElement);
camera.position.set(0, 0, 3);
scene.background = new THREE.Color( 0x11f8bb );

sun.add(pointLight);
sun.position.set(75, 300, -75);
scene.add(sun);
scene.add(ambientLight);

//lerp and rate    > rate --> Faster the animation
controls.enableDamping = true;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3;

//show stats
stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );

loadModels();

window.addEventListener('resize', () => {
    let width = window.innerWidth;
    let height = window.innerHeight;
    renderer.setSize(width, height);
    camera.aspect = width / height;
    //update camera frustum
    camera.updateProjectionMatrix();
});

//Render --> This is works for vr
//and requestAnimationFrame doesn't
//so we'll future proof rn instead of later
renderer.setAnimationLoop( () => {
    stats.begin();
    controls.update();
    controls.runKeyBinds();
    renderer.render(scene, camera);
    stats.end();
});

function stop() {
    renderer.setAnimationLoop( null );
}

function loadModels() {
    //make a sphere around the light so we can see it
    const lightBox = new THREE.Mesh(
        new THREE.SphereBufferGeometry( 5, 32, 32 ),
        new THREE.MeshBasicMaterial({
            color: 0xffffff
        })
    );
    lightBox.position.set(3, 100, 1);
    scene.add(lightBox);

    //create ground
    let ground = new THREE.Mesh(
        new THREE.BoxBufferGeometry(200, 0, 200 ),
        new THREE.MeshStandardMaterial({
            color: 0x1d7500,
            roughness: 0.8
    }));
    ground.position.set(0, -1.75, 0);
    scene.add(ground);

    //add trees
    loader.load( "/models/tree_snub_trunk.gltf", 
        // called when the resource is loaded
        function ( gltf ) {
            const model = gltf.scene.children[0];
            model.scale.set(...modelScale);
            model.position.set(0, -1.25, 0);

            let material = model.material;
            material.flatShading = true;
            let geometry = model.geometry;
            
            for(let i = 1; i < 100; ++i) {
                const xRand = Math.random() * 200 - 100;
                const yRand = Math.random() * 200 - 100;
                const object = new THREE.Mesh(geometry, material);
                object.position.set(xRand, -1.25, yRand);
                scene.add(object);
            }
        }
    );

    loader.load( "/models/christmas_tree.gltf", 
        // called when the resource is loaded
        function ( gltf ) {
            const model = gltf.scene.children[0];
            model.scale.set(...modelScale);
            model.position.set(0, -1.25, 0);
            
            let material = model.material;
            material.flatShading = true;
            let geometry = model.geometry;
            
            for(let i = 1; i < 100; ++i) {
                const xRand = Math.random() * 200 - 100;
                const yRand = Math.random() * 200 - 100;
                const object = new THREE.Mesh(geometry, material);
                object.position.set(xRand, -1.25, yRand);
                scene.add(object);
            }
        }
    );

    loader.load( "/models/shrub2.gltf", 
        // called when the resource is loaded
        function ( gltf ) {
            const model = gltf.scene.children[0];
            model.scale.set(...modelScale);
            model.position.set(0, -1.25, 0);
            
            let material = model.material;
            material.flatShading = true;
            let geometry = model.geometry;
            
            for(let i = 1; i < 100; ++i) {
                const xRand = Math.random() * 200 - 100;
                const yRand = Math.random() * 200 - 100;
                const object = new THREE.Mesh(geometry, material);
                object.position.set(xRand, -1.25, yRand);
                scene.add(object);
            }
        }
    );

    loader.load( "/models/good_bush.glb", 
        //TODO fix this
        function ( gltf ) {
            gltf.scene.position.set(0, -1.5, 0);
            scene.add(gltf.scene);
            console.log('added bush');

        }
    );

    // //bushes
    // for(let i = 1; i < 150; ++i) {
    //     loader.load( "/models/bush_berries.gltf", 
    //         // called when the resource is loaded
    //         function ( gltf ) {
    //             let xRand = Math.random() * 200 - 100;
    //             let zRand = Math.random() * 200 - 100;
    //             gltf.scene.rotateY(Math.random() * 6.28);
    //             gltf.scene.scale.set(1.2, 1.2, 1.2);
    //             gltf.scene.position.set(xRand, -1.25, zRand);
    //             scene.add( gltf.scene );
    //         }
    //     );
    // }
}

Remove your previous light setup and try it with this:

var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
hemiLight.position.set( 0, 300, 0 );
scene.add( hemiLight );

var dirLight = new THREE.DirectionalLight( 0xffffff );
dirLight.position.set( 75, 300, -75 );
scene.add( dirLight );

You should only set WebGLRenderer.physicallyCorrectLights to true if you also apply correct units to the lights. For now, don’t set it and see if the above code improves your lighting.

1 Like

Hey I really appreciate the response, but no luck. Still looks the same. I looked at some of the gltf viewer source code and tried to copy some of it (that’s why I added physicallyCorrectLights) but yeah it didn’t change anything.

Here’s the output after the changes

04

Can you please share a live demo or small repo (as a zip file), that demonstrates the issue?

Yeah, I edited my previous comment and added the link to my firebase app

1 Like

Make sure that the model material isn’t metallic – it should have material.metalness=0. If it is metallic, it will likely need an environment map to look correct.

5 Likes

I LOVE YOU
This problem has messed with me for days.
Thank you so much.
I had to console.log the structure of the models because of the multiple meshes.
Anyways this is the winning code

loader.load( "/models/good_bush.glb", 
    function ( gltf ) {
        gltf.scene.position.set(0, -1.5, -2);
        const model = gltf.scene.children[6];
        model.children[0].material.metalness = 0;
        model.children[1].material.metalness = 0;
        scene.add(model);
    }
);
5 Likes

Why can’t ambient light or directional light be reflected when setting metallic
How to solve this without changing the light and environment map :rofl:

This is just how metallic reflectance works — it isn’t a bug, and there is no workaround. A reflective metallic surface needs details to reflect, and ambient and directional lights do not provide that. The reflected image comes from an environment map, which can be baked or generated at runtime.

1 Like