Skip to content

环境光

此笔记记录于DISCOVER three.js,大多数为其中的摘要,少数为笔者自己的理解

基本介绍

在现实世界中,无数光线从场景中的所有物体表面反射和反弹无数次,随着每次反射或反弹颜色会逐渐消退变淡并改变颜色,直到最终到达我们的眼睛或相机。这创造了我们每天在周围世界看到的美丽而微妙的光影图案。

对我们来说不幸的是,计算机无法模拟无限。一种称为 光线追踪的技术可用于模拟几千条光线,每条光线在场景中反弹几次。但是,使用这种技术实时渲染帧需要太多的处理能力,因此光线追踪和 路径追踪等相关技术更适合创建预渲染图像或动画。

使用three.js创建高质量的照明就是选择这些技术的组合来创建完整的照明设置。在three.js中,将灯光类分为两类,以匹配两类灯光:

  1. 直接光照,模拟直接光照。
  2. 环境光,这是一种廉价且可信的间接照明方式。

基于图像的照明

基于图像的照明是一系列技术的名称,这些技术涉及预先计算照明信息并将其存储在纹理中。最重要的IBL技术是 环境映射(也称为反射映射),也就是您刚才设置的MeshBasicMaterial.envMap的值。

基于图像的照明 (IBL):场景背景反映在球体上

环境贴图通常使用专门的摄影技术或外部3D渲染程序生成。有几种格式用于存储生成的图像,其中两种在上面的场景中进行了演示:立方体贴图和等距矩形贴图。单击菜单中的选项以查看每个选项的示例。

环境照明

环境照明是一种伪造间接照明的方法,它既快速又易于设置,同时仍能提供合理的结果。three.js核心中有两个环境光类可用:

  • AmbientLight从各个方向向每个对象添加恒定数量的光。
  • 天空颜色和地面颜色之间的 HemisphereLight渐变,可用于模拟许多常见的照明场景。

与直射光一样,环境光也继承自 基类Light,因此它们具有.color.intensity属性。Light,反过来,继承自Object3D,所以所有的灯光也有.position.rotation.scale属性。但是,旋转或缩放灯光没有效果。改变AmbientLight的位置也没有效果。

环境光会影响场景中的所有对象。因此,无需为场景添加多个环境光。 与直射光不同(除了RectAreaLight),环境光不能投射阴影。

light.js

js
import {
  AmbientLight,  
  DirectionalLight,
  HemisphereLight,  
} from 'three';

function createLights() {
  // const ambientLight = new AmbientLight('white', 2);

  const ambientLight = new HemisphereLight( 
    'white', // bright sky color
    'darkslategrey', // dim ground color
    5, // intensity
  ); 

  const mainLight = new DirectionalLight('white', 5);
  mainLight.position.set(10, 10, 10);

  return { ambientLight, mainLight }; 
}

export { createLights };
  • AmbientLight是在three.js中伪造间接照明的最廉价的方法。这种类型的光会从各个方向向场景中的每个对象添加恒定数量的光照。放置此灯的位置无关紧要,相对于灯光放置其他对象的位置也无关紧要。

World.js

js
import { createCamera } from './components/camera.js';
import { createCube } from './components/cube.js';
import { createLights } from './components/lights.js';
import { createScene } from './components/scene.js';

import { createControls } from './systems/controls.js';
import { createRenderer } from './systems/renderer.js';
import { Resizer } from './systems/Resizer.js';
import { Loop } from './systems/Loop.js';

let camera;
let renderer;
let scene;
let loop;

class World {
  constructor(container) {
    camera = createCamera();
    renderer = createRenderer();
    scene = createScene();
    loop = new Loop(camera, scene, renderer);
    container.append(renderer.domElement);

    const controls = createControls(camera, renderer.domElement);

    const cube = createCube();
    const { ambientLight, mainLight } = createLights(); 

    loop.updatables.push(controls);
    scene.add(ambientLight, mainLight, cube); 

    const resizer = new Resizer(container, camera, renderer);
  }

  render() {
    // draw a single frame
    renderer.render(scene, camera);
  }

  start() {
    loop.start();
  }

  stop() {
    loop.stop();
  }
}

export { World };

HemisphereLight

立方体背面的照明看起来相当暗淡。为了使基于AmbientLightDirectionalLight灯光照明的场景看起来不错,我们需要添加具有不同方向和强度的多个定向灯。对于 使用多个直射灯的设置,这会遇到我们上面描述的许多相同问题。正如我们稍后会看到的,HemisphereLight这里给出了更好的结果,几乎没有额外的性能成本。

这并不意味着AmbientLight是没用的。例如HemisphereLight,它并不适合所有场景,在这种情况下,您可以退回到AmbientLight。此外,这种灯照是增加整体亮度或为场景添加轻微色调的最廉价的方法。您有时会发现它对调制其他类型的光照(例如环境贴图)或调整阴影暗度很有用。

  • AmbientLight不显示深度
  • 来自 HemisphereLight的光在场景顶部的天空颜色和场景底部的地面颜色之间渐变。

我们可以通过改变灯光的.position来调整天空和地面之间的渐变。与所有灯光类型一样,.rotation.scale没有效果。HemisphereLight构造函数采用与所有其他灯光相同的.color.intensity参数,但有一个附加 .groundColor参数。通常,我们会使用明亮的天空.color和更暗的地面.groundColor

js
const ambientLight = new HemisphereLight(
  'white', // bright sky color
  'darkslategrey', // dim ground color
  5, // intensity
);

但是,由于HemisphereLight光线不会从任何特定方向照射,因此该场景中没有闪亮的高光(又名 镜面高光。这就是为什么我们通常将这种类型的灯与至少一个直射灯配对。