Three.js - RectAreaLight 光源

闾丘树
2023-12-01

RectAreaLight是矩形面光源,光源类似一个平面,整个面会均匀的发光,这种光源可以用来模拟明亮的窗户,和发光的条状照明灯。
示例:https://ithanmang.gitee.io/threejs/home/201808/20180801/02-RectAreaLight.html

1、示例:

使用矩形面光源,需要注意以下事项

  • RectAreaLight光源不支持阴影效果。
  • 仅仅MeshStandardMaterialMeshPhysicalMaterial会被支持。
  • 必须包含RectAreaLightUniformsLibjs 库文件,到场景中,否则不会产生反光效果。
<!--注意:使用RectAreaLight 必须包含这个js库文件-->
<script src="../../libs/examples/js/lights/RectAreaLightUniformsLib.js"></script>

2、构造函数

RectAreaLight( color : Integer, intensity : Float, width : Float, height : Float )

2.1、参数

color - (可选) 光的颜色. 默认是 0xffffff (white).
intensity - (可选) 光的强度或者亮度. 默认为1.
width - (可选) 光面的宽度,默认为10.
height - (可选) 光面的高度,默认为10.

3、示例代码

示例中创建了一个矩形面光源

// 实例化矩形面光源,10 * 10 光源强度为1
rectLight = new THREE.RectAreaLight(0xffffff, 1, 10, 10);
rectLight.position.set(5, 6, 0);
scene.add(rectLight);

并且创建了一个矩形网格对象,将矩形面光源与矩形网格绑定

// 创建矩形网格,便于操作和测试
rectLightMesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(), new THREE.MeshBasicMaterial());
rectLightMesh.scale.x = rectLight.width;
rectLightMesh.scale.y = rectLight.height;
// 将矩形面光源与 plane 绑定
rectLight.add(rectLightMesh);

创建矩形面光源的背面

let rectLightMeshBack = new THREE.Mesh(new THREE.PlaneBufferGeometry(), new THREE.MeshBasicMaterial({color: 0x808080}));

 // 绕 y 轴旋转180度,形成与面光源的背面效果
 rectLightMeshBack.rotation.y = Math.PI;
 rectLightMesh.add(rectLightMeshBack);

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>RectAreaLight 矩形平面光源</title>
    <style>
        body {
            margin: 0;
            overflow: hidden; /*溢出隐藏*/
        }
    </style>
    <script src="../../libs/build/three.min.js"></script>
    <script src="../../libs/examples/js/controls/OrbitControls.js"></script>
    <script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
    <script src="../../libs/examples/js/libs/stats.min.js"></script>
    <script src="../../libs/examples/js/Detector.js"></script>

    <!--注意:使用RectAreaLight 必须包含这个js库文件-->
    <script src="../../libs/examples/js/lights/RectAreaLightUniformsLib.js"></script>
</head>
<body>
<script>

    let stats = initStats();
    let scene, camera, renderer, rectLight, rectLightMesh, controls, guiControls;
    let floor;
    let origin = new THREE.Vector3(0, 0, 0);

    // 场景
    function initScene() {

        scene = new THREE.Scene();

    }

    // 相机
    function initCamera() {

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 5000);
        camera.position.set(0, 20, 40);
        camera.lookAt(new THREE.Vector3(0, 0, 0));

    }

    // 渲染器
    function initRenderer() {

        renderer = new THREE.WebGLRenderer({antialias: true});
        // 设置渲染器的像素比例,按照设备
        renderer.setPixelRatio(window.devicePixelRatio);
        // 渲染范围
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 开启阴影支持
        renderer.shadowMap.enabled = true;
        // 阴影类型
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;

        // 将渲染器添加到文档
        document.body.appendChild(renderer.domElement);

    }

    let ambient;
    // 灯光
    function initLight() {

        ambient = new THREE.AmbientLight(0xffffff);
        scene.add(ambient);

        // 实例化矩形面光源,10 * 10 光源强度为1
        rectLight = new THREE.RectAreaLight(0xffffff, 1, 10, 10);
        rectLight.position.set(5, 6, 0);
        scene.add(rectLight);

        // 创建矩形网格,便于操作和测试
        rectLightMesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(), new THREE.MeshBasicMaterial());
        rectLightMesh.scale.x = rectLight.width;
        rectLightMesh.scale.y = rectLight.height;
        // 将矩形面光源与 plane 绑定
        rectLight.add(rectLightMesh);

        let rectLightMeshBack = new THREE.Mesh(new THREE.PlaneBufferGeometry(), new THREE.MeshBasicMaterial({color: 0x808080}));

        // 绕 y 轴旋转180度,形成与面光源的背面效果
        rectLightMeshBack.rotation.y = Math.PI;
        rectLightMesh.add(rectLightMeshBack);

    }

    // 控制器
    function initControls() {

        controls = new THREE.OrbitControls(camera, renderer.domElement);
        // 添加惯性
        controls.enableDamping = true;
        // 最大偏移角度
        controls.maxPolarAngle = 0.49 * Math.PI;
        // 旋转速度
        controls.rotateSpeed = 0.05;

    }

    // 调试插件
    function initGui() {

        guiControls = new function () {

            this.ambientLight = ambient.color.getStyle();
            this.ambientIntensity = ambient.intensity;

            this.motion = true;
            this.width = rectLight.width;
            this.height = rectLight.height;
            this.color = rectLight.color.getStyle();
            this.intensity = rectLight.intensity;

            this.floorColor = floor.material.color.getStyle();
            this.floorRoughness = floor.material.roughness;
            this.floorMetalness = floor.material.metalness;

            this.color = standMaterial.color.getStyle();
            this.roughness = standMaterial.roughness;
            this.metalness = standMaterial.metalness;
        };

        let gui = new dat.GUI({width: 300});/*这是插件的宽度*/
        gui.add(guiControls, 'motion');

        let ambientFolder = gui.addFolder('环境光');
        ambientFolder.addColor(guiControls, 'ambientLight').onChange(function (e) {
           ambient.color.setStyle(e);
        });

        ambientFolder.add(guiControls,'ambientIntensity',0, 1).onChange(function (e) {
           ambient.intensity = e;
        });
        ambientFolder.open();

        let lightFolder =  gui.addFolder('矩形面光');
        lightFolder.add(guiControls, 'width', 0, 20).onChange(function (e) {
           rectLight.width = e;
           rectLightMesh.scale.x = rectLight.width;
        });

        lightFolder.add(guiControls, 'height', 0, 20).onChange(function (e) {
           rectLight.height = e;
           rectLightMesh.scale.y = rectLight.height;
        });

        lightFolder.addColor(guiControls, 'color').onChange(function (e) {
            rectLight.color = new THREE.Color(e);
            rectLightMesh.material.color.copy(rectLight.color);
        });

        lightFolder.add(guiControls, 'intensity',0 ,5).onChange(function (e) {
           rectLight.intensity = e;
        });

        lightFolder.open();

        let floorFolder = gui.addFolder('地板');

        floorFolder.addColor(guiControls, 'floorColor').onChange(function (e) {
           floor.material.color.setStyle(e);
        });

        floorFolder.add(guiControls,'floorRoughness',0, 1).onChange(function (e) {
           floor.material.roughness = e;
        });

        floorFolder.add(guiControls,'floorMetalness',0,1).onChange(function (e) {
           floor.material.metalness = e;
        });

        floorFolder.open();

        let standFolder = gui.addFolder('标准材质');

        standFolder.addColor(guiControls,'color').onChange(function (e) {
           standMaterial.color.setStyle(e);
        });

        standFolder.add(guiControls,'roughness',0,1).onChange(function (e) {
           standMaterial.roughness = e;
        });

        standFolder.add(guiControls,'metalness',0,1).onChange(function (e) {
           standMaterial.metalness = e;
        });

        standFolder.open();

    }

    let standMaterial;
    // 场景中的内容
    function initContent() {

        // 地板
        let floorGeometry = new THREE.BoxBufferGeometry(2000, 1, 2000);

        // 使用矩形平明光源,必须使用 MeshStandarMaterial 或者 MeshPhysicalMaterial,来实现反射效果
        let floorMaterial = new THREE.MeshStandardMaterial({color: 0x636363, roughness: 0, metalness: 0});

        floor = new THREE.Mesh(floorGeometry, floorMaterial);
        scene.add(floor);

        standMaterial = new THREE.MeshStandardMaterial({color: 0xA00000, roughness: 0, metalness: 0});

        // 立方体
        let cubeGeometry = new THREE.BoxBufferGeometry(4, 4, 4);
        let cube = new THREE.Mesh(cubeGeometry, standMaterial);
        cube.position.set(-5, 2, 0);
        scene.add(cube);

        // 球体
        let sphereGeometry = new THREE.SphereBufferGeometry(2, 50, 50);
        let sphere = new THREE.Mesh(sphereGeometry, standMaterial);
        sphere.position.set(0, 3, 0);
        scene.add(sphere);

        // 圆桶体
        let cylinderGeometry = new THREE.TorusBufferGeometry(2, 0.3, 50, 50);
        let cylinder = new THREE.Mesh(cylinderGeometry, standMaterial);
        cylinder.rotation.x = -0.5 * Math.PI;
        cylinder.position.set(5, 2, 0);
        scene.add(cylinder);

    }

    // 性能插件
    function initStats() {

        let stats = new Stats();

        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';

        document.body.appendChild(stats.domElement);

        return stats;
    }

    // 更新
    function update() {

        stats.update();
        controls.update();
        // guiControls.motion 为true 的时候会一直旋转
        if (guiControls.motion){

            let time = (Date.now() / 2000);

            let lx = 15.0 * Math.cos( time );
            let lz = 15.0 * Math.sin( time );

            let ly = 5.0 + 5.0 * Math.sin( time / 3.0 );

            rectLight.position.set(lx, ly, lz);
            rectLight.lookAt(origin);

        }

    }

    // 初始化
    function init() {
        // 兼容性判断,若不兼容会提示信息
        if (!Detector.webgl) Detector.addGetWebGLMessage();

        initScene();
        initCamera();
        initRenderer();
        initLight();
        initControls();
        initContent();
        initGui();

        window.addEventListener('resize', onWindowResize, false);
    }

    // 窗口变动触发的方法
    function onWindowResize() {

        // 重新设置相机的宽高比
        camera.aspect = window.innerWidth / window.innerHeight;

        // 更新相机投影矩阵
        camera.updateProjectionMatrix();

        // 更新渲染器大小
        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    // 循环渲染
    function animate() {

        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        update();
    }

    // 页面绘制完后加载
    window.onload = function () {

        init();
        animate();

    };

</script>
</body>
</html>
 类似资料: