Samstag, 7. September 2013

Three.js - Shadows

Shadows are expensive. Thats why on default there is no shadow. For creating some shadows you need to set up a bunch of things so it works out.


  • tell the renderer that you want shadows
  • enable objects to cast shadows
  • enable objects to receive shadows
  • enable a light source to cast shadows (directional or spotlight only)

Renderer

ShadowMapEnable is required, shadowMapSoft is optional to soften the shadows.
    renderer.shadowMapEnabled = true;
    renderer.shadowMapSoft = true;

Objects

To enable objects to cast a shadow you have to set castShadow:
cylinder.castShadow = true;

To see a shadow on an object, the object has to receive the shadow.
plane.receiveShadow = true;

Light

To lights can create shadows: directional light and spotlight.

It's important to specify a box (orange cube) in which shadows are enabled via CameraNear, -Far, -Left, -Right, -Top, -Bottom. Keep it small for performance.

        //directional light
 var directionalLight = new THREE.DirectionalLight(0xffffff);
 directionalLight.position.set(5, 0, 5);
 directionalLight.target.position.set(0, 0, 0);
 
 directionalLight.castShadow = true;
 directionalLight.shadowDarkness = 0.5;
 
 directionalLight.shadowCameraNear = 0;
 directionalLight.shadowCameraFar = 15;
 
 directionalLight.shadowCameraLeft = -5;
 directionalLight.shadowCameraRight = 5;
 directionalLight.shadowCameraTop = 5;
 directionalLight.shadowCameraBottom = -5;
 
 scene.add(directionalLight);
        //spotlight
  var spotLight = new THREE.SpotLight( 0xffffff,1 );
  spotLight.position.set( 5,0,6 );
  
  spotLight.castShadow = true;
  
  spotLight.target.position.set(-1, 0, 1 );
  spotLight.shadowDarkness = 0.5;
  
  spotLight.shadowCameraNear = 6; 
  spotLight.shadowCameraFar = 13;
  
 scene.add( spotLight );

Debug help

To display the light's direction use this:
 spotLight.shadowCameraVisible = true;


Here is the complete code with both lights:

<html>
<html>
 <head>
  <script src="three/build/three.min.js"></script>
  <script src="three/examples/js/controls/OrbitControls.js"></script>
  <script src="jquery-1.10.2.min.js"></script>
    
  <script type="text/javascript">
     
   $(function() {
   
    //scene
    var scene = new THREE.Scene();
    //camera
    var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
    camera.position.set(0,-12,5);
    camera.lookAt(new THREE.Vector3( 0, 5, 0 ));
    
    //renderer
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );

    renderer.shadowMapEnabled = true;
    renderer.shadowMapSoft = true;

    //controls
    var controls = new THREE.OrbitControls( camera, renderer.domElement );
      
    //show canvas
    $("#canvas-container").html(renderer.domElement);
    
    //lights
    
 //directional light
 var directionalLight = new THREE.DirectionalLight(0xffffff);
 directionalLight.position.set(5, 0, 5);
 directionalLight.target.position.set(0, 0, 0);
 
 directionalLight.castShadow = true;
 directionalLight.shadowDarkness = 0.5;
 directionalLight.shadowCameraVisible = true;
 
 directionalLight.shadowCameraNear = 0;
 directionalLight.shadowCameraFar = 15;
 
 directionalLight.shadowCameraLeft = -5;
 directionalLight.shadowCameraRight = 5;
 directionalLight.shadowCameraTop = 5;
 directionalLight.shadowCameraBottom = -5;
 
 scene.add(directionalLight);

    
 //spotlight
  var spotLight = new THREE.SpotLight( 0xffffff,1 );
  spotLight.position.set( 5,0,6 );
  
  spotLight.castShadow = true;
  spotLight.shadowCameraVisible = true;
  
  spotLight.target.position.set(-1, 0, 1 );
  spotLight.shadowDarkness = 0.5;
  
  spotLight.shadowCameraNear = 6; 
  spotLight.shadowCameraFar = 13;
  
 scene.add( spotLight );

 
 
    
    //plane
    var geometry = new THREE.PlaneGeometry(20, 10);
    var material = new THREE.MeshPhongMaterial( { color: 0xcccccc } );
    var plane = new THREE.Mesh( geometry, material );
    plane.receiveShadow = true;
    scene.add(plane);
    
    
    //cube
    var geometry = new THREE.CubeGeometry(1,1,1);
    var material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
    var cube = new THREE.Mesh( geometry, material );
    cube.position.set(-4,0,0.5);
    cube.castShadow = true;
    scene.add( cube );
    
         
  //cylinder
    var geometry = new THREE.CylinderGeometry(1, 0, 3, 50, 50, false);
    var material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
    var cylinder = new THREE.Mesh( geometry, material );
    cylinder.position.set(-1,-2,1);
    cylinder.rotation.x = -Math.PI / 2;
    cylinder.castShadow = true;
    scene.add( cylinder );
    
   
   
  
  
    //render scene
    var render = function () {
     requestAnimationFrame(render);
     renderer.render(scene, camera);
    };
      
    render();
      
   });
     
  </script>
    
 </head>
 <body style="background: black">
    
  <div id="canvas-container" style="position: absolute; left:0px; top:0px"></div>
    
 </body>
</html>

Keine Kommentare:

Kommentar veröffentlichen