Using Blender lighting in Three JS or easy way to put shadows in a 3D Model

So, I have a glb scene of a florest, and I’m loading it into Three JS. The problem is, with a hemispherical lighting, it casts no shadows from the threes, rocks and all. It’s just a plane scene withou shadows. How could I fix this? I thought that I could do the lighting stuff in Blender and then export it and just render in Three JS, but I couldn’t do it. Can someone help me? I’m going to leave the code and some pics here!

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import {OrbitControls} from "three/addons/controls/OrbitControls";

// Classe para o personagem
class Character {
  constructor(path) {
    this.path = path;
    this.model = null;
    this.mixer = null;
    this.clips = null;
    

    const loader = new GLTFLoader();
    loader.load(this.path, (gltf) => {
      this.model = gltf.scene;



      this.mixer = new THREE.AnimationMixer(this.model);
      this.clips = gltf.animations;
    })
  }

  getModel() {
    return this.model;
  }

  update(deltaTime) {
    if (this.mixer) {
      this.mixer.update(deltaTime);
    }
  }
}

// Configuração da cena Three.js
const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, -20, 5);

const clock = new THREE.Clock()

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);

renderer.shadowMap.enabled = true;


document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);

controls.target.set(0, 0, 0); // Set the target point
controls.enableZoom = true; // Enable zooming with the mouse wheel
controls.enablePan = true; // Enable panning by holding the middle mouse button

const hemisphereLight = new THREE.HemisphereLight(0xaaaaaa, 0x000000, 1);

const shadowLight = new THREE.DirectionalLight(0xffffff, 1);

shadowLight.position.set(-150, 350, 350);

shadowLight.castShadow = true;

shadowLight.shadow.camera.left = -400;
shadowLight.shadow.camera.right = 400;
shadowLight.shadow.camera.top = 400;
shadowLight.shadow.camera.bottom = -400;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 1000;

shadowLight.shadow.mapSize.width = 2048;
shadowLight.shadow.mapSize.height = 2048;

scene.add(hemisphereLight);
scene.add(shadowLight);
const mainCharacter = new Character('./knight5.glb')
const florest = new Character('florest.glb');
// Função de animação
const animate = () => {
  requestAnimationFrame(animate);
  const deltaTime = clock.getDelta();
  scene.add(mainCharacter.getModel());
  scene.add(florest.getModel());
  controls.update(); // Update the camera controls
  mainCharacter.update(deltaTime);
  // Animação do personagem ou quaisquer outras atualizações

  renderer.render(scene, camera);
};

animate();

You can certainly set up materials well in Blender with Principled BSDF + glTF, but I’m not aware of any good workflow to set up your lighting and shadows in Blender, unfortunately, unless you’re willing to completely bake the lighting/shadows to textures. Otherwise you’ll almost certainly need to do that part of the setup in three.js itself.

My advice here would generally be:

  1. use a GUI like lil-gui or leva for faster tweaks
  2. bake AO maps in Blender
  3. consider an env-map for main lighting, with directional light for shadows
  4. use the various helper utilities to make it easier to position things
  5. enable renderer.toneMapping in lit scenes

Hey. Thanks for the answer! I am a total noob in this world of ThreeJS, so I can’t understand a lot of what you said that I should do, but I could get a bit. I’ll try to do like you said, but first, let me just ask you a question that I think you may know how to answer me. In blender, I can set light in points and there’s a option to export them to GLTF. But, when I load the model this way, it comes all black and white. Am I doing something wrong? Like, is it possible to make the scene in Blender and then render with ThreeJS?

In Blender:

ThreeJS:

How are those materials configured in Blender? Screenshot of the node graph and/or material panel would help. There are a lot of ways to set up materials in Blender, most of which do not export to anything outside of Blender. If you want to export you’ll need to get pretty familiar with the guide here, which explains how to make materials you can export:

https://docs.blender.org/manual/en/latest/addons/import_export/scene_gltf2.html

Then I would test the model in some online viewers (e.g. https://gltf-viewer.donmccurdy.com/) first, before trying in your own application, to eliminate some of the guesswork.


I think what you’re seeing in that “black and white” scene is a wildly over-exposed (too bright!) render. While it is possible to export point lights to glTF, and lights do have physical units … you’ll not necessarily see the same thing in two different renderers, with different exposure and tone mapping and so on. And Blender has a few different modes in the exporter settings for lights.

If you try decreasing exposure on that scene you might get closer to the Blender result, but I’m not sure. Try values for exposure in the range of -8 to +8 here:

const exposure = -3;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = Math.pow(2, exposure);
1 Like

This exposure way worked out! You are a life saver <3 How can I compensate? You really helped me :slight_smile:

1 Like

Well, the light is working now, but still missing the shadows, but I’ll figure out I think!