Satinderpal Singh
Satinderpal Singh

Reputation: 548

Load original lighting for glTF 3D models using three.js like sketchfab.com or windows 3D Viewer

I am facing issue in 3D Modeling.

Choose and adjust the light for every glTF 3D Model. Initially, my models look dark. But I do not want to choose light settings manually for every 3D Model. I want to know that there is any way to apply automatically light like sketchfab.com or windows 3D Viewer does. There is no need to adjust or choose the lighting while opening 3D Models in such apps.

enter image description here enter image description here

function animate() {
    this.animationFrameRef = requestAnimationFrame(this.animate.bind(this));
    this.renderer.render(this.scene, this.camera);
}
    
function init() {
    let width = this.elementRef.nativeElement.clientWidth;
    let height = this.elementRef.nativeElement.clientHeight;
    this.scene = new Scene();
    this.scene.background = new Color(0xeeeeee);
    this.camera = new PerspectiveCamera(50, width / height, .1, 2000);
    this.camera.rotation.y = 45 / 180 * Math.PI;
    this.camera.position.x = 800;
    this.camera.position.y = 100;
    this.camera.position.z = 1000;
    
    this.renderer = new WebGLRenderer({ antialias: true });
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(width, height);
    document.body.appendChild(this.renderer.domElement);
    this.controls = new OrbitControls(this.camera,this.renderer.domElement);
    
    this.controls.minDistance = 1;
    this.controls.maxDistance = 800;
    
    this.controls.enableDamping = true;
    this.controls.dampingFactor = 0.05;
    
    this.controls.update();
    
    this.hlight = new AmbientLight(null);
    this.scene.add(this.hlight);
    
    this.directionalLight = new DirectionalLight(null);
    this.directionalLight.position.set(1, 1, 0);
    this.directionalLight.castShadow = true;
    
    this.scene.add(this.directionalLight);
    
    
    let loader = new GLTFLoader();
    this.isLoading = true;
    loader.load(this.model, (gltf) => {
        var box = new Box3().setFromObject(gltf.scene);
        var center = new Vector3();
        box.getCenter(center);
        gltf.scene.position.sub(center); // center the model
        this.scene.add(gltf.scene);
    }, (xhr) => {
        console.log((xhr.loaded / xhr.total * 100) + '% loaded');
    }, (event) => {});
    
    window.addEventListener('resize', this.onWindowResize.bind(this));
    this.animate();
    }

Upvotes: 3

Views: 2089

Answers (2)

Unmeltable Ice
Unmeltable Ice

Reputation: 81

I had this problem before. My solution is Image-Based Lighting, which seems to be used on multiple online open-sourced model viewers.

Don McCurdy's glTF Viewer should help.

The viewer's source is located here. Pay attention to the usages of PMREMGenerator and Scene.environment.

This may not solve all your problems, but worth trying :)

EDITED

Mentioned by this answer, PMREMGenerator is not required in environment map procedure since r131.

So a simplified solution is:

  1. Load an HDR environment map via classes like RGBELoader or EXRLoader
  2. Put loaded texture into Scene.environment
import { Scene } from "three";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

var scene = new Scene();
var rgbeLoader = new RGBELoader();

rgbeLoader.load("/path/to/envMap.hdr", envMap => {
  scene.environment = envMap;
}, undefined, error => {
  console.error("Failed to load envMap.", error);
});

Offical Code Example:

Preview

Code

Upvotes: 1

aaadraniki
aaadraniki

Reputation: 68

class RoomEnvironment extends THREE.Scene {

    constructor() {

        super();

        const geometry = new THREE.BoxGeometry();
        geometry.deleteAttribute( 'uv' );

        const roomMaterial = new THREE.MeshStandardMaterial( { side: THREE.BackSide } );
        const boxMaterial = new THREE.MeshStandardMaterial();

        const mainLight = new THREE.PointLight( 0xffffff, 5.0, 28, 2 );
        mainLight.position.set( 0.418, 16.199, 0.300 );
        this.add( mainLight );

        const room = new THREE.Mesh( geometry, roomMaterial );
        room.position.set( - 0.757, 13.219, 0.717 );
        room.scale.set( 31.713, 28.305, 28.591 );
        this.add( room );

        const box1 = new THREE.Mesh( geometry, boxMaterial );
        box1.position.set( - 10.906, 2.009, 1.846 );
        box1.rotation.set( 0, - 0.195, 0 );
        box1.scale.set( 2.328, 7.905, 4.651 );
        this.add( box1 );

        const box2 = new THREE.Mesh( geometry, boxMaterial );
        box2.position.set( - 5.607, - 0.754, - 0.758 );
        box2.rotation.set( 0, 0.994, 0 );
        box2.scale.set( 1.970, 1.534, 3.955 );
        this.add( box2 );

        const box3 = new THREE.Mesh( geometry, boxMaterial );
        box3.position.set( 6.167, 0.857, 7.803 );
        box3.rotation.set( 0, 0.561, 0 );
        box3.scale.set( 3.927, 6.285, 3.687 );
        this.add( box3 );

        const box4 = new THREE.Mesh( geometry, boxMaterial );
        box4.position.set( - 2.017, 0.018, 6.124 );
        box4.rotation.set( 0, 0.333, 0 );
        box4.scale.set( 2.002, 4.566, 2.064 );
        this.add( box4 );

        const box5 = new THREE.Mesh( geometry, boxMaterial );
        box5.position.set( 2.291, - 0.756, - 2.621 );
        box5.rotation.set( 0, - 0.286, 0 );
        box5.scale.set( 1.546, 1.552, 1.496 );
        this.add( box5 );

        const box6 = new THREE.Mesh( geometry, boxMaterial );
        box6.position.set( - 2.193, - 0.369, - 5.547 );
        box6.rotation.set( 0, 0.516, 0 );
        box6.scale.set( 3.875, 3.487, 2.986 );
        this.add( box6 );


        // -x right
        const light1 = new THREE.Mesh( geometry, createAreaLightMaterial( 50 ) );
        light1.position.set( - 16.116, 14.37, 8.208 );
        light1.scale.set( 0.1, 2.428, 2.739 );
        this.add( light1 );

        // -x left
        const light2 = new THREE.Mesh( geometry, createAreaLightMaterial( 50 ) );
        light2.position.set( - 16.109, 18.021, - 8.207 );
        light2.scale.set( 0.1, 2.425, 2.751 );
        this.add( light2 );

        // +x
        const light3 = new THREE.Mesh( geometry, createAreaLightMaterial( 17 ) );
        light3.position.set( 14.904, 12.198, - 1.832 );
        light3.scale.set( 0.15, 4.265, 6.331 );
        this.add( light3 );

        // +z
        const light4 = new THREE.Mesh( geometry, createAreaLightMaterial( 43 ) );
        light4.position.set( - 0.462, 8.89, 14.520 );
        light4.scale.set( 4.38, 5.441, 0.088 );
        this.add( light4 );

        // -z
        const light5 = new THREE.Mesh( geometry, createAreaLightMaterial( 20 ) );
        light5.position.set( 3.235, 11.486, - 12.541 );
        light5.scale.set( 2.5, 2.0, 0.1 );
        this.add( light5 );

        // +y
        const light6 = new THREE.Mesh( geometry, createAreaLightMaterial( 100 ) );
        light6.position.set( 0.0, 20.0, 0.0 );
        light6.scale.set( 1.0, 0.1, 1.0 );
        this.add( light6 );

    }

}

function createAreaLightMaterial( intensity ) {

    const material = new THREE.MeshBasicMaterial();
    material.color.setScalar( intensity );
    return material;

}

const environment = new RoomEnvironment();
const pmremGenerator = new THREE.PMREMGenerator( renderer );
scene.environment = pmremGenerator.fromScene( environment ).texture;

renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;
renderer.outputEncoding = THREE.sRGBEncoding;

Upvotes: 1

Related Questions