ThreeJs--光源

250 阅读14分钟

概述

本章能学习到的内容

  1. Three中可用的光源
  2. 特定光源的使用时机
  3. 如何调整和配置所有光源的行为
  4. 如何创建光晕

不同种类的光源

基础光源

THREE.AmbientLight

在创建THREE.AmbientLight时,颜色将会应用到全局。该光线没有特别的来源方向,不会产生阴影。通常和其他种类的光源一起使用,目的是弱化阴影或者给场景添加额外的一种颜色。

function initStats(type) {

    var panelType = (typeof type !== 'undefined' && type) && (!isNaN(type)) ? parseInt(type) : 0;
    var stats = new Stats();

    stats.showPanel(panelType); // 0: fps, 1: ms, 2: mb, 3+: custom
    document.body.appendChild(stats.dom);

    return stats;
}
function initRenderer(additionalProperties) {

    var props = (typeof additionalProperties !== 'undefined' && additionalProperties) ? additionalProperties : {};
    var renderer = new THREE.WebGLRenderer(props);
    renderer.shadowMap.enabled = true;
    renderer.shadowMapSoft = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;

    renderer.setClearColor(new THREE.Color(0x000000));
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    document.getElementById("webgl-output").appendChild(renderer.domElement);

    return renderer;
}
function initCamera(initialPosition) {
    var position = (initialPosition !== undefined) ? initialPosition : new THREE.Vector3(-30, 40, 30);

    var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.copy(position);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    return camera;
}
function init () {
    var stats = initStats();
    var renderer = initRenderer();
    // 设置相机及摄像机位置
    var camera = initCamera();
    // 创建一个场景
    var scene = new THREE.Scene();
    // 添加环境光
    var ambientLight = new THREE.AmbientLight("#606008", 1);
    // 将环境光添加到场景中
    scene.add(ambientLight);
    // 添加聚光灯
    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);
    // 添加一个简单的场景
    addHouseAndTree(scene);
    // 添加控制
    var controls = setupControls();
    // 渲染
    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;
    }
}
代码解释一
        // 添加环境光
        var ambientLight = new THREE.AmbientLight("#606008", 1);
        // 将环境光添加到场景中
        scene.add(ambientLight);
        ......
        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;
        });
  1. 不需要指定位置且会应用到全局
  2. 通过scene.add(ambientLight)添加到场景
  3. intensity参数指定光的强度,默认值为1
  4. dat.GUI控制菜单,gui.addColor().onChange(function(e){}),控制菜单变化,需要调用方法
THREE.Color对象

需要为材质或者灯光指定颜色时,可以使用THREE.Color对象。它可以基于以下任何一种方式来完成:

  1. 无参构造:构建变颜色的对象
  2. 十六进制数值:0xababab,这是最佳的颜色对象构造形式
  3. 十六进制字符串:“#ababab”
  4. RGB字符串:“rgb(255,0,0)”
  5. 颜色名称:“red”
  6. HSL字符串:“hsl(0%,100%,50%)”
  7. 分离的RGB值:三个值都是0到1之间的值,“1.0.0”

u=3080407153,1703675698&fm=253&fmt=auto&app=138&f=PNG.webp

  1. 点光源:从指定一点向所有方向发射光线
  2. 聚光灯光源:从指定一点以锥形发射光线
  3. 平行光源:不是从一个点发射光线,而是从二维平面发射光线,光线彼此平行

THREE.SpotLight

聚光灯光源是经常使用的光源之一,特别是如果想使用阴影的话。该光源有锥形效果,有方向和角度。

属性描述
angle(角度)光源发射出光束的宽度,单位是弧度,默认是Math.PI/3
castShadow(投影)如果设置为true,则光源会产生阴影
color(颜色)光源的颜色
decay(衰减)光源强度随着离开光源的距离而衰减的速度,该值为2时更接近现实世界中的效果
distance(距离)光源的照射距离。默认值为0,这意味着光线强度不会随着距离的增加而减弱
intensity(强度)光源照射的强度
penumbra(半影区)该属性设置聚光灯的锥形照明区域在其区域边缘附近的平滑衰减速度
position(位置)光源在场景中的位置
power(功率)指定光源的功率,以流明为单位
target(目标)光源照射场景中的特定对象或者位置
visible(是否可见)true,光源打开;false,光源关闭

当THREE.SpotLight的shadow属性为enable时,也可以调整阴影特性

代码解释一
    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;
  1. 创建聚光灯光源
  2. 设置castShadow为true,需要阴影
  3. 聚光灯光照方向,通过target设置,这里指向plane对象
代码解释二
    var target = new THREE.Object3D();
    target.position = new THREE.Vector3(5, 0, 0);
    
    spotLight.target = plane;

如果想让聚光灯射向某一个点,可以用如上的方式,创建一个THREE.Object3D对象。

代码解释三
var debugCamera = new THREE.CameraHelper(spotLight.shadow.camera);
scene.add(debugCamera);

当实际阴影效果与所希望的不一致时,使用THREE.CameraHelper可以非常方便的帮助我们发现问题所在。

代码解释四
var pp = new THREE.SpotLightHelper(spotLight);
scene.add(pp);
......
function render() {
    pp.update();
}

如果你需要调试聚光灯光源本身存在的问题,可以使用THREE.SpotLightHelper,我们可以直观的看到聚光灯的形状和朝向。

THREE.PointLight

单点发光、照射所有方向的光源。

function init() {
  var stats = initStats();
  // 初始化渲染器
  var renderer = initRenderer();
  // 初始化相机
  var camera = initCamera();
  // 初始化轨迹球控制器
  var trackballControls = initTrackballControls(camera, renderer);
  // 初始化时钟
  var clock = new THREE.Clock();
  // 创建一个场景,用于存放所有的元素,如对象、相机和灯光
  var scene = new THREE.Scene();
  // 添加一个简单的场景
  addHouseAndTree(scene)
  // 创建一个环境光
  var ambientLight = new THREE.AmbientLight("#0c0c0c");
  scene.add(ambientLight);
  // 创建一个点光源
  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);
  // 创建一个点光源的阴影相机辅助对象
  var shadowHelper = new THREE.CameraHelper(pointLight.shadow.camera)
  // 添加一个小球体模拟点光源
  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);

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

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

    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;
  }
}
属性概述
color(颜色)光源颜色
distance(距离)光源照射的距离
intensity(强度)光源照射的强度
position(位置)光源的位置
visible(是否可见)光源是否可见
decay(衰减)光源强度随着离开光源的距离而衰减的速度
power(功率)当物理正确模式启用时,该属性指定光源的功率
代码解释一
  // 创建一个点光源
  var pointColor = "#ccffcc";
  var pointLight = new THREE.PointLight(pointColor);
  // 设置光源的衰减
  pointLight.decay = 0.1
  // 设置光源投射阴影
  pointLight.castShadow = true;
  scene.add(pointLight);

点光源可以像聚光灯光源一样启用阴影并设置其属性。

  1. 指定聚光灯颜色new THREE.PointLight
  2. 设置聚光灯衰减
  3. 设置聚光灯阴影
  4. 设置聚光灯距离,决定光线强度变为0之前光线传播的距离。如果其值设置为0,则光线强度不会随着距离的增加而衰弱
展示效果

20240914-215026.jpg

THREE.DirectionalLight

可以看做是距离很远的光,发出的所有光线都是相互平行的,例如太阳光。

function init() {
  var stats = initStats();
  var renderer = initRenderer();
  // 初始化摄像机
  var camera = initCamera();
  camera.position.set(-80, 80, 80);
  // 初始化场景
  var scene = new THREE.Scene();

  // 初始化平面
  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.set(15, -5, 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.set(-4, 3, 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.set(20, 0, 2);
  sphere.castShadow = true;

  scene.add(sphere);

  // 初始化环境光
  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.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 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);
  render();
  function render() {
    stats.update();
    directionalLight.position.x = 10;
    directionalLight.position.y = 20; 
    directionalLight.position.z = -5;
    sphereLightMesh.position.copy(directionalLight.position);
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }
}
代码解释一
  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;

聚光灯光源必须定义生成阴影的光锥。对于平行光,所有的光线都是平行的,所以不会有光锥,而是一个立方体的区域

展示效果

20240914-215027.jpg

特殊光源

THREE.HemisphereLight(半球光源)

该光源更加贴近户外光照效果

function init() {

  var stats = initStats();
  var renderer = initRenderer();
  // 初始化相机
  var camera = initCamera();
  // 初始化场景
  var scene = new THREE.Scene();

  // 添加皮肤
  var textureGrass = new THREE.TextureLoader().load("../../learning-threejs-third/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;

  // 旋转平面
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(15, 0, 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.set(-4, 3, 0);
  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);
  sphere.position.set(10, 5, 10); 
  sphere.castShadow = true;
  scene.add(sphere);

  // 创建聚光灯
  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.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);
  // 渲染
  render();

  function render() {
    stats.update();
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }
}
代码解释一
  var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.6);
  hemiLight.position.set(0, 500, 0);
  scene.add(hemiLight);

仔细观察会发现球体的底部有接近草地的绿色,顶部有天空的蓝色。只要在参数中指定即可。

属性描述
groundColor从地面发出的光线颜色
color天空发出的光线颜色
intensity强度
展示效果

20240918-220816.jpg

THREE.AreaLight(区域光源)

使用THREE.AreaLight,可以定义一个发光区域。

function init() {
  const stats = initStats();
  const renderer = initRenderer({
    antialias: true
  });
  // 初始化相机
  const camera = initCamera();
  // 设置相机位置
  camera.position.set(-50, 30, 50)
  // 初始化轨迹球控件
  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();
  // 创建一个场
  var scene = new THREE.Scene();
  // 创建地面
  var planeGeometry = new THREE.PlaneGeometry(70, 70, 1, 1);
  var planeMaterial = new THREE.MeshStandardMaterial({
    roughness: 0.044676705160855,
    metalness: 0.0
  });
  // 创建地面网格
  var plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(0, 0, 0);
  // 添加地面到场景
  scene.add(plane);
  // 创建聚光灯
  var spotLight0 = new THREE.SpotLight(0xcccccc);
  spotLight0.position.set(-40, 60, -10);
  spotLight0.intensity = 0.1;
  spotLight0.lookAt(plane);
  scene.add(spotLight0);
  // 创建3个区域光
  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);
  // 创建3个平面 用于显示区域光的位置
  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);
  // 渲染
  render();

  function render() {
    stats.update();
    trackballControls.update(clock.getDelta());
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }
}
显示效果

20240919-213724.jpg

我们定义了三个THREE.AreaLight,每个都有自己的颜色。

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

设置光源颜色 0xff0000,光源强调 500 宽度 4 高度 10。与其他光源一样,可以使用position属性设置该光源在场景中的位置。

代码解释二
  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);

通过 THREE.BoxGeometry 来模拟区域光。将该位置和区域光位置设置一样。

光晕

光晕效果可以让三维效果更加的逼真。

function init() {
  var stats = initStats();
  var renderer = initRenderer({
    alpha: true
  });
  var camera = initCamera();
  camera.position.set(-20, 10, 45);
  camera.lookAt(new THREE.Vector3(10, 0, 0));
  var trackballControls = initTrackballControls(camera, renderer);
  var clock = new THREE.Clock();
  var scene = new THREE.Scene();
  // 加载纹理
  var textureGrass = new THREE.TextureLoader().load("../../learning-threejs-third/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;
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(15, 0, 0);
  scene.add(plane);
  // 创建聚光灯光源
  var spotLight = new THREE.SpotLight(0xffffff);
  spotLight.position.set(-40, 60, -10);
  spotLight.castShadow = true;
  scene.add(spotLight);
  var target = new THREE.Object3D();
  target.position = new THREE.Vector3(5, 0, 0);
  // 创建平行光光源
  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);
  // 加载镜头光晕纹理
  var textureFlare0 = THREE.ImageUtils.loadTexture("../../learning-threejs-third/assets/textures/flares/lensflare0.png");
  var textureFlare3 = THREE.ImageUtils.loadTexture("../../learning-threejs-third/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());
    requestAnimationFrame(render);
    renderer.render(scene, camera);
  }
}
展示效果

20240919-222213.jpg

参数描述
texture(纹理)一个图片,用来决定光晕形状
size(尺寸)可以指定光晕多大,单位为像素
distance(距离)光源到摄像机的距离
blending(混合)可以为光晕提供多个材质,混合模式决定了如何将他们混合在一起
color(颜色)光晕颜色
opacity(不透明度)透明度
代码解释一
  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));

通过THREE.Lensflare的add方法,只需要指定纹理、尺寸、距离、混合模式。

总结

Three.js 是一个基于 WebGL 的 JavaScript 3D 库,它提供了丰富的功能来创建和展示 3D 图形。在 Three.js 中,光源是渲染场景中非常重要的一部分,因为它们不仅能够照亮模型,还能为场景增添真实感。以下是 Three.js 中几种常见的光源类型及其使用特点的总结:

  1. 方向光(Directional Light) :方向光模拟的是太阳光或远距离的大面积光源,它产生平行光线,并且对所有物体的影响相同,无论距离光源多远。方向光不会衰减,并且可以投射阴影,非常适合模拟自然光照的效果。
  2. 点光源(Point Light) :点光源从一个点向四周发射光线,类似于灯泡或者蜡烛。这种光源会随着距离的增加而逐渐减弱亮度,这被称为光的衰减。点光源可以设置颜色和强度,并且也可以投射阴影。
  3. 聚光灯(Spot Light) :聚光灯类似于手电筒发出的光,它从一点朝特定方向发射光线,并且有一个明确的锥形范围。聚光灯同样支持衰减效果,并且可以调整其内锥和外锥的角度来控制光束的大小和强度。
  4. 区域光(Area Light) :虽然 Three.js 没有直接提供区域光的支持,但可以通过自定义着色器或其他技术手段实现类似效果。区域光模仿了现实世界中较大表面的光源,如软盒灯等,产生的光照更加柔和,边缘过渡自然。
  5. 环境光(Ambient Light) :环境光是对整个场景进行均匀照明的一种方式,它不具有方向性,也不受任何物体遮挡影响。环境光通常用于模拟环境中的漫反射光,但它不能投射阴影,也不能单独照亮某个物体。
  6. ** Hemisphere Light(半球光)**:半球光是一种特殊的环境光,它可以模拟天空和地面反射的光线,通过设置顶部和底部的颜色来达到照亮场景的目的。它常用于创建柔和的全局照明效果。

每种光源都有其独特的作用和适用场合,在实际应用中可以根据需要组合使用多种类型的光源来创造丰富多彩的视觉效果。同时,为了提高性能,Three.js 还允许开发者调整光源的参数,比如范围、强度、颜色等,以及是否启用阴影映射等功能。掌握好不同光源的特点和用法,可以帮助开发者更好地构建逼真、美观的 3D 场景。