ThreeJs入门13-光的初体验-平行光

1,437 阅读5分钟

「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战

yuque_diagram.jpg

示例代码采用three.js-r73版本: cdnjs.cloudflare.com/ajax/libs/t…

上节我们介绍了环境光,这次我们再介绍一个光的种类平行光DirectionalLight

方向光

  • 平行光又称为方向光(Directional Light),是一组没有衰减的平行的光线。
  • 平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。

image.png

  • 构造函数
THREE.DirectionalLight = function ( color, intensity )
  • color: 16进制颜色
  • intensity:光线的强度,默认为1
    • RGB的三个值均在0~255之间,不能反映出光照的强度变化,光照越强,物体表面就更明亮。它的取值范围是0到1。如果为0,表示光线基本没什么作用。

方向光的特点

  • 使用方向光需要注意以下几点
    • 方向光不能在物体里面
    • 改变方向光的位置
    • 改变方向光的强度
    • 改变方向光的颜色
    • 不做特殊设置,光是可以穿透物体的

我们通过示例来说明下这几种情况。写一下我们的示例,之前的代码删除掉光源相关设置即可,重新定义一个平行光

function initCamera() {
    camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
    camera.position.x = 600;
    camera.position.y = 0;
    camera.position.z = 600;
    camera.up.x = 0;
    camera.up.y = 1;
    camera.up.z = 0;
    camera.lookAt({ x: 0, y: 0, z: 0 });
}

var param;
var light;
var lightPos
function initLight() {
    light = new THREE.DirectionalLight(0xFF0000, 1)
    light.position.set(0, 0, 600)
    scene.add(light)
}

效果如下: image.png

  • 我们设置了摄像机的位置(600, 0, 600),平行光的位置(0, 0, 600),物体的位置(0, 0, 0),
  • 相对来说,摄像机是垂直屏幕,面向屏幕里的,所以坐标轴转动了。

方向光不能在物体里面

  • 我们添加gui,来动态改变平行光的位置
var param;
var light;
var lightPos
function initLight() {
    var ParamObj = function () {
        this.x = 0;
        this.y = 0;
        this.z = 0;
    }
    param = new ParamObj();
    var gui = new dat.GUI();
    gui.add(param, "x", -10000, 10000).name('平行光X的位置')
    gui.add(param, "y", -10000, 10000).name('平行光Y的位置')
    gui.add(param, "z", -10000, 10000).name('平行光Z的位置')
    // 平行光定义为红色
    light = new THREE.DirectionalLight(0xFF0000, 1)
    light.position.set(param.x, param.y, param.z)
    scene.add(light)
}

image.png

  • 默认平行光是在 (0, 0, 0) 的位置,也就是说光源的位置是在几何体里面的,光射向方向也是在里面的,已经形成一个点完全射不出来了,所以外面看不出来颜色了。
  • 所以说:方向光不能在物体里面

改变方向光的位置

  • 我们改变参数的时候,动态更新平行光位置
function changeLightPos() {
    light.position.set(param.x, param.y, param.z);
}

function animation() {
    changeLightPos();
    renderer.render(scene, camera);
    requestAnimationFrame(animation);
    update()
}
  • 我们改变xyz数值为正值,可以看到对应的颜色变化

平行光.gif

  • 我们改变xyz数值为负值,然后按住鼠标左键转动到背面,我们可以看到背面颜色的变化

平行光背面.gif

  • 所以说,改变方向光的位置会有变化

改变方向光的强度

  • 我们在gui中添加光照强度的改变
function initLight() {
    var ParamObj = function () {
        ...
        this.intensity = 1;
    }
 		...
    gui.add(param, "intensity", 0, 1).name('平行光的光照强度')
		...
}
    
function changeLightPos() {
    light.position.set(param.x, param.y, param.z);
    light.intensity = param.intensity
}

2022-01-25 11-43-03.2022-01-25 11_43_24.gif

  • 所以说:改变光的强度会有变化

改变方向光的颜色

我们通过一个颜色选择器插件,来动态改变光的颜色。

<input
  class="color-pricker"
  data-jscolor="{value:'#FF0000', alpha:1}"
  onChange="colorPickerUpdate(this.jscolor, '#pr3')"
/>
function initColorPicker() {
    jscolor.presets.default = {
        width: 141,               // make the picker a little narrower
        position: 'top',        // position it to the right of the target
        previewPosition: 'right', // display color preview on the right
        previewSize: 40,          // make the color preview bigger
        format: 'hex',
        previewSize: 40,
        closeButton: true,
        closeText: '关闭',
        palette: [
            '#000000', '#7d7d7d', '#870014', '#ec1c23', '#ff7e26',
            '#fef100', '#22b14b', '#00a1e7', '#3f47cc', '#a349a4',
            '#ffffff', '#c3c3c3', '#b87957', '#feaec9', '#ffc80d',
            '#eee3af', '#b5e61d', '#99d9ea', '#7092be', '#c8bfe7',
        ],
    };
}

function colorPickerUpdate(picker, selector) {
    const hex = '0x' + picker.toHEXString().replace(/#/, '')
    light.color.setHex(hex)
}
  • 我们改变方向光的颜色,看看几何体显示颜色的变化

改变光的颜色.gif

  • 我们可以看到,由于我们的几何体反射红光吸收其他颜色,当方向光的颜色中不包含红色时,就会变成黑色,改变方向光的颜色类似于改变方向光的强度

上述三个特征,codepen示例代码

不做特殊设置,光是可以穿透物体的

我们创建多个物体,来表示层级关系

function initObject() {
    var geometry = new THREE.CubeGeometry(200, 100, 50, 4, 4);
    var material = new THREE.MeshLambertMaterial({ color: 0xFF0000 });
    var mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(0, 0, 0);
    scene.add(mesh);

    var geometry2 = new THREE.CubeGeometry(200, 100, 50, 4, 4);
    var material2 = new THREE.MeshLambertMaterial({ color: 0xFF0000 });
    var mesh2 = new THREE.Mesh(geometry2, material2);
    mesh2.position.set(-300, 0, 0);
    scene.add(mesh2);

    var geometry3 = new THREE.CubeGeometry(200, 100, 50, 4, 4);
    var material3 = new THREE.MeshLambertMaterial({ color: 0xFF0000 });
    var mesh3 = new THREE.Mesh(geometry3, material3);
    mesh3.position.set(0, -150, 0);
    scene.add(mesh3);

    var mesh4 = new THREE.Mesh(geometry3, material3);
    mesh4.position.set(0, 150, 0);
    scene.add(mesh4);

    var mesh5 = new THREE.Mesh(geometry3, material3);
    mesh5.position.set(300, 0, 0);
    scene.add(mesh5);

    var mesh6 = new THREE.Mesh(geometry3, material3);
    mesh6.position.set(0, 0, 100);
    scene.add(mesh6);
}

改变光的位置,查看显示效果 image.png

  • 我们可以看到,蓝色框中的两个物体,前面的物体把后面的物体遮挡住,但是后面的物体还是有颜色的,这是为什么呢?
  • 在计算机中,目前我们没有计算投影,也没有设定前面的物体要挡住后面的物体,也没有设定前面物体把阴影投影到后面物体上,所以光直接透过去了,并且没有衰减。
  • 所以,如果不做特殊设置,光是可以穿透物体的

codepen示例代码

总结

  • 光的种类-平行光(方向光) DirectionalLight
  • 方向光与位置和强度有关
    • 方向光不能在物体里面
    • 光的位置影响方向光
    • 光的强度影响方向光
    • 光的颜色影响方向光
    • 不做特殊设置,光是可以穿透物体