个人博客地址: https://cxx001.gitee.io
前言
没有光源,渲染场景将不可见。threejs中已经帮我们实现了大量的光源,我们可以直接使用,主要分为两类:基础光源和特殊光源,下面将依次详细介绍。

基础光源
1. THREE.AmbientLight(环境光)
该光源颜色会应用到场景全局,光源没有特别的来源方向,并且不会生成阴影。通常,不会将环境光作为场景中唯一的光源,因为它会将场景中的所有物体渲染为相同颜色。一般和其它光源一起使用,它只是为了弱化阴影或给场景添加一些额外的颜色,所以它的用色应该尽量保守,如果设置的颜色过于明亮,那么画面颜色就过于饱和了。
下面示例帮助你理解,试试改变AmbientLight光颜色或开启/关闭spotLight光源,观察场景变化。
<!-- chapter-03-01.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Ambient Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    function init() {
    	// 初始化fps显示插件
        var stats = initStats();
        // 创建场景对象
        var scene = new THREE.Scene();
        // 创建透视投影摄像机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 创建渲染器
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); // 设置背景颜色
        renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染窗口大小
        renderer.shadowMapEnabled = true; // 激活阴影
        // 创建平面
        var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true; // 接收阴影
        // 设置平面位置
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);
        // 创建立方体对象
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true; // 投射阴影
        // 设置立方体位置
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);
		
    	// 创建球体
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        // 设置球体位置
        sphere.position.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true; // 投射阴影
        scene.add(sphere);
        // 设置摄像机位置
        camera.position.x = -25;
        camera.position.y = 30;
        camera.position.z = 25;
    	// 设置摄像机镜头朝向
        camera.lookAt(new THREE.Vector3(10, 0, 0));
        // 创建环境光
        var ambiColor = "#0c0c0c";  // 使用的是比较暗淡的灰色
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);
        // 创建聚光灯并开启投射阴影
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        scene.add(spotLight);
        // 将渲染器添加到DOM里显示
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        // 设置dat.GUI插件显示属性
        var controls = new function () {
            this.ambientColor = ambiColor; // 环境光颜色
            this.disableSpotlight = false; // 聚光灯是否可见
        };
		
    	// 将添加的控制属性添加到gui界面
        var gui = new dat.GUI();
    	// 颜色设置
        gui.addColor(controls, 'ambientColor').onChange(function (e) {
            ambientLight.color = new THREE.Color(e);
        });
    	// 开关设置
        gui.add(controls, 'disableSpotlight').onChange(function (e) {
            spotLight.visible = !e;  // 聚光灯是否可见
        });
		// 开始渲染
        render();
		var step = 0;
        function render() {
            // 更新fps显示
            stats.update();
            
            // 旋转立方体
            cube.rotation.x += 0.02;
            cube.rotation.y += 0.02;
            cube.rotation.z += 0.02;
            // 跳动球体
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
            // 重新渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
		
    	// 初始化fps显示插件
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
效果:

2. THREE.PointLight(点光源)
点光源发射光线示意图:

从特定的一点向所有方向发射光线。夜空中的照明弹就是一个很好的点光源例子。
threejs里的点光源也没有阴影,因为它朝所有方向发射光线,这种情况下计算阴影对GPU是一个沉重的负担。
下面我们依旧通过示例来理解,这是一个点光源绕场景移动,为了看到点光源位置,我们让一个橙色的小球沿着相同的轨迹移动。你可以看到随着光源的移动,红色的方块和蓝色的球被这个光源从不同的侧面照亮。
<!-- chapter-03-02.html -->
<!DOCTYPE html>
<html>
<head>
    <title>point Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        // renderer.shadowMapEnabled = true; // 点光源没有阴影
        var planeGeometry = new THREE.PlaneGeometry(60, 20, 20, 20);
        var planeMaterial = new THREE.MeshPhongMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        // plane.receiveShadow = true;
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff7777});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        // cube.castShadow = true;
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true;
        scene.add(sphere);
        camera.position.x = -25;
        camera.position.y = 30;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(10, 0, 0)); // 镜头照射位置
        // 添加环境光,弱的灰色,为了柔化场景
        var ambiColor = "#0c0c0c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);
        // 添加点光源
        var pointColor = "#ccffcc";
        var pointLight = new THREE.PointLight(pointColor);
        pointLight.distance = 100;  // 光源照射距离
        scene.add(pointLight);
        var sphereLight = new THREE.SphereGeometry(0.2);
        var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
        var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
        // sphereLightMesh.castShadow = true;
        sphereLightMesh.position = new THREE.Vector3(3, 0, 3);
        scene.add(sphereLightMesh);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        var controls = new function () {
            this.ambientColor = ambiColor;  // 环境光颜色
            this.pointColor = pointColor;   // 点光源颜色
            this.intensity = 1;    // 光照强度
            this.distance = 100;   // 光照距离
        };
        var gui = new dat.GUI();
        gui.addColor(controls, 'ambientColor').onChange(function (e) {
            ambientLight.color = new THREE.Color(e);
        });
        gui.addColor(controls, 'pointColor').onChange(function (e) {
            pointLight.color = new THREE.Color(e);
        });
        gui.add(controls, 'intensity', 0, 3).onChange(function (e) {
            pointLight.intensity = e;
        });
        gui.add(controls, 'distance', 0, 100).onChange(function (e) {
            pointLight.distance = e;
        });
        render();
        var step = 0;
		var invert = 1;
        var phase = 0;
        function render() {
            stats.update();
            
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
            // 模拟光源移动
            if (phase > 2 * Math.PI) {
                invert = invert * -1;
                phase -= 2 * Math.PI;
            } else {
                phase += 0.03;
            }
            sphereLightMesh.position.z = +(7 * (Math.sin(phase)));
            sphereLightMesh.position.x = +(14 * (Math.cos(phase)));
            sphereLightMesh.position.y = 5;
            if (invert < 0) {
                var pivot = 14;
                sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;
            }
			// 光源和球体一起移动
            pointLight.position.copy(sphereLightMesh.position);
            // 重新渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
所使用的点光源属性:
| 属性 | 描述 | 
|---|---|
| color(颜色) | 光源的颜色 | 
| distance(距离) | 光源照射的距离。默认值为0,这意味着光的强度不会随着距离增加而减少 | 
| intensity(强度) | 光源照射的强度。默认值1 | 
| position(位置) | 光源在场景中的位置 | 
| visible(是否可见) | 默认为true,光源会打开;如果设置为false,光源就会关闭 | 
效果:

3. THREE.SpotLight(聚光灯)
聚光灯发射光线示意图:

从特定的一点发射锥形形状的光线,这是最常使用的光源之一,特别是你想要使用阴影的话。该光源具有产生光的方向和角度,类似手电筒。
聚光灯光源的所有属性:
| 属性 | 描述 | 
|---|---|
| angle(角度) | 光源发射出的光束的宽度。默认是Math.PI/3 | 
| castShadow(投影) | 如果设置为true,这个光源就会投射阴影 | 
| color(颜色) | 光源颜色 | 
| distance(距离) | 光源照射的距离。默认值为0,这意味着光的强度不会随着距离增加而减少 | 
| intensity(强度) | 光源照射的强度。默认值1 | 
| exponent(光强衰减指数) | 发射的光线强度随着光源距离的增加而减弱,这个属性决定了光线强度递减的速度。使用小值,从光源发出的光线可以达到远处的物体,而使用大值,光线仅能到达非常接近光源的物体。 | 
| onlyShadow(仅阴影) | 如果此属性设置为true,则该光源只生成阴影,不会在场景中添加任何光照 | 
| position(位置) | 光源在场景中的位置 | 
| shadowBias(阴影偏移) | 用来偏移阴影位置。当你使用非常薄的对象时,可能出现奇怪的渲染失真现象,如果你看到奇怪的阴影效果,将该属性设置为很小的值(如0.01)通过可以解决问题。此属性默认值为0 | 
| shadowCameraFar(投影远点) | 到距离光源的哪一个位置可以生成阴影。默认值为5000(这几个参考投射投影摄像机理解) | 
| shadowCameraNear(投影近点) | 从距离光源的哪一个位置开始生成阴影。默认值为50 | 
| shadowCameraFov(投影视场) | 用于生成阴影的视场有多大。默认值为50 | 
| shadowCameraVisible(投影方式是否可见) | 如果设置为true,可以看到光源在哪里以及如何生成阴影的(看到光源照射锥体)。默认值为false | 
| shadowDarkness(投影暗度) | 定义阴影的暗度。在场景渲染后无法修改。默认值为0.5 | 
| shadowMapWidth和shadowMapHeight(阴影映射的宽/高) | 决定有多少像素用来生成阴影。**当阴影有锯齿或看起来不光滑时,可以增加这个值。**在场景渲染后无法修改。两者默认值为512 | 
| target(目标) | 可以将光源指向场景中特定的对象或位置(位置需要是THREE.Object3Dd对象,不是THREE.Vectors3对象)。 | 
| visible() | 默认为true,光源会打开;如果设置为false,光源就会关闭 | 
<!-- chapter-03-03.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Spot Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    function init() {
		// 是否停止移动光源
        var stopMovingLight = false;
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
        renderer.shadowMapType = THREE.PCFShadowMap; // 这是默认值,如果设置为PCFSoftShadowMap则会使阴影更柔和
        var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true;
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff3333});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true;
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true;
        scene.add(sphere);
        camera.position.x = -35;
        camera.position.y = 30;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(10, 0, 0));
        // 添加环境光
        var ambiColor = "#1c1c1c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);
        // 添加1个聚光灯光源,设置位置和照射方向(和摄像机设置类似), 这个固定照射地面
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 30, -10);
        spotLight0.lookAt(plane);
        scene.add(spotLight0);
		// 添加另一个聚光灯光源,和小球一起运动
    	//var target = new THREE.Object3D();
        //target.position = new THREE.Vector3(5, 0, 0);
    
        var pointColor = "#ffffff";
        var spotLight = new THREE.SpotLight(pointColor);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        spotLight.shadowCameraNear = 2;
        spotLight.shadowCameraFar = 200;
        spotLight.shadowCameraFov = 30;
        spotLight.target = plane;  // 照射方向,可以是这里的网格物体,也可以是上面的target具体某点对象
        spotLight.distance = 0;
        spotLight.angle = 0.4;
        scene.add(spotLight);
        var sphereLight = new THREE.SphereGeometry(0.2);
        var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
        var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
        sphereLightMesh.castShadow = true;
        sphereLightMesh.position = new THREE.Vector3(3, 20, 3);
        scene.add(sphereLightMesh);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        var step = 0;
        var invert = 1;
        var phase = 0;
        var controls = new function () {
            this.ambientColor = ambiColor;
            this.pointColor = pointColor;
            this.intensity = 1;  // 光照强度
            this.distance = 0;   // 光照距离
            this.exponent = 30;  // 随着距离光源越远,光强度衰减指数
            this.angle = 0.1;  // 光源视场角度
            this.debug = false;  // 是否开启调试模式(打开投影方式可见)
            this.castShadow = true;  // 是否投射阴影,false则不会产生阴影
            this.onlyShadow = false;  // 是否只生成阴影,true则不会在场景中产生光照
            this.target = "Plane";   // 光源照射目标
            this.stopMovingLight = false;  // 是否停止移动光源
        };
        var gui = new dat.GUI();
        gui.addColor(controls, 'ambientColor').onChange(function (e) {
            ambientLight.color = new THREE.Color(e);
        });
        gui.addColor(controls, 'pointColor').onChange(function (e) {
            spotLight.color = new THREE.Color(e);
        });
        gui.add(controls, 'angle', 0, Math.PI * 2).onChange(function (e) {
            spotLight.angle = e;
        });
        gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
            spotLight.intensity = e;
        });
        gui.add(controls, 'distance', 0, 200).onChange(function (e) {
            spotLight.distance = e;
        });
        gui.add(controls, 'exponent', 0, 100).onChange(function (e) {
            spotLight.exponent = e;
        });
        gui.add(controls, 'debug').onChange(function (e) {
            spotLight.shadowCameraVisible = e;
        });
        gui.add(controls, 'castShadow').onChange(function (e) {
            spotLight.castShadow = e;
        });
        gui.add(controls, 'onlyShadow').onChange(function (e) {
            spotLight.onlyShadow = e;
        });
		// gui添加选择列表方式
        gui.add(controls, 'target', ['Plane', 'Sphere', 'Cube']).onChange(function (e) {
            console.log(e);
            switch (e) {
                case "Plane":
                    spotLight.target = plane;
                    break;
                case "Sphere":
                    spotLight.target = sphere;
                    break;
                case "Cube":
                    spotLight.target = cube;
                    break;
            }
        });
        gui.add(controls, 'stopMovingLight').onChange(function (e) {
            stopMovingLight = e;
        });
        render();
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
            // 小球和spotLight光源一起移动
            if (!stopMovingLight) {
                if (phase > 2 * Math.PI) {
                    invert = invert * -1;
                    phase -= 2 * Math.PI;
                } else {
                    phase += 0.03;
                }
                sphereLightMesh.position.z = +(7 * (Math.sin(phase)));
                sphereLightMesh.position.x = +(14 * (Math.cos(phase)));
                sphereLightMesh.position.y = 10;
                if (invert < 0) {
                    var pivot = 14;
                    sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;
                }
                spotLight.position.copy(sphereLightMesh.position);
            }
            // 重新渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
	
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
效果:

4. THREE.DirectionalLight(平行光)
平行光发生光线示意图:

从二维平面发射光线,光线彼此平行。这种类型的光可以看作是距离很远的光,如太阳光,它如此遥远,以至于达到地球时所有的光线几乎都是相互平行的。**它不像前面聚光灯那样离目标越远越暗淡,被平行光照亮的整个区域接收到的光强度是一样的。**它也可以产生阴影,很多属性和上面SpotLight一样,它的光照区域是一个立方体,类似正交投影摄像机,而SpotLight则类似透视投影摄像机。
<!-- chapter-03-04.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Directional Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
		// 平面
        var planeGeometry = new THREE.PlaneGeometry(600, 200, 20, 20);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true;
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = -5;
        plane.position.z = 0;
        scene.add(plane);
		// 立方体
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff3333});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true;
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);
		// 球
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true;
        scene.add(sphere);
        camera.position.x = -35;
        camera.position.y = 30;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(10, 0, 0));
        // 添加环境光,给场景润色
        var ambiColor = "#1c1c1c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);
		// 添加平行光
        var pointColor = "#ff5808";
        var directionalLight = new THREE.DirectionalLight(pointColor);
        directionalLight.position.set(-40, 60, -10);
        directionalLight.castShadow = true;
    	// 设置光照立方体区域
        directionalLight.shadowCameraNear = 2;
        directionalLight.shadowCameraFar = 200;
        directionalLight.shadowCameraLeft = -50;
        directionalLight.shadowCameraRight = 50;
        directionalLight.shadowCameraTop = 50;
        directionalLight.shadowCameraBottom = -50;
		// 同前面聚光灯属性
        directionalLight.distance = 0;
        directionalLight.intensity = 0.5;
        directionalLight.shadowMapHeight = 1024;
        directionalLight.shadowMapWidth = 1024;
        scene.add(directionalLight);
        // 和光源一起移动的小球
        var sphereLight = new THREE.SphereGeometry(1);
        var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
        var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
        sphereLightMesh.castShadow = true;
        sphereLightMesh.position = new THREE.Vector3(3, 20, 3);
        scene.add(sphereLightMesh);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
    	// 属性同上面聚光灯
        var controls = new function () {
            this.ambientColor = ambiColor;
            this.pointColor = pointColor;
            this.intensity = 0.5;
            this.distance = 0;
            this.exponent = 30;
            this.angle = 0.1;
            this.debug = false;
            this.castShadow = true;
            this.onlyShadow = false;
            this.target = "Plane";
        };
        var gui = new dat.GUI();
        gui.addColor(controls, 'ambientColor').onChange(function (e) {
            ambientLight.color = new THREE.Color(e);
        });
        gui.addColor(controls, 'pointColor').onChange(function (e) {
            directionalLight.color = new THREE.Color(e);
        });
        gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
            directionalLight.intensity = e;
        });
        gui.add(controls, 'distance', 0, 200).onChange(function (e) {
            directionalLight.distance = e;
        });
        gui.add(controls, 'debug').onChange(function (e) {
            directionalLight.shadowCameraVisible = e;
        });
        gui.add(controls, 'castShadow').onChange(function (e) {
            directionalLight.castShadow = e;
        });
        gui.add(controls, 'onlyShadow').onChange(function (e) {
            directionalLight.onlyShadow = e;
        });
        gui.add(controls, 'target', ['Plane', 'Sphere', 'Cube']).onChange(function (e) {
            console.log(e);
            switch (e) {
                case "Plane":
                    directionalLight.target = plane;
                    break;
                case "Sphere":
                    directionalLight.target = sphere;
                    break;
                case "Cube":
                    directionalLight.target = cube;
                    break;
            }
        });
        render();
    
		var step = 0;
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
            sphereLightMesh.position.z = -8;
            sphereLightMesh.position.y = +(27 * (Math.sin(step / 3)));
            sphereLightMesh.position.x = 10 + (26 * (Math.cos(step / 3)));
				
            directionalLight.position.copy(sphereLightMesh.position);
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
效果:

特殊光源
1. THREE.HemisphereLight(半球光源)
使用半球光源可以创建出更加贴近自然的户外光照效果。在户外,并不是所有的光照都来自上方,还有大气的散射和地面以及其它物体的反射。THREE.HemisphereLight光源就是为了这种情形创建的。
它的属性很简单:
| 属性 | 描述 | 
|---|---|
| groundColor | 从地面发出的光线的颜色 | 
| color | 从天空发出的光线的颜色 | 
| intensity | 光线照射的强度 | 
<!-- chapter-03-05.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Hemisphere Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        scene.fog = new THREE.Fog(0xaaaaaa, 0.010, 200);  // 添加雾化效果
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
		
    	// 添加本地图片纹理(草地地面)
        var textureGrass = THREE.ImageUtils.loadTexture("../assets/textures/ground/grasslight-big.jpg");
        textureGrass.wrapS = THREE.RepeatWrapping;
        textureGrass.wrapT = THREE.RepeatWrapping;
        textureGrass.repeat.set(4, 4);
    	// 用本地图片做网格对象的材质
        var planeGeometry = new THREE.PlaneGeometry(1000, 200, 20, 20);
        var planeMaterial = new THREE.MeshLambertMaterial({map: textureGrass}); // 本地纹理材质
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true;
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff3333});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true;
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);
        var sphereGeometry = new THREE.SphereGeometry(4, 25, 25);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = 10;
        sphere.position.y = 5;
        sphere.position.z = 10;
        sphere.castShadow = true;
        scene.add(sphere);
        camera.position.x = -20;
        camera.position.y = 15;
        camera.position.z = 45;
        camera.lookAt(new THREE.Vector3(10, 0, 0));
        // 添加聚光灯光源
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 60, -10);
        spotLight0.lookAt(plane);
        scene.add(spotLight0);
		// 添加半球光源
        var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.6);
        hemiLight.position.set(0, 500, 0);
        scene.add(hemiLight);
		
    	// 添加平行光源
        var pointColor = "#ffffff";
        var dirLight = new THREE.DirectionalLight(pointColor);
        dirLight.position.set(30, 10, -50);
        dirLight.castShadow = true;
        dirLight.target = plane;
        dirLight.shadowCameraNear = 0.1;
        dirLight.shadowCameraFar = 200;
        dirLight.shadowCameraLeft = -50;
        dirLight.shadowCameraRight = 50;
        dirLight.shadowCameraTop = 50;
        dirLight.shadowCameraBottom = -50;
        dirLight.shadowMapWidth = 2048;
        dirLight.shadowMapHeight = 2048;
        scene.add(dirLight);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        var controls = new function () {
            this.hemisphere = true;   // 是否开启半球光源(通过光强为0来设置)
            this.color = 0x00ff00;    // 从地面发出的光线颜色
            this.skyColor = 0x0000ff; // 从天空发出的光线颜色
            this.intensity = 0.6;     // 光照强度
        };
        var gui = new dat.GUI();
        gui.add(controls, 'hemisphere').onChange(function (e) {
            if (!e) {
                hemiLight.intensity = 0;
            } else {
                hemiLight.intensity = controls.intensity;
            }
        });
        gui.addColor(controls, 'color').onChange(function (e) {
            hemiLight.groundColor = new THREE.Color(e);
        });
        gui.addColor(controls, 'skyColor').onChange(function (e) {
            hemiLight.color = new THREE.Color(e);
        });
        gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
            hemiLight.intensity = e;
        });
        render();
    
		var step = 0;
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
观察示例,通过开启/关闭半球光源,看场景中物体受反射光的影响。

2. THREE.AreaLight(区域光源)
区域光不是从某一个点发光,它是从一块区域发光,可以定义长方形的发光区域。它没有定义在WebGLRenderer渲染器中,因为会带来非常严重的性能损失。而是定义在WebGLDeferredRenderer渲染器中,它使用了一种不同的方法(分成多个步骤),相对标志渲染器WebGLRenderer,可以更好地处理复杂地光照(或者非常大量地光源)。
使用WebGLDeferredRenderer要额外引入一些外部库。好像新版区域光源也给加到标志渲染器了,本示例用的旧版。
<!-- chapter-03-06.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Area Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
	// 引入WebGLDeferredRenderer渲染器
    <script type="text/javascript" src="../libs/WebGLDeferredRenderer.js"></script>
    <script type="text/javascript" src="../libs/ShaderDeferred.js"></script>
    <script type="text/javascript" src="../libs/RenderPass.js"></script>
    <script type="text/javascript" src="../libs/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/FXAAShader.js"></script>
    <script type="text/javascript" src="../libs/MaskPass.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    var camera;
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        scene.add(camera);
		
        // 针对区域光源这种大量光源性能优化的渲染器
        var renderer = new THREE.WebGLDeferredRenderer({
            width: window.innerWidth,
            height: window.innerHeight,
            scale: 1, antialias: true,
            tonemapping: THREE.FilmicOperator, brightness: 2.5
        });
		
        // 地面
        var planeGeometry = new THREE.PlaneGeometry(70, 70, 1, 1);
        var planeMaterial = new THREE.MeshPhongMaterial({color: 0xffffff, specular: 0xffffff, shininess: 200});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 0;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);
        camera.position.x = 20;
        camera.position.y = 30;
        camera.position.z = 21;
        camera.lookAt(new THREE.Vector3(0, 0, -30));
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        // 固定的聚光灯光源
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 60, -10);
        spotLight0.intensity = 0.1;
        spotLight0.lookAt(plane);
        scene.add(spotLight0);
		// 添加红色区域光源1
        var areaLight1 = new THREE.AreaLight(0xff0000, 3);
        areaLight1.position.set(-10, 10, -35);
        areaLight1.rotation.set(-Math.PI / 2, 0, 0);
        areaLight1.width = 4;
        areaLight1.height = 9.9;
        scene.add(areaLight1);
		
        // 添加绿色区域光源2
        var areaLight2 = new THREE.AreaLight(0x00ff00, 3);
        areaLight2.position.set(0, 10, -35);
        areaLight2.rotation.set(-Math.PI / 2, 0, 0);
        areaLight2.width = 4;
        areaLight2.height = 9.9;
        scene.add(areaLight2);
		
        // 添加蓝色区域光源3
        var areaLight3 = new THREE.AreaLight(0x0000ff, 3);
        areaLight3.position.set(10, 10, -35);
        areaLight3.rotation.set(-Math.PI / 2, 0, 0);
        areaLight3.width = 4;
        areaLight3.height = 9.9;
        scene.add(areaLight3);
		
        // 红色长方形1(z为0)设置到区域光源1位置,用于标志光源的位置
        var planeGeometry1 = new THREE.BoxGeometry(4, 10, 0);
        var planeGeometry1Mat = new THREE.MeshBasicMaterial({color: 0xff0000});
        var plane1 = new THREE.Mesh(planeGeometry1, planeGeometry1Mat);
        plane1.position.copy(areaLight1.position);
        scene.add(plane1);
		// 绿色长方形2设置到区域光源2位置
        var planeGeometry2 = new THREE.BoxGeometry(4, 10, 0);
        var planeGeometry2Mat = new THREE.MeshBasicMaterial({color: 0x00ff00});
        var plane2 = new THREE.Mesh(planeGeometry2, planeGeometry2Mat);
        plane2.position.copy(areaLight2.position);
        scene.add(plane2);
		
        // 蓝色长方形3设置到区域光源3位置
        var planeGeometry3 = new THREE.BoxGeometry(4, 10, 0);
        var planeGeometry3Mat = new THREE.MeshBasicMaterial({color: 0x0000ff});
        var plane3 = new THREE.Mesh(planeGeometry3, planeGeometry3Mat);
        plane3.position.copy(areaLight3.position);
        scene.add(plane3);
        var controls = new function () {
            // 对应3块区域光的颜色和强度
            this.color1 = 0xff0000;
            this.intensity1 = 2;
            this.color2 = 0x00ff00;
            this.intensity2 = 2;
            this.color3 = 0x0000ff;
            this.intensity3 = 2;
        };
		
        var gui = new dat.GUI();
        // 改变光颜色和对应的长方形颜色
        gui.addColor(controls, 'color1').onChange(function (e) {
            areaLight1.color = new THREE.Color(e);
            planeGeometry1Mat.color = new THREE.Color(e);
            scene.remove(plane1);
            plane1 = new THREE.Mesh(planeGeometry1, planeGeometry1Mat);
            plane1.position.copy(areaLight1.position);
            scene.add(plane1);
        });
        gui.add(controls, 'intensity1', 0, 5).onChange(function (e) {
            areaLight1.intensity = e;
        });
        gui.addColor(controls, 'color2').onChange(function (e) {
            areaLight2.color = new THREE.Color(e);
            planeGeometry2Mat.color = new THREE.Color(e);
            scene.remove(plane2);
            plane2 = new THREE.Mesh(planeGeometry2, planeGeometry2Mat);
            plane2.position.copy(areaLight2.position);
            scene.add(plane2);
        });
        gui.add(controls, 'intensity2', 0, 5).onChange(function (e) {
            areaLight2.intensity = e;
        });
        gui.addColor(controls, 'color3').onChange(function (e) {
            areaLight3.color = new THREE.Color(e);
            planeGeometry3Mat.color = new THREE.Color(e);
            scene.remove(plane3);
            plane3 = new THREE.Mesh(planeGeometry1, planeGeometry3Mat);
            plane3.position.copy(areaLight3.position);
            scene.add(plane3);
        });
        gui.add(controls, 'intensity3', 0, 5).onChange(function (e) {
            areaLight3.intensity = e;
        });
        render();
        function render() {
            stats.update();
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
效果:

3. THREE.LensFlare(镜头光晕)
类似你直接朝着太阳拍照时就会出现镜头光晕效果。
光晕属性:
| 参数 | 描述 | 
|---|---|
| texture(纹理) | 纹理就是一个图片,用来决定光晕的形状 | 
| size(尺寸) | 指定光晕大小。如果指定为-1,那么将使用纹理本身的大小 | 
| distance(距离) | 从光源(0)到摄像机(1)的距离。 | 
| blending(混合) | 可以为光晕提供多种材质。混合模式决定了如何将它们混合在一起。 | 
| color(颜色) | 光晕的颜色 | 
示例:
<!-- chapter-03-07.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Lensflarest</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        scene.fog = new THREE.Fog(0xaaaaaa, 0.010, 200); // 添加雾化效果
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
        renderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
        // 创建草地地面
        var textureGrass = THREE.ImageUtils.loadTexture("../assets/textures/ground/grasslight-big.jpg");
        textureGrass.wrapS = THREE.RepeatWrapping;
        textureGrass.wrapT = THREE.RepeatWrapping;
        textureGrass.repeat.set(4, 4);
        var planeGeometry = new THREE.PlaneGeometry(1000, 200, 20, 20);
        var planeMaterial = new THREE.MeshLambertMaterial({map: textureGrass});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true;
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);
        // 创建立方体
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff3333});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true;
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);
		
    	// 创建球体
        var sphereGeometry = new THREE.SphereGeometry(4, 25, 25);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = 10;
        sphere.position.y = 5;
        sphere.position.z = 10;
        sphere.castShadow = true;
        scene.add(sphere);
        camera.position.x = -20;
        camera.position.y = 15;
        camera.position.z = 45;
        camera.lookAt(new THREE.Vector3(10, 0, 0));
        // 添加环境光
        var ambiColor = "#1c1c1c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);
        // 添加聚光灯
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 60, -10);
        spotLight0.lookAt(plane);
        scene.add(spotLight0);
		
    	// 添加平行光
        var pointColor = "#ffffff";
        var spotLight = new THREE.DirectionalLight(pointColor);
        spotLight.position.set(30, 10, -50);
        spotLight.castShadow = true;
        spotLight.shadowCameraNear = 0.1;
        spotLight.shadowCameraFar = 100;
        spotLight.shadowCameraFov = 50;
        spotLight.target = plane;
        spotLight.distance = 0;
        spotLight.shadowCameraNear = 2;
        spotLight.shadowCameraFar = 200;
        spotLight.shadowCameraLeft = -100;
        spotLight.shadowCameraRight = 100;
        spotLight.shadowCameraTop = 100;
        spotLight.shadowCameraBottom = -100;
        spotLight.shadowMapWidth = 2048;
        spotLight.shadowMapHeight = 2048;
        scene.add(spotLight);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        var controls = new function () {
            this.ambientColor = ambiColor;
            this.pointColor = pointColor;
            this.intensity = 0.1;
        };
        var gui = new dat.GUI();
        gui.addColor(controls, 'ambientColor').onChange(function (e) {
            ambientLight.color = new THREE.Color(e);
        });
        gui.addColor(controls, 'pointColor').onChange(function (e) {
            spotLight.color = new THREE.Color(e);
        });
        gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
            spotLight.intensity = e;
        });
		// 创建光晕纹理
        var textureFlare0 = THREE.ImageUtils.loadTexture("../assets/textures/lensflare/lensflare0.png");
    	// 创建镜头光晕,把它放在光源处(距离为0)
    	var flareColor = new THREE.Color(0xffaacc);
        var lensFlare = new THREE.LensFlare(textureFlare0, 350, 0.0, THREE.AdditiveBlending, flareColor);
		// 光源到摄像机附近添加新的光晕(使用的很淡的纹理),通过上面主光晕对象的add方法添加,增强表现效果,可以屏蔽对比。
    	var textureFlare3 = THREE.ImageUtils.loadTexture("../assets/textures/lensflare/lensflare3.png");
        lensFlare.add(textureFlare3, 60, 0.6, THREE.AdditiveBlending);
        lensFlare.add(textureFlare3, 70, 0.7, THREE.AdditiveBlending);
        lensFlare.add(textureFlare3, 120, 0.9, THREE.AdditiveBlending);
        lensFlare.add(textureFlare3, 70, 1.0, THREE.AdditiveBlending);
        lensFlare.position.copy(spotLight.position);
        scene.add(lensFlare);
        render();
    
		var step = 0;
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    };
    window.onload = init;
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>
效果:




















