本章的主要内容
1 three.js有哪些可用的光源
2 什么时候用什么光源、
3 如何调整配置各种光源
4 如何创建镜头炫光
一 光源
光源大概有7种,
其中基础光源有4种
环境光(AmbientLight会它的颜色会添加到整个场景和所有对象的当前颜色上),
点光源(PointLight空间中的一点,朝所有的方向发射光线),
聚光灯光源(SpotLight这种光源有聚光的效果,类似于台灯,吊灯,手电筒),
方向光(DirectionalLight也称无限光,从这种光源发出的光线可以看作是平行的,例如太阳光)
特殊光源有3种(这三种我们后面再详述)
半球光光源(HemisphereLight,可以为室内场景创建更加自然的光照效果,模拟反光面和光线微弱的天气)
面光源(AreaLight使用这种光源可以指定散发光线的平面,而不是空间的一个点)
镜头炫光(LensFlare这不是一种光源,但是通过该炫光可以为场景中的光源添加炫目的效果)
1.1 环境光
AmbientLight光源的颜色会影响到整个场景,
环境光没有特定的光源,是模拟漫反射的一种光源,因此不需要指定位置
它能将灯光均匀地照射在场景中每个物体上面,一般情况下用来弱化阴影或者添加一些颜色到环境中,
因此不能将AmbientLight作为场景中的唯一光源,那样的会就会导致下图左边的情况,
右边为使用了SpotLight光源,并使用AmbientLight用来弱化SpotLight生成的生硬的阴影,
注意一下AmbientLight会将颜色应用于整个场景,因此使用AmbientLight的时候,用色应该尽量的保守,如果颜色过于明亮,画面颜色就会饱和
var ambiColor = "#0c0c0c";
var ambientLight = new THREE.AmbientLight(ambiColor);
scene.add(ambientLight);
//环境光不需要设置光源的位置等信息,只需要一个颜色即可,这个颜色就是漫反射到所有对象上的颜色
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="dat.gui.js"></script> <script type="text/javascript" src="AsciiEffect.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { var scene=new THREE.Scene();//生成一个场景 //生成一个相机 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面 camera.position.x=-20; camera.position.y=40; camera.position.z=30; camera.lookAt(scene.position); //生成一个渲染器 var render=new THREE.WebGLRenderer(); render.setClearColorHex(0xEEEEEE); render.setSize(window.innerWidth,window.innerHeight); render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 //生成一个坐标轴,辅助线 var axes=new THREE.AxisHelper(20); //生成一个平面 var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面 //生成一个材质 var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff}); //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体 var plane=new THREE.Mesh(planeGeometry,planeMaterial); plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转 plane.position.x=0; plane.position.y=0; plane.position.z=0; plane.receiveShadow=true;//平面进行接受阴影 var cubeGeometry=new THREE.CubeGeometry(10,10,10); var planeMaterial1=new THREE.MeshLambertMaterial({color:0xff0000}); /*var cube=new THREE.Mesh(cubeGeometry,planeMaterial1); //plane1.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转 cube.position.x=-4; cube.position.y=3; cube.position.z=0; cube.castShadow=true;//需要阴影,方块进行投射阴影*/ //聚光灯光源 /*var spotLight=new THREE.SpotLight(0xffffff); spotLight.position.set(-40,60,-10); spotLight.castShadow=true;*/ var ambientLight=new THREE.AmbientLight("#0c0c0c"); scene.add(ambientLight); //将相机,渲染器,坐标轴,平面都追加到场景中,然后对场景和相机进行渲染 scene.add(camera); scene.add(render); scene.add(axes); scene.add(plane); //scene.add(cube); //scene.add(spotLight); //var effect=new THREE.AsciiEffect(render); ///effect.setSize(window.innerWidth,window.innerHeight); document.getElementById("WebGL-output").append(render.domElement); var controls=new function(){ this.rotationSpeed=0.02; this.numberofObject=scene.children.length; this.addCube=function(){ var cubeSize=Math.ceil(Math.random()*3); var cubeGeometry=new THREE.BoxGeometry(cubeSize,cubeSize,cubeSize); var cubeMaterial=new THREE.MeshLambertMaterial({color:Math.random()*0xffffff}); var cube=new THREE.Mesh(cubeGeometry,cubeMaterial); cube.castShadow=true; cube.name="cube-"+scene.children.length; cube.position.x=-30+Math.round(Math.random()*planeGeometry.parameters.width); cube.position.y=Math.round(Math.random()*5); cube.position.z=-20+Math.round(Math.random()*planeGeometry.parameters.height); scene.add(cube); this.numberofObject=scene.children.length; }; this.removeCube=function(){ var allChildren=scene.children; var lastChild=allChildren[allChildren.length-1]; if(lastChild instanceof THREE.Mesh){ scene.remove(lastChild); this.numberofObject=scene.children.length; } }; }; var gui=new dat.GUI(); gui.add(controls,"rotationSpeed",0,0.5); gui.add(controls,"addCube"); gui.add(controls,"removeCube"); gui.add(controls,"numberofObject").listen();; function renderScene(){ scene.traverse(function (e) { if (e instanceof THREE.Mesh && e != plane) { e.rotation.x += controls.rotationSpeed; e.rotation.y += controls.rotationSpeed; e.rotation.z += controls.rotationSpeed; } }); requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.2 点光源
点光源是一种单点发光,照射全部方向的光源,例如生活中的照明弹就属于点光源,
由于点光源是向所有方向发射光线,因此不会产生阴影,
它有颜色color,强度intensity,距离distance,位置position,是否可见visible等几个属性,
PointLight光源的distance属性决定的是光线可以照射多远,值为0时,表示光线的亮度不会随着距离的增加而递减
其中左图为强度较小的情况,右图为强度较大的情况
var pointColor = "#ccffcc";
var pointLight = new THREE.PointLight(pointColor);
pointLight.distance = 100;//距离,决定了光线可以照射多远
pointLight.intensity = 1;//强度
scene.add(pointLight);
1.3 聚光灯光源
SpotLight聚光灯光源有一种锥形的效果,例如日常生活中的手电筒,灯笼等,该光源具有下面的属性
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属性,为3D空间的一个点,target属性的值为Object3D
var target = new THREE.Object3D();
target.position = new THREE.Vector3(5, 0, 0);
spotLight.target = target;
*/
spotLight.distance = 0;
spotLight.angle = 0.4;
scene.add(spotLight);
属性 | 描述 |
castShadow(投影) | 设置为true,则该光源可以产生阴影 |
shadowCameraNear | 从距离光源的哪一点开始生成阴影 |
shadowCameraFar | 从距离光源哪一点开始停止生成阴影 |
shadowCameraFov | 形成阴影的视场 |
target | 决定了光源的方向,如果target属性的值出现移动的情况,那么光源也会跟着该target进行移动,该值必须为Object3D类型,因此可以是geom,也可以是具体的某一个点,这个代码中会有体现 |
angle | 光源照射出来的光柱有多宽 |
exponent | 光强衰减指数,距离光源越远,光照强度越弱,但是减弱的速度是由该值控制 |
shadowCameraVisible | 通过设置此值,可以看到光源在哪里,以及如何产生阴影,即该值主要用于调试 |
shadowDarkness | 阴影强度,即阴影有多黑,场景渲染后该值不可以再修改了 |
shadowMapWidth | 多少像素用来生成阴影,如果阴影的边缘看起来不够光滑参差不齐,那么可以考虑加大该值,该值同shadowDarkness,场景渲染后不可修改 |
distance | 距离target的距离 |
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="dat.gui.js"></script> <script type="text/javascript" src="AsciiEffect.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { var scene=new THREE.Scene();//生成一个场景 //生成一个相机 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面 camera.position.x=-20; camera.position.y=40; camera.position.z=30; camera.lookAt(scene.position); //生成一个渲染器 var render=new THREE.WebGLRenderer(); render.setClearColorHex(0xEEEEEE); render.setSize(window.innerWidth,window.innerHeight); render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 //生成一个坐标轴,辅助线 var axes=new THREE.AxisHelper(20); //生成一个平面 var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面 //生成一个材质 var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff}); //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体 var plane=new THREE.Mesh(planeGeometry,planeMaterial); plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转 plane.position.x=0; plane.position.y=0; plane.position.z=0; plane.receiveShadow=true;//平面进行接受阴影 var cubeGeometry=new THREE.CubeGeometry(10,10,10); var planeMaterial1=new THREE.MeshLambertMaterial({color:0xff0000}); /*var cube=new THREE.Mesh(cubeGeometry,planeMaterial1); //plane1.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转 cube.position.x=-4; cube.position.y=3; cube.position.z=0; cube.castShadow=true;//需要阴影,方块进行投射阴影*/ //聚光灯光源 /**/var spotLight=new THREE.SpotLight(0xffffff); spotLight.position.set(0,20,0);
spotLight.castShadow=true;
spotLight.target=plane;//光源照射的方向
spotLight.angle=Math.PI/3;//光源的角度
spotLight.shadowCameraNear=2;
spotLight.shadowCameraFar=20;
spotLight.shadowCameraVisible=true;
scene.add(spotLight); //环境光 /*var ambientLight=new THREE.AmbientLight("#0c0c0c"); scene.add(ambientLight);*/ //点光源 /* var pointLight=new THREE.PointLight(0xffffff); pointLight.position.set(0,10,10); pointLight.distance=100; pointLight.castShadow=true; pointLight.intensity=3; scene.add(pointLight);*/ var lightGeometry=new THREE.BoxGeometry(4,4,4); var lightMaterial=new THREE.MeshLambertMaterial({color:Math.random()*0xffffff}); var light=new THREE.Mesh(lightGeometry,lightMaterial); light.position.set(0,20,0); scene.add(light); //将相机,渲染器,坐标轴,平面都追加到场景中,然后对场景和相机进行渲染 scene.add(camera); scene.add(render); scene.add(axes); scene.add(plane); //scene.add(cube); // //var effect=new THREE.AsciiEffect(render); ///effect.setSize(window.innerWidth,window.innerHeight); document.getElementById("WebGL-output").append(render.domElement); var controls=new function(){ this.rotationSpeed=0.02; this.numberofObject=scene.children.length; this.addCube=function(){ var cubeSize=Math.ceil(Math.random()*3); var cubeGeometry=new THREE.BoxGeometry(cubeSize,cubeSize,cubeSize); var cubeMaterial=new THREE.MeshLambertMaterial({color:Math.random()*0xffffff}); var cube=new THREE.Mesh(cubeGeometry,cubeMaterial); cube.castShadow=true; cube.name="cube-"+scene.children.length; cube.position.x=-30+Math.round(Math.random()*planeGeometry.parameters.width); cube.position.y=Math.round(Math.random()*5); cube.position.z=-20+Math.round(Math.random()*planeGeometry.parameters.height); scene.add(cube); this.numberofObject=scene.children.length; }; this.removeCube=function(){ var allChildren=scene.children; var lastChild=allChildren[allChildren.length-1]; if(lastChild instanceof THREE.Mesh){ scene.remove(lastChild); this.numberofObject=scene.children.length; } }; }; var gui=new dat.GUI(); gui.add(controls,"rotationSpeed",0,0.5); gui.add(controls,"addCube"); gui.add(controls,"removeCube"); gui.add(controls,"numberofObject").listen();; function renderScene(){ requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.4 DirectinalLight---方向光光源(类似于太阳光的一种光源)
该光源可以看做是距离很远很远的光源,以至于该光源所发出的所有光线都是相互平行的,
方向光光源的一个范例就是太阳,方向光光源不像聚焦光那样离目标越远越暗淡,被方向光光源照亮的整个区域接收到的光强是一样的
方向光光源的shadowCameraNear,far,left,right,top,bottom六个属性构成了一个方块的范围,
在这个方块的范围内的所有对象都可以投影或者接收投影,包围对象的方块范围定义的越紧密,投影的效果越好
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="dat.gui.js"></script> <script type="text/javascript" src="AsciiEffect.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { var scene=new THREE.Scene();//生成一个场景 //生成一个相机 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面 camera.position.x=-20; camera.position.y=40; camera.position.z=30; camera.lookAt(scene.position); //生成一个渲染器 var render=new THREE.WebGLRenderer(); render.setClearColorHex(0xEEEEEE); render.setSize(window.innerWidth,window.innerHeight); render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 //生成一个坐标轴,辅助线 var axes=new THREE.AxisHelper(20); //生成一个平面 var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面 //生成一个材质 var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff}); //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体 var plane=new THREE.Mesh(planeGeometry,planeMaterial); plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转 plane.position.x=0; plane.position.y=0; plane.position.z=0; plane.receiveShadow=true;//平面进行接受阴影 var cubeGeometry=new THREE.CubeGeometry(10,10,10); var planeMaterial1=new THREE.MeshLambertMaterial({color:0xff0000}); /*var cube=new THREE.Mesh(cubeGeometry,planeMaterial1); //plane1.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转 cube.position.x=-4; cube.position.y=3; cube.position.z=0; cube.castShadow=true;//需要阴影,方块进行投射阴影*/ //聚光灯光源 /*var spotLight=new THREE.SpotLight(0xffffff); spotLight.position.set(0,20,0); spotLight.castShadow=true; spotLight.target=plane;//光源照射的方向 spotLight.angle=Math.PI/3;//光源的角度 spotLight.shadowCameraNear=2; spotLight.shadowCameraFar=20; spotLight.shadowCameraVisible=true; scene.add(spotLight);*/ //环境光 /*var ambientLight=new THREE.AmbientLight("#0c0c0c"); scene.add(ambientLight);*/ //点光源 /* var pointLight=new THREE.PointLight(0xffffff); pointLight.position.set(0,10,10); pointLight.distance=100; pointLight.castShadow=true; pointLight.intensity=3; scene.add(pointLight);*/ /*方向光光源*/ var pointColor = "white"; var directionalLight = new THREE.DirectionalLight(pointColor); directionalLight.position.set(0,10,0); directionalLight.castShadow = true; directionalLight.shadowCameraNear =6; directionalLight.shadowCameraFar =10; directionalLight.shadowCameraLeft =-5; //directionalLight.shadowCameraLeft = 10; directionalLight.shadowCameraRight =5; directionalLight.shadowCameraTop =5; directionalLight.shadowCameraBottom =-5; directionalLight.shadowCameraVisible=true; //directionalLight.distance = 5; directionalLight.target=plane; directionalLight.intensity = 0.5; //directionalLight.shadowMapHeight = 1024; //directionalLight.shadowMapWidth = 1024; scene.add(directionalLight); var lightGeometry=new THREE.BoxGeometry(1,1,1); var lightMaterial=new THREE.MeshLambertMaterial({color:Math.random()*0xffffff}); var light=new THREE.Mesh(lightGeometry,lightMaterial); light.position.set(0,10,0); scene.add(light); //将相机,渲染器,坐标轴,平面都追加到场景中,然后对场景和相机进行渲染 scene.add(camera); scene.add(render); //scene.add(axes); scene.add(plane); //scene.add(cube); // //var effect=new THREE.AsciiEffect(render); ///effect.setSize(window.innerWidth,window.innerHeight); document.getElementById("WebGL-output").append(render.domElement); var controls=new function(){ this.rotationSpeed=0.02; this.numberofObject=scene.children.length; this.addCube=function(){ var cubeSize=Math.ceil(Math.random()*3); var cubeGeometry=new THREE.BoxGeometry(cubeSize,cubeSize,cubeSize); var cubeMaterial=new THREE.MeshLambertMaterial({color:Math.random()*0xffffff}); var cube=new THREE.Mesh(cubeGeometry,cubeMaterial); cube.castShadow=true; cube.name="cube-"+scene.children.length; cube.position.x=-30+Math.round(Math.random()*planeGeometry.parameters.width); cube.position.y=Math.round(Math.random()*5); cube.position.z=-20+Math.round(Math.random()*planeGeometry.parameters.height); scene.add(cube); this.numberofObject=scene.children.length; }; this.removeCube=function(){ var allChildren=scene.children; var lastChild=allChildren[allChildren.length-1]; if(lastChild instanceof THREE.Mesh){ scene.remove(lastChild); this.numberofObject=scene.children.length; } }; }; var gui=new dat.GUI(); gui.add(controls,"rotationSpeed",0,0.5); gui.add(controls,"addCube"); gui.add(controls,"removeCube"); gui.add(controls,"numberofObject").listen();; function renderScene(){ requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.5 半球光源----HemisphereLight
这种光源可以为室外场景创建更加自然的光照效果
我们模拟室外光照的时候,可以使用方向光源来模拟太阳,再添加一个环境光源,为场景添加基础色
但是这样看起来不太自然,因为室外的光并不都是来自于上方,很多是来自于空气的散射和地面的反射,以及其他物体的反射
所以在使用方向光源来模拟太阳的情况下再添加一个半球光就自然多了
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="dat.gui.js"></script> <script type="text/javascript" src="AsciiEffect.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { var scene=new THREE.Scene();//生成一个场景 //生成一个相机 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面 camera.position.x=-20; camera.position.y=40; camera.position.z=30; camera.lookAt(scene.position); scene.add(camera); //生成一个渲染器 var render=new THREE.WebGLRenderer(); render.setClearColorHex(0xEEEEEE); render.setSize(window.innerWidth,window.innerHeight); render.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 scene.add(render); //生成一个地面的平面,该地面的材质不再只是颜色,而是一个图片 var textureGrass = THREE.ImageUtils.loadTexture("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(10,10,10); var cubeMaterial=new THREE.MeshLambertMaterial({color:"red"}); 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 hemiLight=new THREE.HemisphereLight(0x0000ff,0x00ff00,0.6); hemiLight.position.set(0,500,0); hemiLight.groundColor = new THREE.Color(0x00ff00);//设置地面发出的光线的颜色 hemiLight.color = new THREE.Color(0x0000ff);//设置天空发出的光线的颜色 hemiLight.intensity = 0.6; scene.add(hemiLight); //生成聚光灯 var spotLight0 = new THREE.SpotLight(0xcccccc); spotLight0.position.set(-40, 60, -10); spotLight0.lookAt(plane); scene.add(spotLight0); //生成一个方向光,模拟太阳光 var pointColor = "#ffffff"; var dirLight = new THREE.DirectionalLight(pointColor); dirLight.position.set(0, 10, 0); 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").append(render.domElement); function renderScene(){ requestAnimationFrame(renderScene); render.render(scene, camera); } scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.6 平面光光源------AreaLight
平面光光源可以定义为一个发光的矩形
1 由于该光源是THREE.js的扩展,需要引入扩展库
2 平面光源是一种很复杂的光源,因此不能再使用WebGLRenderer对象了,该对象会造成严重的性能损失
3 因此在处理复杂光源或者多个光源的时候,使用WebGL的延迟渲染器WebGLDeferredRenderer
<!DOCTYPE html> <html> <head> <title>Example 03.06 - 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> <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 { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> var camera; // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); scene.add(camera); // create a render and set the size // var renderer = new THREE.WebGLRenderer(); var renderer = new THREE.WebGLDeferredRenderer({ width: window.innerWidth, height: window.innerHeight, scale: 1, antialias: true, tonemapping: THREE.FilmicOperator, brightness: 2.5 }); // renderer.setSize(window.innerWidth, window.innerHeight); // renderer.shadowMapEnabled = true; // create the ground plane 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.receiveShadow = true; // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.x = 0; plane.position.y = 0; plane.position.z = 0; // add the plane to the scene scene.add(plane); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 30; camera.position.z = 21; camera.lookAt(new THREE.Vector3(0, 0, -30)); // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(renderer.domElement); // call the render function var step = 0; var spotLight0 = new THREE.SpotLight(0xcccccc); spotLight0.position.set(-40, 60, -10); spotLight0.intensity = 0.1; spotLight0.lookAt(plane); scene.add(spotLight0); var areaLight1 = new THREE.AreaLight(0xff0000, 3);// color和instensity areaLight1.position.set(-10, 10, -35); areaLight1.rotation.set(-Math.PI / 2, 0, 0); areaLight1.width = 4; areaLight1.height = 9.9; scene.add(areaLight1); 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); 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); 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); var controls = new function () { this.rotationSpeed = 0.02; 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(); // render using requestAnimationFrame 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; </script> </body> </html>
1.7 镜头眩光----LensFlare
当我们直接朝着太阳拍照时就会出现镜头眩光,对于游戏或者三维图像来说,镜头眩光会使得场景看起来更真实
<!DOCTYPE html> <html> <head> <title>Example 03.07 - 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 { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); scene.fog = new THREE.Fog(0xaaaaaa, 0.010, 200); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size 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("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; // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; // add the plane to the scene scene.add(plane); // create a cube 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; // position the cube cube.position.x = -4; cube.position.y = 3; cube.position.z = 0; // add the cube to the scene 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); // position the sphere sphere.position.x = 10; sphere.position.y = 5; sphere.position.z = 10; sphere.castShadow = true; // add the sphere to the scene scene.add(sphere); // position and point the camera to the center of the scene 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 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); // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(renderer.domElement); // call the render function var step = 0; // used to determine the switch point for the light animation var invert = 1; var phase = 0; var controls = new function () { this.rotationSpeed = 0.03; this.bouncingSpeed = 0.03; this.ambientColor = ambiColor; this.pointColor = pointColor; this.intensity = 0.1; 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) { spotLight.color = new THREE.Color(e); }); gui.add(controls, 'intensity', 0, 5).onChange(function (e) { spotLight.intensity = e; }); var textureFlare0 = THREE.ImageUtils.loadTexture("lensflare0.png"); var textureFlare3 = THREE.ImageUtils.loadTexture("lensflare3.png"); var flareColor = new THREE.Color(0xffaacc); /*参数1:纹理,眩光的材质 参数2:尺寸,眩光的大小,-1的话就是使用材质本身大小 参数3:距离,光源(0)到相机(1)的距离 参数4:融合,//当眩光有多种材质的时候,这些材质如何融合在一起 参数5:颜色,眩光的颜色*/ var lensFlare = new THREE.LensFlare(textureFlare0, 350, 0.0, THREE.AdditiveBlending, flareColor); 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(); function render() { stats.update(); // rotate the cube around its axes cube.rotation.x += controls.rotationSpeed; cube.rotation.y += controls.rotationSpeed; cube.rotation.z += controls.rotationSpeed; // bounce the sphere up and down step += controls.bouncingSpeed; 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; </script> </body> </html>
总结
环境光源没有位置概念,会将颜色应用到场景的每一个物体上,主要作用是弱化阴影,给场景添加颜色
点光源类似于照明弹,朝所有的方向发光,因此不产生阴影
聚光灯光源类似于手电筒,形成锥形的光束,随着距离的增加而变弱,可以设定生成阴影
方向光光源类似于太阳,从很远的地方发出的平行光束,距离越远,衰减的越多
想要一个自然的室外效果,除了添加环境光弱化阴影,添加聚光灯为场景增加光线,还需要使用半球光光源将天空和空气以及地面的散射计算进去,使得更自然,更真实
平面光光源定义了一个发光的发光体,需要使用webgl的延迟渲染机制
眩光效果,在有太阳的时候使用眩光光源,会使得场景更真实