three.js给场景加上阴影

时间:2021-11-07 03:10:03

现实世界中(假设只在地球,先不考虑外太空three.js给场景加上阴影three.js给场景加上阴影three.js给场景加上阴影),只要有光的地方就会有阴影产生。所以当我们构建好一个具备光照的场景后,还必须给其加上阴影,才能更清楚地显示场景中各个元素的关系,光照和阴影是webgl和three.js开发大型场景必不可少的元素,如果少了这两者,想象一下,地球上一切事物如果没有阴影,没有灯光,那么是不是世界乌漆嘛黑,什么都看不见?本节先不讲光照,先讲讲阴影的投射和接收,各种光源和材质的介绍和应用,在后面会单独写文章进行详细介绍。接下来先看看怎样给场景添加阴影。

添加阴影主要是这几个步骤:

渲染器一定要允许产生阴影:

//渲染器
//antialias:true增加抗锯齿效果
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setClearColor(new THREE.Color(0x000000));//设置窗口背景颜色为黑
renderer.setSize(window.innerWidth, window.innerHeight);//设置窗口尺寸
renderer.shadowMapEnabled = true;//开启阴影,加上阴影渲染

灯光要投下阴影,否则场景不会产生阴影:

var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-50, 60, 15);
spotLight.castShadow = true;//开启灯光投射阴影

物体要投下阴影和接受阴影,假设这里的物体为Mesh;否则也不会有阴影产生:

Mesh.castShadow = true;//开启投影
Mesh.receiveShadow = true;//接收阴影
当阴影添加完毕后,就可以产生阴影的效果啦。接下来实现一个有阴影的场景,其效果如下图所示:

three.js给场景加上阴影

这个实例的静态版本在我另一片博文:点击打开链接,轨道控制器鼠标交互的版本在这篇博文:点击打开链接

但有一点需要特别注意,光源的位置一定要距离合适,否则容易引起阴影模糊粗糙的像打马赛克一样three.js给场景加上阴影three.js给场景加上阴影three.js给场景加上阴影,像下面的图所示:

three.js给场景加上阴影

下面附上示例代码:

<!DOCTYPE html> <html lang="en"> <head>  <meta charset="UTF-8">  <title>threejs-basic-geometry</title>  <style>  body{
            font-family: Monospace;  background: #f0f0f0;  margin: 0px;  overflow: hidden;  }
    </style> </head> <body> <script type="text/javascript" src="build/three.js"></script> <script type="text/javascript" src="js/Detector.js"></script> <script type="text/javascript" src="js/controls/OrbitControls.js"></script> <script type="text/javascript">  //检测webgl的支持情况  if(!Detector.webgl) {Detector.addGetWebGLMessage();}
    var container;  var camera, scene, renderer;  //用于轨道控制器  var orbitControls, clock, delta;  main();  render();  //主函数  function main(){
        //添加一个div元素  container = document.createElement('div')
        document.body.appendChild(container);  scene = new THREE.Scene();//创建一个新场景  //添加一个透视相机  camera = new THREE.PerspectiveCamera(30,  window.innerWidth/window.innerHeight, 1, 1000);  camera.position.set(100, 300, 100);//设置相机位置  camera.lookAt(new THREE.Vector3(0,0,0));//让相机指向原点  //渲染器  //antialias:true增加抗锯齿效果  renderer = new THREE.WebGLRenderer({antialias:true});  renderer.setClearColor(new THREE.Color(0x000000));//设置窗口背景颜色为黑  renderer.setSize(window.innerWidth, window.innerHeight);//设置窗口尺寸  renderer.shadowMapEnabled = true;  //将renderer关联到container,这个过程类似于获取canvas元素  container.appendChild(renderer.domElement);  //添加轨道控制器  //新建一个轨道控制器  orbitControls = new THREE.OrbitControls(camera, renderer.domElement);  orbitControls.target = new THREE.Vector3(0, 0, 0);//控制焦点  orbitControls.autoRotate = false;//将自动旋转关闭  clock = new THREE.Clock();//用于更新轨道控制器  //给场景添加光源  //自然光  var ambientLight = new THREE.AmbientLight( 0x0c0c0c );  scene.add( ambientLight ); // //平行光源 // var directionalLight = new THREE.DirectionalLight( 0xffffff ); // directionalLight.position.set( 1, 0.75, 0.5 ).normalize(); // directionalLight.castShadow = true; // scene.add(directionalLight)  var spotLight = new THREE.SpotLight(0xffffff);  //spotLight.position.set(-50, 60, 15);  spotLight.position.set(-200, 160, 85);  spotLight.castShadow = true;//允许投射阴影  scene.add(spotLight);  plane();  cube();  sphere();  cylinder();  }
    //创建一个平面  function plane(){
        var planeGeo = new THREE.PlaneGeometry(100,100,10,10);//创建平面  var planeMat = new THREE.MeshLambertMaterial({  //创建材料  color:0xFFFFFF,  wireframe:false  });  var planeMesh = new THREE.Mesh(planeGeo, planeMat);//创建网格模型  planeMesh.position.set(0, 0, -20);//设置平面的坐标  planeMesh.rotation.x = -0.5 * Math.PI;//将平面绕X轴逆时针旋转90度  planeMesh.receiveShadow = true;//允许接收阴影  scene.add(planeMesh);//将平面添加到场景中  }
    //创建一个立方体  function cube(){
        var cubeGeo = new THREE.CubeGeometry(20, 20, 20, 5, 5, 5);//创建立方体  var cubeMat = new THREE.MeshLambertMaterial({//创建材料  color:0x003300,  wireframe:false  });  var cubeMesh = new THREE.Mesh(cubeGeo, cubeMat);//创建立方体网格模型  cubeMesh.position.set(15, 10, 0);//设置立方体的坐标  cubeMesh.castShadow = true;//允许投射阴影  cubeMesh.receiveShadow = true;//允许接收阴影  scene.add(cubeMesh);//将立方体添加到场景中  }
    //创建一个球  function sphere(){
        var sphereGeo = new THREE.SphereGeometry(16, 40, 40);//创建球体  var sphereMat = new THREE.MeshLambertMaterial({//创建材料  color:0x0000FF,  wireframe:false  });  var sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);//创建球体网格模型  sphereMesh.position.set(-25, 16, 0);//设置球的坐标  sphereMesh.castShadow = true;//允许投射阴影  sphereMesh.receiveShadow = true;//允许接收阴影  scene.add(sphereMesh);//将球体添加到场景  }
    //创建圆柱体  function cylinder(){
        //创建圆柱体  var cylinderGeo = new THREE.CylinderGeometry(15, 15 ,40 ,40 ,40);  var cylinderMat = new THREE.MeshLambertMaterial({//创建材料  color:0xFF6600,  wireframe:false  });  //创建圆柱体网格模型  var cylinderMesh = new THREE.Mesh(cylinderGeo, cylinderMat);  cylinderMesh.position.set(0, 20, -40);//设置圆柱坐标sphere  cylinderMesh.castShadow = true;//允许投射阴影  cylinderMesh.receiveShadow = true;//允许接收阴影  scene.add(cylinderMesh);//向场景添加圆柱体  }
    //渲染  function render(){
        delta = clock.getDelta();  orbitControls.update(delta);  requestAnimationFrame(render);  renderer.render(scene, camera);  }
</script> </body> </html>