Thursday, March 21, 2013

Scaling Land to Fit the Three.js Sun

‹prev | My Chain | next›

After all this time, I still do not quite understand lighting in Three.js. I would like to have sunlight shining down on my awesome river landscape:



The problem is that I have made my river rafting world much larger than the normal DirectionalLight in Three.js. I made the land 5000 by 5000:

  var ground = makeGround(5000);
  // ...
  function makeGround(size) {
    var faces = 100;
    var shape = new THREE.PlaneGeometry(size, size, faces, faces);
    var cover = Physijs.createMaterial(new THREE.MeshPhongMaterial(), 1, 0.1);
    // ...
    var ground = new Physijs.HeightfieldMesh(
      shape, cover, 0
    );
    // ...
  }
If I add a directional light that is equal parts offset in the x, y, and z directions, I get shadows in the scene. But the shadows are only visible in the middle of the river. For much of the beginning part of the journey and much of the end, there are no shadows.

Three.js includes a debugging mechanism for figuring out the shape of lights. So I enable it with the shadowCameraVisible property:
  function addSunlight(scene) {
    var sunlight = new THREE.DirectionalLight();
    sunlight.intensity = 0.5;
    sunlight.castShadow = true;
    sunlight.position.set(1, 1, 1);
    sunlight.shadowCameraVisible = true;
    scene.add(sunlight);
  }
I manually position the camera well away from land to find:



The red “X” marks the orientation of the light source. The yellow box signifies the extent of the shadow making region of the light. In other words: source of the mystery found. My code will only produce shadows in the very center of the game.

To make the shadow box larger, I fiddle with parameters available on DirectionalLight:
  function addSunlight(scene) {
    var sunlight = new THREE.DirectionalLight();
    sunlight.intensity = 0.5;
    sunlight.castShadow = true;
    sunlight.shadowCameraLeft = -1500;
    sunlight.shadowCameraRight = 1500;
    sunlight.shadowCameraTop = 2500;
    sunlight.shadowCameraNear = -2000;
    sunlight.position.set(1, 1, 1);
    sunlight.shadowCameraVisible = true;
    scene.add(sunlight);
  }
This makes for a nice improvement in the shadow casting area of my “Sun” directional light source:



Although it occurs to me. Perhaps I am taking the wrong approach. Instead of making light bigger, perhaps it is easier to scale down everything else. There must be a reason that DirectionalLight defaults to the size that it does.

After removing the shadow box size properties from the sunlight and scaling the playing area down, I am left with this:



I think this is probably the way to go. The overall effect in the game is still not quite right, so I will probably come back to this tomorrow to see if there are some other settings in need of tweaking. But, so far so good with the scaled down approach.


Day #697

3 comments:

  1. I have got exactly the same issue so far. Still working on it! Any improvement you side?

    ReplyDelete
  2. Ijust found a solution for my own problem:
    YOu just nee to remove the normalize() function to have the full control on your shadow and light parameters, from
    light.position.set(5000, 5000, 5000 ).normalize();
    to
    light.position.set(5000, 5000, 5000 );

    Cheerio

    ReplyDelete
    Replies
    1. Nice! I was not aware of the normalize() method -- something else for me to learn about :)

      For me, the problem was the very concept of a shadow box with directional light. Somehow it just didn't seem to fit. Thanks to mucking around with it here, I was eventually able to get it working pretty nicely: http://japhr.blogspot.com/2013/03/threejs-directional-light-shadow-boxes.html.

      Still more for me to learn though!

      Delete