---
title: "Three.js中光源"
description: "上述都是基于`THREE.Light`对象扩展."
url: "https://hicc.pro/p/three.js/threejs-lighting"
author: "tyler wang"
published: "2023-01-31T09:45:36.000Z"
updated: "2023-02-19T15:17:43.000Z"
category: "Threejs"
lang: "zh-CN"
site: "Hipo日志"
---

# Three.js中光源

### Three.js中光源

| 光源 |  |
| -------- | -------- | 
| `THREE.AmbientLight`     | 基本光源，该光源的颜色会叠加到场景现有物体的颜色上     | 
| `THREE.PointLight`     | 点光源，从空间上的一点向所有方向发射光线。点光源不能用来创建阴影(新版本支持了) | 
| `THREE.SpotLight`     | 这种光源有聚光的效果，类似台灯、吊灯或者手电筒。这种光源可以投射阴影     |
| `THREE.DirectionalLight`     | 无限光，从这种光源发出的光可以看作是平行的，就像太光，这种光源可以创建阴影     | 
| `THREE.HemisphereLight`     | 一种特殊的光源，可以通过模拟反光面和光线微弱的太空来创建更加自然的室外光线。此光源不提供任何与阴影相关的功能     |
| `THREE.AreaLight`     | 使用这种光源可以指定散发光线的平面，而不是一个点。不投射任何阴影  |
| `THREE.LensFlare`     | 这不是一种光源，但是通过`THREE.LensFlare`为场景中的光源添加镜头光晕的效果 |

上述都是基于`THREE.Light`对象扩展.

![](https://image.hicc.pro/pro/20230201232753FgE8xolxCSUqr0G5AJqsN4rHdPSWy8eqwtoTTBppt0DAMml5h.png)

### 基础光源

#### `THREE.AmbientLight` 

创建`AmbientLight`很简单，一般和其他光源配合使用来产生阴影。
```js
var ambientLight = new THREE.AmbientLight("#606008", 1);
scene.add(ambientLight);
```

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/01-ambient-light.html)

```js
function init() {

  // use the defaults
  var stats = initStats();
  var renderer = initRenderer();
  var camera = initCamera();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

  // add ambient lighting
  var ambientLight = new THREE.AmbientLight("#606008", 1);
  scene.add(ambientLight);

  // add spotlight for the shadows
  var spotLight = new THREE.SpotLight(0xffffff, 1, 180, Math.PI / 4);
  spotLight.shadow.mapSize.set(2048, 2048);
  spotLight.position.set(-30, 40, -10);
  spotLight.castShadow = true;
  scene.add(spotLight);

  // add a simple scene
  addHouseAndTree(scene)

  // add controls
  var controls = setupControls();

  // call the render function
  render();

  function render() {
    stats.update();
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }

  function setupControls() {
    var controls = new function () {
      this.intensity = ambientLight.intensity;
      this.ambientColor = ambientLight.color.getStyle();
      this.disableSpotlight = false;
    };

    var gui = new dat.GUI();
    gui.add(controls, 'intensity', 0, 3, 0.1).onChange(function (e) {
      ambientLight.color = new THREE.Color(controls.ambientColor);
      ambientLight.intensity = controls.intensity;
    });
    gui.addColor(controls, 'ambientColor').onChange(function (e) {
      ambientLight.color = new THREE.Color(controls.ambientColor);
      ambientLight.intensity = controls.intensity;
    });
    gui.add(controls, 'disableSpotlight').onChange(function (e) {
      spotLight.visible = !e;
    });

    return controls;
  }
}
```

#### `THREE.SpotLight`聚光灯

创建聚光灯`SpotLight`的经典步骤

```js
var spotLight = new THREE.SpotLight("#ffffff");
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 100;
spotLight.target = plane;
spotLight.distance = 0;
spotLight.angle = 0.4;
spotLight.shadow.camera.fov = 120;
```

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/02-spot-light.html)

```js
function init() {

  // use the defaults
  var stats = initStats();
  var renderer = initRenderer();
  var camera = initCamera();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

  var cubeAndSphere = addDefaultCubeAndSphere(scene);
  var cube = cubeAndSphere.cube;
  var sphere = cubeAndSphere.sphere;
  var plane = addGroundPlane(scene);
  

  // add subtle ambient lighting
  var ambiColor = "#1c1c1c";
  var ambientLight = new THREE.AmbientLight(ambiColor);
  scene.add(ambientLight);

  // add spotlight for a bit of light
  var spotLight0 = new THREE.SpotLight(0xcccccc);
  spotLight0.position.set(-40, 30, -10);
  spotLight0.lookAt(plane);
  scene.add(spotLight0);

  // add target and light
  var target = new THREE.Object3D();
  target.position = new THREE.Vector3(5, 0, 0);

  var spotLight = new THREE.SpotLight("#ffffff");
  spotLight.position.set(-40, 60, -10);
  spotLight.castShadow = true;
  spotLight.shadow.camera.near = 1;
  spotLight.shadow.camera.far = 100;
  spotLight.target = plane;
  spotLight.distance = 0;
  spotLight.angle = 0.4;
  spotLight.shadow.camera.fov = 120;
  scene.add(spotLight);
  var debugCamera = new THREE.CameraHelper(spotLight.shadow.camera);

  var pp = new THREE.SpotLightHelper(spotLight)
  scene.add(pp)

  // add a small sphere simulating the 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, 20, 3);
  scene.add(sphereLightMesh);

  // for controlling the rendering
  var step = 0;
  var invert = 1;
  var phase = 0;

  var controls = setupControls();
  render();

  function render() {
    stats.update();
    // rotate the cube around its axes
    cube.rotation.x += controls.rotationSpeed;
    cube.rotation.y += controls.rotationSpeed;
    cube.rotation.z += controls.rotationSpeed;

    // bounce the sphere up and down
    step += controls.bouncingSpeed;
    sphere.position.x = 20 + (10 * (Math.cos(step)));
    sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));

    // move the light simulation
    if (!controls.stopMovingLight) {
      if (phase > 2 * Math.PI) {
        invert = invert * -1;
        phase -= 2 * Math.PI;
      } else {
        phase += controls.rotationSpeed;
      }
      sphereLightMesh.position.z = +(7 * (Math.sin(phase)));
      sphereLightMesh.position.x = +(14 * (Math.cos(phase)));
      sphereLightMesh.position.y = 15;

      if (invert < 0) {
        var pivot = 14;
        sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;
      }

      spotLight.position.copy(sphereLightMesh.position);
    }

    pp.update();
    // render using requestAnimationFrame
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }

  function setupControls() {
    var controls = new function () {
      this.rotationSpeed = 0.03;
      this.bouncingSpeed = 0.03;
      this.ambientColor = ambiColor;
      this.pointColor = spotLight.color.getStyle();
      this.intensity = 1;
      this.distance = 0;
      this.angle = 0.1;
      this.shadowDebug = false;
      this.castShadow = true;
      this.target = "Plane";
      this.stopMovingLight = false;
      this.penumbra = 0;
    };

    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, 'penumbra', 0, 1).onChange(function (e) {
      spotLight.penumbra = e;
    });

    gui.add(controls, 'distance', 0, 200).onChange(function (e) {
      spotLight.distance = e;
    });

    gui.add(controls, 'shadowDebug').onChange(function (e) {
      if (e) {
        scene.add(debugCamera);
      } else {
        scene.remove(debugCamera);
      }
    });

    gui.add(controls, 'castShadow').onChange(function (e) {
      spotLight.castShadow = e;
    });

    gui.add(controls, 'target', ['Plane', 'Sphere', 'Cube']).onChange(function (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;
    });

    return controls;
  }

}
```

官方文档：https://threejs.org/docs/index.html#api/zh/lights/SpotLight

| `THREE.SpotLight` 属性 | 描述 | 默认值 |
| -------- | -------- | -------- |
| `angle` （角度）     | 光源发射出的光束的宽度，单位是弧度     | `Math.PI/3`     |
| `catShadow` （投影）     | 如果设为`true`，光源会产生阴影     |    |
| `color` （颜色）     | 光源颜色 |    |
| `decay` （衰减）     | 光源强度随着离开光源的激励而衰减的速度。该值为2时更接近现实中的效果。只有当`WebGLRenderer`的属性`physicallyCorrectLights`（物理正确光源）被设置为启用时，才生效 |  1  |
| `distance` （距离）     | 光源照射距离     |   0 （意味着光线强度不会随着距离增加而减弱） |
| `intensity` （强度）     | 光源照射的强度| 1   |
| `penumbra` （半影区）     | 设置聚光灯的锥形照明区域在其区域边缘附近的平滑衰减速度 |  0  |
| `position` （位置）     | 光源在场景中的位置     |    |
| `power` （功率）     | 当`WebGLRenderer`的属性`physicallyCorrectLights`（物理正确光源）被设置为启用时，可设置光源的功率，单位为流明 |  `4*Math.PI`  |
| `target` （目标）     | `THREE.SpotLight` 的指向很重要。指向场景中特定的对象或位置。需要一个`THREE.Object3D`对象（`THREE.mesh`）。     |    |
| `visible` （是否可见）     | `true`时光源就会打开；`false`光源关闭 |    |

 `THREE.SpotLight` 的`shadow`为`endable`时：

| `THREE.SpotLight.shadow`属性 | 描述 | 默认值 |
| -------- | -------- | -------- |
| `shadow.bias` (阴影偏移)     | 用来偏移阴影的位置。当你使用非常薄的对象时，可以用来解决奇怪的效果(将奇设置为更小的值，例如0.01)  |0  |
| `shadow.camera.far` (投影远点)     | 到距离光源的那一个位置可以产生阴影。 你可以设置所有提供给`THREE.PerspectiveCamera`的其他属性    | 5000     |
| `shadow.camera.fov` (投影视场)     | 用于生成阴影的视场大小     | 50     |
| `shadow.camera.near` (投影近点)     | 从距离光源的那一个位置可以产生阴影    | 50     |
| `shadow.mapSize.width` 和`shadow.mapSize.height` (阴影映射宽高)     | 决定了有多少像素用来生成阴影。当阴影有锯齿边缘，或者看起来不光滑的时候，可以增加这个值。在场景渲染之后无法更改     | 512     |
| `shadow.radius` (半径)     | 当值大于1时，阴影的边缘将有平滑的效果。*该属性在`THREE.WebGIRenderer`的`shadowMap.type`属性为`Three.BasicShadowMap`时无效*     |      |

##### 添加摄像机或者光源辅助线

如上述demo所示，开发3D时候，添加辅助线通常会很方便，也很有用

添加摄像机辅助线

```js
var debugCamera = new THREE.CameraHelper(spotLight.shadow.camera);

scene.add(debugCamera)
```
类似聚光灯也能添加辅助线，可以用来观察形状和朝向
```js
var helper = new THREE.SpotLightHelper(spotLight)
scene.add(helper)

function render() {
	...
	helper.update()
	...
}
```

 

#### `THREE.PointLight`点光源

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/03-point-light.html)

```js
function init() {

  // use the defaults
  var stats = initStats();
  var renderer = initRenderer();

  var camera = initCamera();
  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

  // add a simple scene
  addHouseAndTree(scene)

  // add subtle ambient lighting
  var ambientLight = new THREE.AmbientLight("#0c0c0c");
  scene.add(ambientLight);

  // the point light where working with
  var pointColor = "#ccffcc";
  var pointLight = new THREE.PointLight(pointColor);
  pointLight.decay = 0.1

  pointLight.castShadow = true;

  scene.add(pointLight);

  var helper = new THREE.PointLightHelper(pointLight);
  // scene.add(helper);

  var shadowHelper = new THREE.CameraHelper(pointLight.shadow.camera)
  // scene.add(shadowHelper)

  // add a small sphere simulating the pointlight
  var sphereLight = new THREE.SphereGeometry(0.2);
  var sphereLightMaterial = new THREE.MeshBasicMaterial({
    color: 0xac6c25
  });
  var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
  sphereLightMesh.position = new THREE.Vector3(3, 0, 5);
  scene.add(sphereLightMesh);

  // call the render function
  var step = 0;

  // used to determine the switch point for the light animation
  var invert = 1;
  var phase = 0;

  var controls = setupControls();
  render();

  function render() {

    helper.update();
    shadowHelper.update();

    stats.update();
    pointLight.position.copy(sphereLightMesh.position);
    trackballControls.update(clock.getDelta());

    // move the light simulation
    if (phase > 2 * Math.PI) {
      invert = invert * -1;
      phase -= 2 * Math.PI;
    } else {
      phase += controls.rotationSpeed;
    }
    sphereLightMesh.position.z = +(25 * (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;
    }

    // render using requestAnimationFrame
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }

  function setupControls() {
    var controls = new function () {
      this.rotationSpeed = 0.01;
      this.bouncingSpeed = 0.03;
      this.ambientColor = ambientLight.color.getStyle();;
      this.pointColor = pointLight.color.getStyle();;
      this.intensity = 1;
      this.distance = pointLight.distance;
    };

    

    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, 'distance', 0, 100).onChange(function (e) {
      pointLight.distance = e;
    });

    gui.add(controls, 'intensity', 0, 3).onChange(function (e) {
      pointLight.intensity = e;
    });

    return controls;
  }
}
```

官方文档：https://threejs.org/docs/index.html#api/zh/lights/PointLight

| `THREE.PointLight`属性 | 描述 | 默认值  |
| -------- | -------- | -------- |
| `color`     | 光源颜色 |      |
| `distance` （距离）| 光源着色的距离     |   0（意味着光的强度不会随着距离增加而减少）   |
| `intensity` （强度）    | 光源照射的强度     | 1     |
| `position` （位置）   | 光源在场景的位置     |      |
| `visible`  （是否可见）| `true` ｜ `false` |      |
| `decay`  （衰减）| 光源强度随着离开距离而衰减的速度。 `2`时接近现实世界中效果。当`WebGLRenderer`的属性`physicallyCorrectLights`（物理正确光源）被设置为启用时`decay`才有效。     |1|
| `power`  （功率）| 当`WebGLRenderer`的属性`physicallyCorrectLights`（物理正确光源）被设置为启用时，可设置光源的功率，单位为流明。该属性与`intensity`属性为简单的线性关系(`power = instensity * 4 Math.PI`) |  `4*Math.PI`     |

创建 `THREE.PointLight`点光源:

```js
var pointColor = "#ccffcc";
var pointLight = new THREE.PointLight(pointColor);
pointLight.decay = 0.1
pointLight.castShadow = true;
scene.add(pointLight);
```

#### `THREE.DirectionalLight`平行光

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/04-directional-light.html)

```js
function init() {

  // use the defaults
  var stats = initStats();
  var renderer = initRenderer();
  var camera = initCamera();
  camera.position.set(-80, 80, 80);
  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

  // create the ground plane
  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;

  // rotate and position the plane
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 15;
  plane.position.y = -5;
  plane.position.z = 0;

  // add the plane to the scene
  scene.add(plane);

  // create a cube
  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;

  // position the cube
  cube.position.x = -4;
  cube.position.y = 3;
  cube.position.z = 0;

  // add the cube to the scene
  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);

  // position the sphere
  sphere.position.x = 20;
  sphere.position.y = 0;
  sphere.position.z = 2;
  sphere.castShadow = true;

  // add the sphere to the scene
  scene.add(sphere);

  // add subtle ambient lighting
  var ambiColor = "#1c1c1c";
  var ambientLight = new THREE.AmbientLight(ambiColor);
  scene.add(ambientLight);

  var target = new THREE.Object3D();
  target.position = new THREE.Vector3(5, 0, 0);

  var pointColor = "#ff5808";
  var directionalLight = new THREE.DirectionalLight(pointColor);
  directionalLight.position.set(-40, 60, -10);
  directionalLight.castShadow = true;
  directionalLight.shadow.camera.near = 2;
  directionalLight.shadow.camera.far = 80;
  directionalLight.shadow.camera.left = -30;
  directionalLight.shadow.camera.right = 30;
  directionalLight.shadow.camera.top = 30;
  directionalLight.shadow.camera.bottom = -30;

  directionalLight.intensity = 0.5;
  directionalLight.shadow.mapSize.width = 1024;
  directionalLight.shadow.mapSize.height = 1024;

  scene.add(directionalLight);
  var shadowCamera = new THREE.CameraHelper(directionalLight.shadow.camera)

  // add a small sphere simulating the 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, 20, 3);
  scene.add(sphereLightMesh);
  // call the render function
  var step = 0;
  var invert = 1;
  var phase = 0;

  var controls = new function () {
    this.rotationSpeed = 0.03;
    this.bouncingSpeed = 0.03;
    this.ambientColor = ambiColor;
    this.pointColor = pointColor;
    this.intensity = 0.5;
    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, 'debug').onChange(function (e) {
    e ? scene.add(shadowCamera) : scene.remove(shadowCamera);
  });

  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();

  function render() {
    stats.update();
    trackballControls.update(clock.getDelta());

    // rotate the cube around its axes
    cube.rotation.x += controls.rotationSpeed;
    cube.rotation.y += controls.rotationSpeed;
    cube.rotation.z += controls.rotationSpeed;

    // bounce the sphere up and down
    step += controls.bouncingSpeed;
    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);

    // render using requestAnimationFrame
    requestAnimationFrame(render);

    renderer.render(scene, camera);
  }
}
```

官网文档：https://threejs.org/docs/index.html#api/zh/lights/DirectionalLight

`THREE.DirectionalLight`平行光就类似太阳对于地球而言，光线是“平行”的。和`THREE.SpotLight`聚光灯等最大的区别是：平行光不会离目标越远越暗。

平行光形成的阴影不是光锥，而是立方体。和`THREE.SpotLight`一样，包围对象的空间定义越紧密，投影的效果约好。

可以这样调整阴影下效果：

```js
directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 2;
directionalLight.shadow.camera.far = 80;
directionalLight.shadow.camera.left = -30;
directionalLight.shadow.camera.right = 30;
directionalLight.shadow.camera.top = 30;
directionalLight.shadow.camera.bottom = -30;
```

### 特殊光源

#### `THREE.HemisphereLight`半球光光源

要模拟户外的效果可以通过设置`THREE.DirectionalLight`平行光模拟太阳配合`THREE.AmbientLight`给场景提供基础色。但是这样不太自然。因为大自然中光不只有上方的太阳光，更多的是大气的散射和地面以及其他物体的反射。`THREE.HemisphereLight`半球光光源就是来解决这个问题的。

官方文档：https://threejs.org/docs/index.html#api/zh/lights/HemisphereLight

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/05-hemisphere-light.html)

```js
function init() {

  var stats = initStats();
  var renderer = initRenderer();
  var camera = initCamera();

  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

  // create the ground plane
  var textureGrass = new THREE.TextureLoader().load("/assets/threejs/assets/textures/ground/grasslight-big.jpg");
  textureGrass.wrapS = THREE.RepeatWrapping;
  textureGrass.wrapT = THREE.RepeatWrapping;
  textureGrass.repeat.set(10, 10);

  var planeGeometry = new THREE.PlaneGeometry(1000, 1000, 20, 20);
  var planeMaterial = new THREE.MeshLambertMaterial({
    map: textureGrass
  });

  //        var planeMaterial = new THREE.MeshLambertMaterial();
  var plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.receiveShadow = true;

  // rotate and position the plane
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 15;
  plane.position.y = 0;
  plane.position.z = 0;

  // add the plane to the scene
  scene.add(plane);

  // create a cube
  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;

  // position the cube
  cube.position.x = -4;
  cube.position.y = 3;
  cube.position.z = 0;

  // add the cube to the scene
  scene.add(cube);

  var sphereGeometry = new THREE.SphereGeometry(4, 25, 25);
  var sphereMaterial = new THREE.MeshPhongMaterial({
    color: 0x7777ff
  });
  var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

  // position the sphere
  sphere.position.x = 10;
  sphere.position.y = 5;
  sphere.position.z = 10;
  sphere.castShadow = true;

  // add the sphere to the scene
  scene.add(sphere);

  // add spotlight for a bit of light
  var spotLight0 = new THREE.SpotLight(0xcccccc);
  spotLight0.position.set(-40, 60, -10);
  spotLight0.lookAt(plane);
  scene.add(spotLight0);

  var target = new THREE.Object3D();
  target.position = new THREE.Vector3(5, 0, 0);

  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.shadow.camera.near = 0.1;
  dirLight.shadow.camera.far = 200;
  dirLight.shadow.camera.left = -50;
  dirLight.shadow.camera.right = 50;
  dirLight.shadow.camera.top = 50;
  dirLight.shadow.camera.bottom = -50;
  dirLight.shadow.mapSize.width = 2048;
  dirLight.shadow.mapSize.height = 2048;
  scene.add(dirLight);

  // call the render function
  var step = 0;

  // used to determine the switch point for the light animation
  var invert = 1;
  var phase = 0;
  var controls = addControls();

  render();

  function render() {
    stats.update();

    trackballControls.update(clock.getDelta());

    // rotate the cube around its axes
    cube.rotation.x += controls.rotationSpeed;
    cube.rotation.y += controls.rotationSpeed;
    cube.rotation.z += controls.rotationSpeed;

    // bounce the sphere up and down
    step += controls.bouncingSpeed;
    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 addControls() {
    var controls = new function () {
      this.rotationSpeed = 0.03;
      this.bouncingSpeed = 0.03;
      this.hemisphere = true;
      this.color = 0x0000ff;
      this.groundColor = 0x00ff00;
      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, 'groundColor').onChange(function (e) {
      hemiLight.groundColor = new THREE.Color(e);
    });
    gui.addColor(controls, 'color').onChange(function (e) {
      hemiLight.color = new THREE.Color(e);
    });
    gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
      hemiLight.intensity = e;
    });

    return controls;
  }
}
```

仔细观察，上述场景中球体表面底部有接近草地的绿色，而顶部有接近天空的蓝色(设置color).

创建`THREE.HemisphereLight`半球光光源：

```js
var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.6);
hemiLight.position.set(0, 500, 0);
scene.add(hemiLight);
```

| `THREE.HemisphereLight`属性 | Column 2 | 
| -------- | -------- | 
| `groundColor`     | 从地面发出光线的颜色 | 
| `color`     | 从天空发出的光线的颜色  | 
| `intensity`     |光线照射的强度  | 

#### `THREE.AreaLight`区域光

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/06-area-light.html)

```js
function init() {

  var stats = initStats();
  var renderer = initRenderer({
    antialias: true
  });
  var camera = initCamera();
  
  camera.position.set(-50, 30, 50)
  // camera.lookAt(new THREE.Vector3(0, 0, -35));

  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

  // create the ground plane
  var planeGeometry = new THREE.PlaneGeometry(70, 70, 1, 1);
  var planeMaterial = new THREE.MeshStandardMaterial({
    roughness: 0.044676705160855, // calculated from shininess = 1000
    metalness: 0.0

  });
  var plane = new THREE.Mesh(planeGeometry, planeMaterial);
  // plane.receiveShadow  = true;

  // rotate and position the plane
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 0;
  plane.position.y = 0;
  plane.position.z = 0;

  // add the plane to the scene
  scene.add(plane);

  // call the render function
  var step = 0;

  var spotLight0 = new THREE.SpotLight(0xcccccc);
  spotLight0.position.set(-40, 60, -10);
  spotLight0.intensity = 0.1;
  spotLight0.lookAt(plane);
  scene.add(spotLight0);

  var areaLight1 = new THREE.RectAreaLight(0xff0000, 500, 4, 10);
  areaLight1.position.set(-10, 10, -35);
  scene.add(areaLight1);

  var areaLight2 = new THREE.RectAreaLight(0x00ff00, 500, 4, 10);
  areaLight2.position.set(0, 10, -35);
  scene.add(areaLight2);

  var areaLight3 = new THREE.RectAreaLight(0x0000ff, 500, 4, 10);
  areaLight3.position.set(10, 10, -35);
  scene.add(areaLight3);

  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);

  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);

  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 () {
    this.rotationSpeed = 0.02;
    this.color1 = 0xff0000;
    this.intensity1 = 500;
    this.color2 = 0x00ff00;
    this.intensity2 = 500;
    this.color3 = 0x0000ff;
    this.intensity3 = 500;
  };

  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, 1000).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, 1000).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, 1000).onChange(function (e) {
    areaLight3.intensity = e;
  });

  render();

  function render() {
    stats.update();
    trackballControls.update(clock.getDelta());

    // render using requestAnimationFrame
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }
}
```

新版貌似改为`THREE.RectAreaLight`。https://threejs.org/docs/index.html#api/zh/lights/RectAreaLight

#### `Lensflare`镜头光晕

创建镜头光晕效果。

官方文档：https://threejs.org/docs/index.html?q=lens#examples/zh/objects/Lensflare

[在线示例 / Live demo](https://hicc.pro/assets/threejs/src/chapter-03/07-lensflares.html)

```js
function init() {

  var stats = initStats();
  var renderer = initRenderer({
    alpha: true
  });

  var camera = initCamera();
  camera.position.x = -20;
  camera.position.y = 10;
  camera.position.z = 45;
  camera.lookAt(new THREE.Vector3(10, 0, 0));

  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();

  // create a scene, that will hold all our elements such as objects, cameras and lights.
  var scene = new THREE.Scene();

	
  // create the ground plane
  var textureGrass = new THREE.TextureLoader().load("/assets/threejs/assets/textures/ground/grasslight-big.jpg");
  textureGrass.wrapS = THREE.RepeatWrapping;
  textureGrass.wrapT = THREE.RepeatWrapping;
  textureGrass.repeat.set(10, 10);

  var planeGeometry = new THREE.PlaneGeometry(1000, 1000, 20, 20);
  var planeMaterial = new THREE.MeshLambertMaterial({
    map: textureGrass
  });
  var plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.receiveShadow = true;

  // rotate and position the plane
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 15;
  plane.position.y = 0;
  plane.position.z = 0;

  // add the plane to the scene
  scene.add(plane);

  // create a cube
  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;

  // position the cube
  cube.position.x = -4;
  cube.position.y = 3;
  cube.position.z = 0;

  // add the cube to the scene
  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);

  // position the sphere
  sphere.position.x = 10;
  sphere.position.y = 5;
  sphere.position.z = 10;
  sphere.castShadow = true;

  // add the sphere to the scene
  scene.add(sphere);

  // add subtle ambient lighting
  var ambiColor = "#1c1c1c";
  var ambientLight = new THREE.AmbientLight(ambiColor);
  scene.add(ambientLight);

  // add spotlight for a bit of light
  var spotLight0 = new THREE.SpotLight(0xcccccc);
  spotLight0.position.set(-40, 60, -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);
  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);

  // call the render function
  var step = 0;

  // used to determine the switch point for the light animation
  var invert = 1;
  var phase = 0;

  var controls = new function () {
    this.rotationSpeed = 0.03;
    this.bouncingSpeed = 0.03;
    this.ambientColor = ambiColor;
    this.pointColor = pointColor;
    this.intensity = 0.1;
    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) {
    spotLight.color = new THREE.Color(e);
  });

  gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
    spotLight.intensity = e;
  });
	
	var textureFlare0 = THREE.ImageUtils.loadTexture("/assets/threejs/assets/textures/flares/lensflare0.png");
  var textureFlare3 = THREE.ImageUtils.loadTexture("/assets/threejs/assets/textures/flares/lensflare3.png");

  var flareColor = new THREE.Color(0xffaacc);

  var lensFlare = new THREE.Lensflare();

  lensFlare.addElement(new THREE.LensflareElement(textureFlare0, 350, 0.0, flareColor));
  lensFlare.addElement(new THREE.LensflareElement(textureFlare3, 60, 0.6, flareColor));
  lensFlare.addElement(new THREE.LensflareElement(textureFlare3, 70, 0.7, flareColor));
  lensFlare.addElement(new THREE.LensflareElement(textureFlare3, 120, 0.9, flareColor));
  lensFlare.addElement(new THREE.LensflareElement(textureFlare3, 70, 1.0, flareColor));
  spotLight.add(lensFlare);

  render();

  function render() {
    stats.update();
    trackballControls.update(clock.getDelta());
    // rotate the cube around its axes
    cube.rotation.x += controls.rotationSpeed;
    cube.rotation.y += controls.rotationSpeed;
    cube.rotation.z += controls.rotationSpeed;

    // bounce the sphere up and down
    step += controls.bouncingSpeed;
    sphere.position.x = 20 + (10 * (Math.cos(step)));
    sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));

    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }
};
```

创建镜头光晕：

```js
var lensFlare = new THREE.Lensflare(texture, size, distance, blending, color, opacity);
```

| `THREE.Lensflare`参数 | 描述 |
| -------- | -------- | 
| `texture`（纹理）    | 纹理就是一个图片，决定光晕的形状     |
| `size`     | 指定光晕的尺寸，单位像素。如果-1，将使用纹理本身的尺寸 |
| `distance`（距离）    | 从光源(0)到摄像机(1)的距离。 使用这个属性，设置镜头光晕在正确的位置   |
| `blending`（混合）   | 可以为镜头光晕设置多个材质。混合模式决定混合方式。默认`THREE.AdditiveBlending` |
| `color`    | 光晕的颜色  |
| `opacity`     |光晕的透明度。 `0`完全透明，`1`完全不透明  |

---

原文 / Source: <https://hicc.pro/p/three.js/threejs-lighting>
