threejs光源

news2024/10/5 15:34:35

个人博客地址: https://cxx001.gitee.io

前言

没有光源,渲染场景将不可见。threejs中已经帮我们实现了大量的光源,我们可以直接使用,主要分为两类:基础光源和特殊光源,下面将依次详细介绍。


基础光源

1. THREE.AmbientLight(环境光)

该光源颜色会应用到场景全局,光源没有特别的来源方向,并且不会生成阴影。通常,不会将环境光作为场景中唯一的光源,因为它会将场景中的所有物体渲染为相同颜色。一般和其它光源一起使用,它只是为了弱化阴影或给场景添加一些额外的颜色,所以它的用色应该尽量保守,如果设置的颜色过于明亮,那么画面颜色就过于饱和了。

下面示例帮助你理解,试试改变AmbientLight光颜色或开启/关闭spotLight光源,观察场景变化。

<!-- chapter-03-01.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Ambient Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
    	// 初始化fps显示插件
        var stats = initStats();

        // 创建场景对象
        var scene = new THREE.Scene();

        // 创建透视投影摄像机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // 创建渲染器
        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); // 设置背景颜色
        renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染窗口大小
        renderer.shadowMapEnabled = true; // 激活阴影

        // 创建平面
        var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
        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.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);

        // 创建立方体对象
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true; // 投射阴影

        // 设置立方体位置
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 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.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true; // 投射阴影
        scene.add(sphere);

        // 设置摄像机位置
        camera.position.x = -25;
        camera.position.y = 30;
        camera.position.z = 25;
    	// 设置摄像机镜头朝向
        camera.lookAt(new THREE.Vector3(10, 0, 0));

        // 创建环境光
        var ambiColor = "#0c0c0c";  // 使用的是比较暗淡的灰色
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);

        // 创建聚光灯并开启投射阴影
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        scene.add(spotLight);

        // 将渲染器添加到DOM里显示
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        // 设置dat.GUI插件显示属性
        var controls = new function () {
            this.ambientColor = ambiColor; // 环境光颜色
            this.disableSpotlight = false; // 聚光灯是否可见
        };
		
    	// 将添加的控制属性添加到gui界面
        var gui = new dat.GUI();
    	// 颜色设置
        gui.addColor(controls, 'ambientColor').onChange(function (e) {
            ambientLight.color = new THREE.Color(e);
        });
    	// 开关设置
        gui.add(controls, 'disableSpotlight').onChange(function (e) {
            spotLight.visible = !e;  // 聚光灯是否可见
        });

		// 开始渲染
        render();
		var step = 0;
        function render() {
            // 更新fps显示
            stats.update();
            
            // 旋转立方体
            cube.rotation.x += 0.02;
            cube.rotation.y += 0.02;
            cube.rotation.z += 0.02;

            // 跳动球体
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));

            // 重新渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
		
    	// 初始化fps显示插件
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }

    window.onload = init;

	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

效果:

在这里插入图片描述

2. THREE.PointLight(点光源)

点光源发射光线示意图:

从特定的一点向所有方向发射光线。夜空中的照明弹就是一个很好的点光源例子。

threejs里的点光源也没有阴影,因为它朝所有方向发射光线,这种情况下计算阴影对GPU是一个沉重的负担。

下面我们依旧通过示例来理解,这是一个点光源绕场景移动,为了看到点光源位置,我们让一个橙色的小球沿着相同的轨迹移动。你可以看到随着光源的移动,红色的方块和蓝色的球被这个光源从不同的侧面照亮。

<!-- chapter-03-02.html -->
<!DOCTYPE html>
<html>
<head>
    <title>point Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();

        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        // renderer.shadowMapEnabled = true; // 点光源没有阴影

        var planeGeometry = new THREE.PlaneGeometry(60, 20, 20, 20);
        var planeMaterial = new THREE.MeshPhongMaterial({color: 0xffffff});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        // plane.receiveShadow = true;
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);

        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff7777});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        // cube.castShadow = true;
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 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.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true;
        scene.add(sphere);

        camera.position.x = -25;
        camera.position.y = 30;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(10, 0, 0)); // 镜头照射位置

        // 添加环境光,弱的灰色,为了柔化场景
        var ambiColor = "#0c0c0c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);

        // 添加点光源
        var pointColor = "#ccffcc";
        var pointLight = new THREE.PointLight(pointColor);
        pointLight.distance = 100;  // 光源照射距离
        scene.add(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, 0, 3);
        scene.add(sphereLightMesh);

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        var controls = new function () {
            this.ambientColor = ambiColor;  // 环境光颜色
            this.pointColor = pointColor;   // 点光源颜色
            this.intensity = 1;    // 光照强度
            this.distance = 100;   // 光照距离
        };

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

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


        render();
        var step = 0;
		var invert = 1;
        var phase = 0;
        function render() {
            stats.update();
            
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;

            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));

            // 模拟光源移动
            if (phase > 2 * Math.PI) {
                invert = invert * -1;
                phase -= 2 * Math.PI;
            } else {
                phase += 0.03;
            }
            sphereLightMesh.position.z = +(7 * (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;
            }
			// 光源和球体一起移动
            pointLight.position.copy(sphereLightMesh.position);

            // 重新渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;

	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

所使用的点光源属性:

属性描述
color(颜色)光源的颜色
distance(距离)光源照射的距离。默认值为0,这意味着光的强度不会随着距离增加而减少
intensity(强度)光源照射的强度。默认值1
position(位置)光源在场景中的位置
visible(是否可见)默认为true,光源会打开;如果设置为false,光源就会关闭

效果:

3. THREE.SpotLight(聚光灯)

聚光灯发射光线示意图:

从特定的一点发射锥形形状的光线,这是最常使用的光源之一,特别是你想要使用阴影的话。该光源具有产生光的方向和角度,类似手电筒。

聚光灯光源的所有属性:

属性描述
angle(角度)光源发射出的光束的宽度。默认是Math.PI/3
castShadow(投影)如果设置为true,这个光源就会投射阴影
color(颜色)光源颜色
distance(距离)光源照射的距离。默认值为0,这意味着光的强度不会随着距离增加而减少
intensity(强度)光源照射的强度。默认值1
exponent(光强衰减指数)发射的光线强度随着光源距离的增加而减弱,这个属性决定了光线强度递减的速度。使用小值,从光源发出的光线可以达到远处的物体,而使用大值,光线仅能到达非常接近光源的物体。
onlyShadow(仅阴影)如果此属性设置为true,则该光源只生成阴影,不会在场景中添加任何光照
position(位置)光源在场景中的位置
shadowBias(阴影偏移)用来偏移阴影位置。当你使用非常薄的对象时,可能出现奇怪的渲染失真现象,如果你看到奇怪的阴影效果,将该属性设置为很小的值(如0.01)通过可以解决问题。此属性默认值为0
shadowCameraFar(投影远点)到距离光源的哪一个位置可以生成阴影。默认值为5000(这几个参考投射投影摄像机理解)
shadowCameraNear(投影近点)从距离光源的哪一个位置开始生成阴影。默认值为50
shadowCameraFov(投影视场)用于生成阴影的视场有多大。默认值为50
shadowCameraVisible(投影方式是否可见)如果设置为true,可以看到光源在哪里以及如何生成阴影的(看到光源照射锥体)。默认值为false
shadowDarkness(投影暗度)定义阴影的暗度。在场景渲染后无法修改。默认值为0.5
shadowMapWidth和shadowMapHeight(阴影映射的宽/高)决定有多少像素用来生成阴影。**当阴影有锯齿或看起来不光滑时,可以增加这个值。**在场景渲染后无法修改。两者默认值为512
target(目标)可以将光源指向场景中特定的对象或位置(位置需要是THREE.Object3Dd对象,不是THREE.Vectors3对象)。
visible()默认为true,光源会打开;如果设置为false,光源就会关闭
<!-- chapter-03-03.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Spot Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
		// 是否停止移动光源
        var stopMovingLight = false;

        var stats = initStats();

        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
        renderer.shadowMapType = THREE.PCFShadowMap; // 这是默认值,如果设置为PCFSoftShadowMap则会使阴影更柔和

        var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
        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.x = 15;
        plane.position.y = 0;
        plane.position.z = 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.x = -4;
        cube.position.y = 3;
        cube.position.z = 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.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true;
        scene.add(sphere);

        camera.position.x = -35;
        camera.position.y = 30;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(10, 0, 0));

        // 添加环境光
        var ambiColor = "#1c1c1c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);

        // 添加1个聚光灯光源,设置位置和照射方向(和摄像机设置类似), 这个固定照射地面
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 30, -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);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        spotLight.shadowCameraNear = 2;
        spotLight.shadowCameraFar = 200;
        spotLight.shadowCameraFov = 30;
        spotLight.target = plane;  // 照射方向,可以是这里的网格物体,也可以是上面的target具体某点对象
        spotLight.distance = 0;
        spotLight.angle = 0.4;
        scene.add(spotLight);

        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);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        var step = 0;
        var invert = 1;
        var phase = 0;
        var controls = new function () {
            this.ambientColor = ambiColor;
            this.pointColor = pointColor;
            this.intensity = 1;  // 光照强度
            this.distance = 0;   // 光照距离
            this.exponent = 30;  // 随着距离光源越远,光强度衰减指数
            this.angle = 0.1;  // 光源视场角度
            this.debug = false;  // 是否开启调试模式(打开投影方式可见)
            this.castShadow = true;  // 是否投射阴影,false则不会产生阴影
            this.onlyShadow = false;  // 是否只生成阴影,true则不会在场景中产生光照
            this.target = "Plane";   // 光源照射目标
            this.stopMovingLight = false;  // 是否停止移动光源
        };

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

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

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

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

        gui.add(controls, 'onlyShadow').onChange(function (e) {
            spotLight.onlyShadow = e;
        });
		// gui添加选择列表方式
        gui.add(controls, 'target', ['Plane', 'Sphere', 'Cube']).onChange(function (e) {
            console.log(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;
        });


        render();

        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;
            step += 0.03;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));

            // 小球和spotLight光源一起移动
            if (!stopMovingLight) {
                if (phase > 2 * Math.PI) {
                    invert = invert * -1;
                    phase -= 2 * Math.PI;
                } else {
                    phase += 0.03;
                }
                sphereLightMesh.position.z = +(7 * (Math.sin(phase)));
                sphereLightMesh.position.x = +(14 * (Math.cos(phase)));
                sphereLightMesh.position.y = 10;

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

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

            // 重新渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }

    window.onload = init;
	
	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

效果:

在这里插入图片描述

4. THREE.DirectionalLight(平行光)

平行光发生光线示意图:

从二维平面发射光线,光线彼此平行。这种类型的光可以看作是距离很远的光,如太阳光,它如此遥远,以至于达到地球时所有的光线几乎都是相互平行的。**它不像前面聚光灯那样离目标越远越暗淡,被平行光照亮的整个区域接收到的光强度是一样的。**它也可以产生阴影,很多属性和上面SpotLight一样,它的光照区域是一个立方体,类似正交投影摄像机,而SpotLight则类似透视投影摄像机。

<!-- chapter-03-04.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Directional Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();

        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
		// 平面
        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.x = 15;
        plane.position.y = -5;
        plane.position.z = 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.x = -4;
        cube.position.y = 3;
        cube.position.z = 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.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        sphere.castShadow = true;
        scene.add(sphere);

        camera.position.x = -35;
        camera.position.y = 30;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(10, 0, 0));

        // 添加环境光,给场景润色
        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.shadowCameraNear = 2;
        directionalLight.shadowCameraFar = 200;
        directionalLight.shadowCameraLeft = -50;
        directionalLight.shadowCameraRight = 50;
        directionalLight.shadowCameraTop = 50;
        directionalLight.shadowCameraBottom = -50;
		// 同前面聚光灯属性
        directionalLight.distance = 0;
        directionalLight.intensity = 0.5;
        directionalLight.shadowMapHeight = 1024;
        directionalLight.shadowMapWidth = 1024;
        scene.add(directionalLight);

        // 和光源一起移动的小球
        var sphereLight = new THREE.SphereGeometry(1);
        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);

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

    	// 属性同上面聚光灯
        var controls = new function () {
            this.ambientColor = ambiColor;
            this.pointColor = pointColor;
            this.intensity = 0.5;
            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) {
            directionalLight.color = new THREE.Color(e);
        });

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

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

        gui.add(controls, 'debug').onChange(function (e) {
            directionalLight.shadowCameraVisible = e;
        });

        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();
    
		var step = 0;
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;

            step += 0.03;
            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);

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

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }

    window.onload = init;

	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

效果:


特殊光源

1. THREE.HemisphereLight(半球光源)

使用半球光源可以创建出更加贴近自然的户外光照效果。在户外,并不是所有的光照都来自上方,还有大气的散射和地面以及其它物体的反射。THREE.HemisphereLight光源就是为了这种情形创建的。

它的属性很简单:

属性描述
groundColor从地面发出的光线的颜色
color从天空发出的光线的颜色
intensity光线照射的强度
<!-- chapter-03-05.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Hemisphere Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();

        var scene = new THREE.Scene();
        scene.fog = new THREE.Fog(0xaaaaaa, 0.010, 200);  // 添加雾化效果

        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
		
    	// 添加本地图片纹理(草地地面)
        var textureGrass = THREE.ImageUtils.loadTexture("../assets/textures/ground/grasslight-big.jpg");
        textureGrass.wrapS = THREE.RepeatWrapping;
        textureGrass.wrapT = THREE.RepeatWrapping;
        textureGrass.repeat.set(4, 4);

    	// 用本地图片做网格对象的材质
        var planeGeometry = new THREE.PlaneGeometry(1000, 200, 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.x = 15;
        plane.position.y = 0;
        plane.position.z = 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.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        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);
        sphere.position.x = 10;
        sphere.position.y = 5;
        sphere.position.z = 10;
        sphere.castShadow = true;
        scene.add(sphere);

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

        // 添加聚光灯光源
        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.shadowCameraNear = 0.1;
        dirLight.shadowCameraFar = 200;
        dirLight.shadowCameraLeft = -50;
        dirLight.shadowCameraRight = 50;
        dirLight.shadowCameraTop = 50;
        dirLight.shadowCameraBottom = -50;
        dirLight.shadowMapWidth = 2048;
        dirLight.shadowMapHeight = 2048;
        scene.add(dirLight);

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        var controls = new function () {
            this.hemisphere = true;   // 是否开启半球光源(通过光强为0来设置)
            this.color = 0x00ff00;    // 从地面发出的光线颜色
            this.skyColor = 0x0000ff; // 从天空发出的光线颜色
            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, 'color').onChange(function (e) {
            hemiLight.groundColor = new THREE.Color(e);
        });
        gui.addColor(controls, 'skyColor').onChange(function (e) {
            hemiLight.color = new THREE.Color(e);
        });
        gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
            hemiLight.intensity = e;
        });

        render();
    
		var step = 0;
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;

            step += 0.03;
            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 initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;

	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

观察示例,通过开启/关闭半球光源,看场景中物体受反射光的影响。

在这里插入图片描述

2. THREE.AreaLight(区域光源)

区域光不是从某一个点发光,它是从一块区域发光,可以定义长方形的发光区域。它没有定义在WebGLRenderer渲染器中,因为会带来非常严重的性能损失。而是定义在WebGLDeferredRenderer渲染器中,它使用了一种不同的方法(分成多个步骤),相对标志渲染器WebGLRenderer,可以更好地处理复杂地光照(或者非常大量地光源)。

使用WebGLDeferredRenderer要额外引入一些外部库。好像新版区域光源也给加到标志渲染器了,本示例用的旧版。

<!-- chapter-03-06.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Area Light</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
	// 引入WebGLDeferredRenderer渲染器
    <script type="text/javascript" src="../libs/WebGLDeferredRenderer.js"></script>
    <script type="text/javascript" src="../libs/ShaderDeferred.js"></script>
    <script type="text/javascript" src="../libs/RenderPass.js"></script>
    <script type="text/javascript" src="../libs/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/FXAAShader.js"></script>
    <script type="text/javascript" src="../libs/MaskPass.js"></script>

    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    var camera;
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        scene.add(camera);
		
        // 针对区域光源这种大量光源性能优化的渲染器
        var renderer = new THREE.WebGLDeferredRenderer({
            width: window.innerWidth,
            height: window.innerHeight,
            scale: 1, antialias: true,
            tonemapping: THREE.FilmicOperator, brightness: 2.5
        });
		
        // 地面
        var planeGeometry = new THREE.PlaneGeometry(70, 70, 1, 1);
        var planeMaterial = new THREE.MeshPhongMaterial({color: 0xffffff, specular: 0xffffff, shininess: 200});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.x = 0;
        plane.position.y = 0;
        plane.position.z = 0;
        scene.add(plane);

        camera.position.x = 20;
        camera.position.y = 30;
        camera.position.z = 21;
        camera.lookAt(new THREE.Vector3(0, 0, -30));

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        // 固定的聚光灯光源
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 60, -10);
        spotLight0.intensity = 0.1;
        spotLight0.lookAt(plane);
        scene.add(spotLight0);

		// 添加红色区域光源1
        var areaLight1 = new THREE.AreaLight(0xff0000, 3);
        areaLight1.position.set(-10, 10, -35);
        areaLight1.rotation.set(-Math.PI / 2, 0, 0);
        areaLight1.width = 4;
        areaLight1.height = 9.9;
        scene.add(areaLight1);
		
        // 添加绿色区域光源2
        var areaLight2 = new THREE.AreaLight(0x00ff00, 3);
        areaLight2.position.set(0, 10, -35);
        areaLight2.rotation.set(-Math.PI / 2, 0, 0);
        areaLight2.width = 4;
        areaLight2.height = 9.9;
        scene.add(areaLight2);
		
        // 添加蓝色区域光源3
        var areaLight3 = new THREE.AreaLight(0x0000ff, 3);
        areaLight3.position.set(10, 10, -35);
        areaLight3.rotation.set(-Math.PI / 2, 0, 0);
        areaLight3.width = 4;
        areaLight3.height = 9.9;
        scene.add(areaLight3);
		
        // 红色长方形1(z为0)设置到区域光源1位置,用于标志光源的位置
        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);

		// 绿色长方形2设置到区域光源2位置
        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);
		
        // 蓝色长方形3设置到区域光源3位置
        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 () {
            // 对应3块区域光的颜色和强度
            this.color1 = 0xff0000;
            this.intensity1 = 2;
            this.color2 = 0x00ff00;
            this.intensity2 = 2;
            this.color3 = 0x0000ff;
            this.intensity3 = 2;
        };
		
        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, 5).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, 5).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, 5).onChange(function (e) {
            areaLight3.intensity = e;
        });


        render();

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

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;

	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

效果:

在这里插入图片描述


3. THREE.LensFlare(镜头光晕)

类似你直接朝着太阳拍照时就会出现镜头光晕效果。

光晕属性:

参数描述
texture(纹理)纹理就是一个图片,用来决定光晕的形状
size(尺寸)指定光晕大小。如果指定为-1,那么将使用纹理本身的大小
distance(距离)从光源(0)到摄像机(1)的距离。
blending(混合)可以为光晕提供多种材质。混合模式决定了如何将它们混合在一起。
color(颜色)光晕的颜色

示例:

<!-- chapter-03-07.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Lensflarest</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        scene.fog = new THREE.Fog(0xaaaaaa, 0.010, 200); // 添加雾化效果

        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
        renderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;

        // 创建草地地面
        var textureGrass = THREE.ImageUtils.loadTexture("../assets/textures/ground/grasslight-big.jpg");
        textureGrass.wrapS = THREE.RepeatWrapping;
        textureGrass.wrapT = THREE.RepeatWrapping;
        textureGrass.repeat.set(4, 4);
        var planeGeometry = new THREE.PlaneGeometry(1000, 200, 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.x = 15;
        plane.position.y = 0;
        plane.position.z = 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.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        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);
        sphere.position.x = 10;
        sphere.position.y = 5;
        sphere.position.z = 10;
        sphere.castShadow = true;
        scene.add(sphere);

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

        // 添加环境光
        var ambiColor = "#1c1c1c";
        var ambientLight = new THREE.AmbientLight(ambiColor);
        scene.add(ambientLight);

        // 添加聚光灯
        var spotLight0 = new THREE.SpotLight(0xcccccc);
        spotLight0.position.set(-40, 60, -10);
        spotLight0.lookAt(plane);
        scene.add(spotLight0);
		
    	// 添加平行光
        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);

        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        var controls = new function () {
            this.ambientColor = ambiColor;
            this.pointColor = pointColor;
            this.intensity = 0.1;
        };

        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/textures/lensflare/lensflare0.png");
    	// 创建镜头光晕,把它放在光源处(距离为0)
    	var flareColor = new THREE.Color(0xffaacc);
        var lensFlare = new THREE.LensFlare(textureFlare0, 350, 0.0, THREE.AdditiveBlending, flareColor);
		// 光源到摄像机附近添加新的光晕(使用的很淡的纹理),通过上面主光晕对象的add方法添加,增强表现效果,可以屏蔽对比。
    	var textureFlare3 = THREE.ImageUtils.loadTexture("../assets/textures/lensflare/lensflare3.png");
        lensFlare.add(textureFlare3, 60, 0.6, THREE.AdditiveBlending);
        lensFlare.add(textureFlare3, 70, 0.7, THREE.AdditiveBlending);
        lensFlare.add(textureFlare3, 120, 0.9, THREE.AdditiveBlending);
        lensFlare.add(textureFlare3, 70, 1.0, THREE.AdditiveBlending);
        lensFlare.position.copy(spotLight.position);
        scene.add(lensFlare);

        render();
    
		var step = 0;
        function render() {
            stats.update();
            cube.rotation.x += 0.03;
            cube.rotation.y += 0.03;
            cube.rotation.z += 0.03;

            step += 0.03;
            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 initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    };

    window.onload = init;

	// 改变窗口大小后适配
	function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
	window.addEventListener('resize', onResize, false);
</script>
</body>
</html>

效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/706571.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单向/双向V2G环境下分布式电源与电动汽车充电站联合配置方法(matlab代码)

目录 1 主要内容 目标函数 电动汽车负荷建模 算例系统图 程序亮点 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现博士文章《互动环境下分布式电源与电动汽车充电站的优化配置方法研究》第五章《单向/双向V2G环境下分布式电源与电动汽车充电站联合配置方法》…

13 | 代码模型(上):如何使用DDD设计微服务代码模型?

目录 DDD 分层架构与微服务代码模型 微服务代码模型 微服务一级目录结构 各层目录结构 1. 用户接口层 2. 应用层 3. 领域层 4. 基础层 代码模型总目录结构 总结 上一篇文章中完成了领域模型的设计&#xff0c;接下来我们就要开始微服务的设计和落地了。那微服务落地时…

第十七章、Spring的事务处理

1.什么是事务&#xff1f; 保证业务操作完整性的一种数据库机制事务的特点&#xff1a;ACID 原子性 一致性 隔离性 持久性2.如何控制事务 JDBC:Connection.setAutoCommit(false);事务开启Connection.commit();Connection.rollback(); Mybatis:Mybatis自动开启事务sqlSession(…

Revit中桩的绘制及CAD生成桩

一、Revit如何用体量来绘制一个桩基础 如何用体量来绘制一个桩基础呢?这里采用BIM等级考试一级第十期的第三题来教大家 新建体量样板&#xff0c;选择公制体量来绘制 按题目要求先复制4个参照标高平面&#xff0c;同时按住ctrlshift拖动标高再修改高度就可以 开始绘制基础的最…

Axure教程——模糊搜索(中继器 )

本文介绍的是用Axure中的中继器制作模糊搜索 效果 预览地址&#xff1a;https://f16g7e.axshare.com 功能 输入关键字&#xff0c;可查询出相应的结果 制作 一、需要元件 矩形、中继器 二、制作过程 1、搜索框 拖入一个矩形元件&#xff0c;设置大小为21530,在矩形中加入一个…

多元分类预测 | Matlab麻雀算法(SSA)优化混合核极限学习机(HKELM)分类预测,多特征输入模型,SSA-HKELM分类预测

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元分类预测 | Matlab麻雀算法(SSA)优化混合核极限学习机(HKELM)分类预测,多特征输入模型,SSA-HKELM分类预测 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab…

内网IP怎么用域名让外网访问,域名动态解析和静态区别?

域名解析是将域名与公网IP进行对应关系&#xff0c;实现访问域名即访问到对应IP应用的方式。域名解析分静态域名解析和动态域名解析的区别&#xff0c;它们的区别在哪&#xff1f;内网IP服务器怎么用域名让外网连接访问&#xff1f;这些都是需要我们有所了解掌握的。 这里不但…

ShardingSphere 5.3 整合 Seata 分布式事务 | Spring Cloud 61

一、前言 通过以下系列章节&#xff1a; docker-compose 实现Seata Server高可用部署 | Spring Cloud 51 Seata AT 模式理论学习、事务隔离及部分源码解析 | Spring Cloud 52 Spring Boot集成Seata利用AT模式分布式事务示例 | Spring Cloud 53 Seata XA 模式理论学习、使用…

word去掉页眉横线方法

最简单的方法&#xff1a;双击页眉全选文字&#xff0c;然后点清除样式即可。 清除样式的图标&#xff1a; 参考的是下面这篇文章&#xff0c;介绍得很详细&#xff0c;讲了三种方法&#xff0c;如果上面的方法行不通可以试试其他的方法&#xff1a; Word页眉横线怎么去掉

2023年第二届能源与环境工程国际会议(CFEEE 2023)

会议简介 Brief Introduction 2023年第二届能源与环境工程国际会议(CFEEE 2023) 会议时间&#xff1a;2023年9月1日-3日 召开地点&#xff1a;中国三亚 大会官网&#xff1a;CFEEE 2023-2023 International Conference on Frontiers of Energy and Environment Engineering 由I…

编译linux内核(一)

关于linux启动流程 1. 第一阶段&#xff1a;BIOS1.1 硬件自检1.2 启动顺序 2. 第二阶段&#xff1a;主引导记录2.1 主引导记录的结构2.2 分区表 3. 第三阶段&#xff1a;硬盘启动3.1 情况A&#xff1a;卷引导记录3.2 情况B&#xff1a;扩展分区和逻辑分区3.3 情况C&#xff1a;…

chatgpt赋能python:免费的Python编程软件:开发者必备工具!

免费的Python编程软件&#xff1a;开发者必备工具&#xff01; Python是一门广受欢迎的编程语言&#xff0c;它已经成为了很多公司和开发者的首选语言。Python的出现改变了编程的方式&#xff0c;它具有简单、易懂、易读、易写、易拓展等特点&#xff0c;因此成为了很多新手入…

使用 Pod 网络策略保护 Kubernetes 集群流量

Kubernetes Pod 默认可以自由地相互通信。当您的集群用于多个应用程序或团队时,这会带来安全风险。一个 Pod 中的错误行为或恶意访问可能会将流量引导至集群中的其他 Pod。 本文将教您如何通过设置网络策略来避免这种情况。这些规则可让您在 IP 地址级别( OSI第 3 层或第 4 …

二进制表示整数及运算

现代计算机存储和处理信息以二值信号表示&#xff0c;二值信号能够很容易地被表示、存储和传输。例如穿孔卡片上有洞或无洞、电压的高低或顺时针、及顺时针或逆时针的磁场。 图 二进制与电压的关系 1 二进制 大多数计算机使用8位作为一个字节&#xff0c;是最小的可寻址的内存…

【vue】vue高性能虚拟滚动列表【vue2和vue3版组件封装】

项目场景&#xff1a; 当前页显示10w多条数据&#xff0c;不做分页的情况进行渲染。加载和渲染页面会非常慢&#xff0c;滚动也非常卡顿 解决方案&#xff1a; 之渲染可视窗口的列表&#xff0c;其他列表不进行渲染。通过修改偏移量高度进行滚动列表。 vue2版本 virtualLi…

k8s安装环境准备:Virtualbox安装CentOS;复制多个CentOS虚拟机

1.安装virtualbox 下载virtualbox https://www.virtualbox.org/wiki/Downloads 安装&#xff08;windows&#xff09; 双击VirtualBox-7.0.8-156879-Win.exe 选择安装目录 安装完成后&#xff0c;打开virtualbox 2.下载CentOS 下载CentOS-7-x86_64-DVD-2009.iso http://isoredi…

做项目去实习到底做的什么?

300万字&#xff01;全网最全大数据学习面试社区等你来&#xff01; 今天是手机编辑的文章&#xff0c;说说做项目/实习这回事。 我之前发过一些视频&#xff0c;讲校招四要素的&#xff0c;其中一个很重要的部分就是实习。 对社招同学来说&#xff0c;就简单了&#xff0c;面试…

解决磁盘占用率过高100%问题

方法一&#xff1a;关闭程序 首先打开任务管理器&#xff0c;单击磁盘占用率一栏进行排序&#xff0c;查看占用磁盘最高的应用。若占用率最高的始终是同一个三方程序&#xff0c;可尝试卸载。 注&#xff1a;开机时由于频繁读写磁盘&#xff0c;磁盘占用率会很高&#xff0c;等…

vue内嵌原生前端三件套(html+CSS+JavaScript)

问题 vue内嵌原生前端三件套&#xff08;htmlCSSJavaScript&#xff09;&#xff0c;运行后前端页面无响应 详细问题 笔者使用vue框架进行开发&#xff0c; 对于可视化大屏采用echarts实现&#xff0c;但是网上所提供的echarts可视化大屏模板多采用原生前端三件套&#xff0…

13 GDI绘图技术

文章目录 GDI技术GDI 对象画笔对象画刷对象位图对像创建一个位图字体对象 区域对象区域组合 GDI技术 GDI(graphics Device Interface):图形设备接口&#xff0c;用于绘图。 In Windows CE, as in Windows-based desktop platforms, the graphics device interface (GDI) contr…