27

I'm attempting to create a small 1st-person game using Three.js, but I'm having trouble with the lighting. Basically I want to simulate the sun and have it rotate around casting light on everything. I'm using THREE.DirectionalLight at the moment and it only lights up the one direction so sides of cubes remain black/dark.

Do I have to use multiple lights so everything is lit up? Or could I somehow reflect light off the ground/objects?

Joey Morani
  • 25,431
  • 32
  • 84
  • 131

3 Answers3

24

Yes, you'll have to use multiple lights to achieve this, faking the reflected light. Computing real reflected light isn't built in (and computationally very complex/expensive). You have a variety of options.

A second directional light that could always be in the opposite position and direction of your sun.

A hemisphere light that remains constant. Hemisphere lighting gets a sky color and a ground color and intensity and adds a nice extra bit of depth to your lighting.

//                                    sky color ground color intensity 
hemiLight = new THREE.HemisphereLight( 0x0000ff, 0x00ff00, 0.6 ); 

here's a working example https://threejs.org/examples/#webgl_lights_hemisphere

you could use any combination of different lights but be careful there's a performance trade off.

It's also worth mentioning half-lambert shading which is enabled by setting the wrapAround property to true in your material. This gives a nicer falloff to black that results in less harsh lighting. More mid tones and less blacks.

abernier
  • 27,030
  • 20
  • 83
  • 114
Andrew Berg
  • 741
  • 5
  • 9
  • 1
    Thanks! Setting wrapAround to true has fixed it. Now there's no blacks and the colors are still visible even when not directly in the light, which was what I wanted. I've updated the original link :) Just need to figure out how to fix my shadow problem now. – Joey Morani Mar 18 '13 at 16:00
  • 4
    wrapAround seems to have been removed since this comment was posted. How can this effect be achieved now? – Toivo Säwén Jun 29 '17 at 13:51
22

I used a combination of these two lights to create this video: http://www.youtube.com/watch?v=m68FDmU0wGw

            var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
            hemiLight.color.setHSV( 0.6, 0.75, 0.5 );
            hemiLight.groundColor.setHSV( 0.095, 0.5, 0.5 );
            hemiLight.position.set( 0, 500, 0 );
            scene.add( hemiLight );

            var dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
            dirLight.position.set( -1, 0.75, 1 );
            dirLight.position.multiplyScalar( 50);
            dirLight.name = "dirlight";
            // dirLight.shadowCameraVisible = true;

            scene.add( dirLight );

            dirLight.castShadow = true;
            dirLight.shadowMapWidth = dirLight.shadowMapHeight = 1024*2;

            var d = 300;

            dirLight.shadowCameraLeft = -d;
            dirLight.shadowCameraRight = d;
            dirLight.shadowCameraTop = d;
            dirLight.shadowCameraBottom = -d;

            dirLight.shadowCameraFar = 3500;
            dirLight.shadowBias = -0.0001;
            dirLight.shadowDarkness = 0.35;
dirkk0
  • 2,460
  • 28
  • 34
1

You can use scene.environment to do this job, there is already a good example here:

https://gltf-viewer.donmccurdy.com/

check gltf-viewer's code here, which did a great job in sunlight.

https://github.com/donmccurdy/three-gltf-viewer/blob/main/src/viewer.js

notice the environments vairable, which use venice_sunset_1k.hdr as their default background.

To be more detailed, they use a background as their environment, but they didn't 'show' them, you can use the code below

    this.pmremGenerator = new PMREMGenerator( this.renderer );
    this.pmremGenerator.compileEquirectangularShader();
    var rgbe_loader = new RGBELoader();
    var that = this;
    rgbe_loader.setDataType(UnsignedByteType).load("/environment/venice_sunset_2k.hdr", function(texture) {

        var envMap = that.pmremGenerator.fromEquirectangular(texture).texture;

        that.scene.environment = envMap;

        texture.dispose();
        that.pmremGenerator.dispose();

    });

where the hdr file can be found in https://polyhaven.com/a/venice_sunset

Humor
  • 11
  • 2