,光源基类
在Threejs中,光源用Light表示,它是所有光源的基类。它的构造函数是:
THREE.Light (color)
它有一个参数color,接受一个16进制的颜色值。例如要定义一种红色的光源,我们可以这样来定义:
Var light = new THREE.Light(0xFF0000);
由基类派生出来的其他种类光源
THREE.Light只是其他所有光源的基类,要让光源除了具有颜色的特性之外,我们需要其他光源。看看,下面的类图,是目前光源的继承结构。
环境光
经过多次反射而来的光称为环境光(或者也可以这么说:无法确定光最初的方向的光就叫环境光。比如阴天的时候没有太阳,你无法确定光是从哪里照射出来的。)
环境光的颜色会影响整个场景,并且其光线没有特定的来源,所以你无须指定它的位置。在使用其它光源的同时使用环境光,目的是弱化阴影或添加一些颜色。
环境光用THREE.AmbientLight来表示,它的构造函数如下所示:
AmbientLight( color,intensity )
color: 光的颜色
intensity : 光的强度,默认是1.0,就是说是100%强度的灯光
例子 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{padding: 0; margin: 0; overflow: hidden;}
</style>
<title>环境光</title>
</head>
<body>
<div id="WebGL-output"></div>
</body>
<script src='three.js'></script>
<script src='dat.gui.js'></script>
<script>
var scene = new THREE.Scene();
var axes = new THREE.AxisHelper(100);
scene.add(axes);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(-8,8,20);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#fff');
document.body.appendChild(renderer.domElement);
//矩形
var mshFloor = new THREE.Mesh( new THREE.CubeGeometry( 2000, 1, 2000 ), new THREE.MeshPhongMaterial());
mshFloor.position.set( 0, -1, 0 );
scene.add(mshFloor)
//立方体
var cube = new THREE.Mesh(new THREE.CubeGeometry(1,2,3), new THREE.MeshLambertMaterial({
color : 0x7777ff
}));
cube.position.set(0,0.5,0);
scene.add(cube);
//环境光
var light = new THREE.AmbientLight(0xffffff);
light.position.set( 0, 5, 0 );
scene.add(light);
//小球,它的位置就是光源的位置
var sphereLight = new THREE.SphereGeometry(0.2);
var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
sphereLightMesh.position.set(light.position.x, light.position.y, light.position.z);
scene.add(sphereLightMesh);
//GUI
var controls = new function(){
this.color = light.color.getHex();
this.intensity = light.intensity;
this.light_x = light.position.x;
this.light_y = light.position.y;
this.light_z = light.position.z;
}
var gui = new dat.GUI();
gui.addColor(controls, 'color').onChange(function (e) {
light.color = new THREE.Color(e);
});
gui.add(controls, 'intensity', 0,1).onChange(function (e) {
light.intensity = e;
});
gui.add(controls, 'light_x', -50,50).onChange(function (e) {
light.position.x = e;
sphereLightMesh.position.x = e;
});
gui.add(controls, 'light_y', -50,50).onChange(function (e) {
light.position.y = e;
sphereLightMesh.position.y = e;
});
gui.add(controls, 'light_z', -50,50).onChange(function (e) {
light.position.z = e;
sphereLightMesh.position.z = e;
});
//更新函数
function updata(){
cube.rotation.y +=0.01;
axes.rotation.y +=0.01;
mshFloor.rotation.y +=0.01;
renderer.render(scene, camera);
requestAnimationFrame(updata);
}
updata();
//窗口事件
window.onresize = function(){
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</html>
效果图:
从上面的例子可以看出,光的位置对环境光是没有影响的。
点光源
点光源是一种单点发光并照射所有方向的光源。比如夜空中的照明灯。
点光源用PointLight来表示,它的构造函数如下所示:
PointLight( color, intensity, distance,decay)
color:光的颜色
intensity:光的强度,默认是1.0,就是说是100%强度的灯光
distance:光能照射到的最远的距离。
decay : 值为0~1. 此值越大,光的衰减程度越多。
例子 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{padding: 0; margin: 0; overflow: hidden;}
</style>
<title>点光源</title>
</head>
<body>
<div id="WebGL-output"></div>
</body>
<script src='three.js'></script>
<script src='dat.gui.js'></script>
<script>
var scene = new THREE.Scene();
var axes = new THREE.AxisHelper(100);
scene.add(axes);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(-8,8,20);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#fff');
document.body.appendChild(renderer.domElement);
//矩形
var mshFloor = new THREE.Mesh( new THREE.CubeGeometry( 2000, 1, 2000 ), new THREE.MeshPhongMaterial());
mshFloor.position.set( 0, -1, 0 );
scene.add(mshFloor)
//立方体
var cube = new THREE.Mesh(new THREE.CubeGeometry(1,2,3), new THREE.MeshLambertMaterial({
color : 0x7777ff
}));
cube.position.set(0,0.5,0);
scene.add(cube);
//点光源
var light = new THREE.PointLight(0xffffff, 1, 1000);
light.position.set( 0, 5, 0 );
scene.add(light);
//小球,它的位置就是光源的位置
var sphereLight = new THREE.SphereGeometry(0.2);
var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
sphereLightMesh.position.set(light.position.x, light.position.y, light.position.z);
scene.add(sphereLightMesh);
//GUI
var controls = new function(){
this.color = light.color.getHex();
this.intensity = light.intensity;
this.distance = light.distance;
this.light_x = light.position.x;
this.light_y = light.position.y;
this.light_z = light.position.z;
}
var gui = new dat.GUI();
gui.addColor(controls, 'color').onChange(function (e) {
light.color = new THREE.Color(e);
});
gui.add(controls, 'intensity', 0,1).onChange(function (e) {
light.intensity = e;
});
gui.add(controls, 'distance', 0,1000).onChange(function (e) {
light.distance = e;
});
gui.add(controls, 'light_x', -50,50).onChange(function (e) {
light.position.x = e;
sphereLightMesh.position.x = e;
});
gui.add(controls, 'light_y', -50,50).onChange(function (e) {
light.position.y = e;
sphereLightMesh.position.y = e;
});
gui.add(controls, 'light_z', -50,50).onChange(function (e) {
light.position.z = e;
sphereLightMesh.position.z = e;
});
//更新函数
function updata(){
cube.rotation.y +=0.01;
axes.rotation.y +=0.01;
mshFloor.rotation.y +=0.01;
renderer.render(scene, camera);
requestAnimationFrame(updata);
}
updata();
//窗口事件
window.onresize = function(){
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</html>
效果图:
聚光灯
聚光灯有一种锥形的效果。比如手电筒发射出来的光。
聚光灯用SpotLight来表示,它的构造函数如下所示:
SpotLight( color, intensity, distance, angle, penumbra, decay)
color:光的颜色
intensity:光的强度,默认是1.0,就是说是100%强度的灯光
distance:光能照射到的最远的距离。
angle : 椎体的角度
penumbra : 羽化程度
decay : 值为0~1. 此值越大,光的衰减程度越多。
例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{padding: 0; margin: 0; overflow: hidden;}
</style>
<title>聚光灯</title>
</head>
<body>
<div id="WebGL-output"></div>
</body>
<script src='three.js'></script>
<script src='dat.gui.js'></script>
<script>
var scene = new THREE.Scene();
var axes = new THREE.AxisHelper(100);
scene.add(axes);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(-8,8,20);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#fff');
renderer.shadowMapEnabled = true;
document.body.appendChild(renderer.domElement);
//矩形
var mshFloor = new THREE.Mesh( new THREE.CubeGeometry( 2000, 1, 2000 ), new THREE.MeshPhongMaterial());
mshFloor.receiveShadow = true;
mshFloor.position.set( 0, -1, 0 );
scene.add(mshFloor)
//立方体
var cube = new THREE.Mesh(new THREE.CubeGeometry(1,2,3), new THREE.MeshLambertMaterial({
color : 0x7777ff
}));
cube.position.set(0,0.5,0);
cube.castShadow = true;
scene.add(cube);
//聚光灯
var light = new THREE.SpotLight(0xffffff, 1, 1000, 1);
light.position.set( 0, 5, 0 );
light.castShadow = true;
light.shadowMapWidth = 2048; //阴影的宽度用多少像素绘制
light.shadowMapHeight = 2048; //阴影的高度用多少像素绘制
scene.add(light);
//小球,它的位置就是光源的位置
var sphereLight = new THREE.SphereGeometry(0.2);
var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
sphereLightMesh.position.set(light.position.x, light.position.y, light.position.z);
scene.add(sphereLightMesh);
//辅助线,帮助我们看到聚光灯angle的变化
var lightHelper = new THREE.SpotLightHelper( light );
scene.add( lightHelper );
//GUI
var controls = new function(){
this.color = light.color.getHex();
this.intensity = light.intensity;
this.distance = light.distance;
this.angle = light.angle;
this.penumbra = 1; //聚光灯的模糊度
this.light_x = light.position.x;
this.light_y = light.position.y;
this.light_z = light.position.z;
}
var gui = new dat.GUI();
gui.addColor(controls, 'color').onChange(function (e) {
light.color = new THREE.Color(e);
});
gui.add(controls, 'intensity', 0,1).onChange(function (e) {
light.intensity = e;
});
gui.add(controls, 'distance', 0,1000).onChange(function (e) {
light.distance = e;
});
gui.add(controls, 'angle', 0,1).onChange(function (e) {
light.angle = e;
lightHelper.update();
});
gui.add(controls, 'penumbra', 0,1).onChange(function (e) {
light.penumbra = e;
});
gui.add(controls, 'light_x', -50,50).onChange(function (e) {
light.position.x = e;
sphereLightMesh.position.x = e;
lightHelper.update();
});
gui.add(controls, 'light_y', -50,50).onChange(function (e) {
light.position.y = e;
sphereLightMesh.position.y = e;
lightHelper.update();
});
gui.add(controls, 'light_z', -50,50).onChange(function (e) {
light.position.z = e;
sphereLightMesh.position.z = e;
lightHelper.update();
});
//更新函数
function updata(){
cube.rotation.y +=0.01;
axes.rotation.y +=0.01;
mshFloor.rotation.y +=0.01;
renderer.render(scene, camera);
requestAnimationFrame(updata);
}
updata();
//窗口事件
window.onresize = function(){
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</html>
效果图:
方向光
方向光可以看作是距离很远的光源,比如太阳光。被方向光照亮的整个区域接收到的光的强度是一样的。你可以用方向光来模拟晚上到早上的过渡效果。
方向光用DirectionalLight来表示,它的构造函数如下所示:
DirectionalLight(color, intensity)
color :颜色
intensity :光的强度,默认是1.0,就是说是100%强度的灯光
例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{padding: 0; margin: 0; overflow: hidden;}
</style>
<title>方向光</title>
</head>
<body>
<div id="WebGL-output"></div>
</body>
<script src='three.js'></script>
<script src='dat.gui.js'></script>
<script>
var scene = new THREE.Scene();
var axes = new THREE.AxisHelper(100);
scene.add(axes);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(-8,8,20);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#fff');
renderer.shadowMapEnabled = true;
document.body.appendChild(renderer.domElement);
//矩形
var mshFloor = new THREE.Mesh( new THREE.CubeGeometry( 2000, 1, 2000 ), new THREE.MeshPhongMaterial());
mshFloor.position.set( 0, -1, 0 );
mshFloor.receiveShadow = true;
scene.add(mshFloor)
//立方体
var cube = new THREE.Mesh(new THREE.CubeGeometry(1,2,3), new THREE.MeshLambertMaterial({
color : 0x7777ff
}));
cube.position.set(0,0.5,0);
cube.castShadow = true;
scene.add(cube);
//方向光
var light = new THREE.DirectionalLight (0xffffff, 0.5);
light.castShadow = true;
light.position.set( 0, 5, 0 );
scene.add(light);
//小球,它的位置就是光源的位置
var sphereLight = new THREE.SphereGeometry(0.2);
var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
sphereLightMesh.position.set(light.position.x, light.position.y, light.position.z);
scene.add(sphereLightMesh);
//GUI
var controls = new function(){
this.color = light.color.getHex();
this.intensity = light.intensity;
this.light_x = light.position.x;
this.light_y = light.position.y;
this.light_z = light.position.z;
}
var gui = new dat.GUI();
gui.addColor(controls, 'color').onChange(function (e) {
light.color = new THREE.Color(e);
});
gui.add(controls, 'intensity', 0,1).onChange(function (e) {
light.intensity = e;
});
gui.add(controls, 'light_x', -50,50).onChange(function (e) {
light.position.x = e;
sphereLightMesh.position.x = e;
});
gui.add(controls, 'light_y', -50,50).onChange(function (e) {
light.position.y = e;
sphereLightMesh.position.y = e;
});
gui.add(controls, 'light_z', -50,50).onChange(function (e) {
light.position.z = e;
sphereLightMesh.position.z = e;
});
//更新函数
function updata(){
cube.rotation.y +=0.01;
axes.rotation.y +=0.01;
mshFloor.rotation.y +=0.01;
renderer.render(scene, camera);
requestAnimationFrame(updata);
}
updata();
//窗口事件
window.onresize = function(){
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</html>
效果图:
区域光
区域光也叫平面光,使用平面光你可以定义一个发光的矩形。该光源不在标准的three.js库中,而是在扩展库中,所以使用之前需要导入几个额外的js文件。
另外该光源是一种非常复杂的光源,它会对WebglRenderer对象造成非常严重的性能损失。所以使用该光源时要使用WebGLDeferredRenderer来代替WebglRenderer。
平面光用AreaLight来表示,它的构造函数如下所示:
AreaLight(color, intensity)
color :颜色
intensity :光的强度,默认是1.0,就是说是100%强度的灯光
例子 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{padding: 0; margin: 0; overflow: hidden;}
</style>
<title>平面光</title>
</head>
<body>
<div id="WebGL-output"></div>
</body>
<script src='three_AreaLight.js'></script>
<script src='dat.gui.js'></script>
<!--平面光需要导入的js库-->
<script type="text/javascript" src="WebGLDeferredRenderer.js"></script>
<script type="text/javascript" src="ShaderDeferred.js"></script>
<script type="text/javascript" src="RenderPass.js"></script>
<script type="text/javascript" src="EffectComposer.js"></script>
<script type="text/javascript" src="CopyShader.js"></script>
<script type="text/javascript" src="ShaderPass.js"></script>
<script type="text/javascript" src="FXAAShader.js"></script>
<script type="text/javascript" src="MaskPass.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0,30,30);
camera.lookAt(scene.position);
//WebGLDeferredRenderer
var renderer = new THREE.WebGLDeferredRenderer({
width: window.innerWidth,
height: window.innerHeight,
scale: 1, antialias: true,
tonemapping: THREE.FilmicOperator, brightness: 2.5
});
document.body.appendChild(renderer.domElement);
//平面
var mshFloor = new THREE.Mesh(
new THREE.PlaneGeometry(70, 70, 1, 1),
new THREE.MeshPhongMaterial({ color: 0xffffff, specular: 0xffffff, shininess: 200 })
);
mshFloor.rotation.x = -0.5 * Math.PI;
scene.add(mshFloor);
//平面光
var light = new THREE.AreaLight(0xffffff, 1.5);
light.position.set(0, 5, -10);
light.rotation.set(-Math.PI / 2, 0, 0);
light.width = 2;
light.height = 4;
scene.add(light);
//伪发光的立方块
var geom = new THREE.CubeGeometry(2, 4, 0);
var mesh = new THREE.MeshBasicMaterial({color: 0xffffff})
var cube = new THREE.Mesh(geom, mesh);
cube.position = light.position;
scene.add(cube);
//GUI
var controls = new function(){
this.color = light.color.getHex();
this.intensity = light.intensity;
this.light_x = light.position.x;
this.light_y = light.position.y;
this.light_z = light.position.z;
}
var gui = new dat.GUI();
gui.addColor(controls, 'color').onChange(function (e) {
light.color = new THREE.Color(e);
//重新设置材质的颜色
mesh.color = new THREE.Color(e);
scene.remove(cube);
cube = new THREE.Mesh(geom, mesh);
cube.position = light.position;
scene.add(cube);
});
gui.add(controls, 'intensity', 0,3).onChange(function (e) {
light.intensity = e;
});
gui.add(controls, 'light_x', -50,50).onChange(function (e) {
light.position.x = e;
cube.position.x = e;
});
gui.add(controls, 'light_y', -50,50).onChange(function (e) {
light.position.y = e;
cube.position.y = e;
});
gui.add(controls, 'light_z', -50,50).onChange(function (e) {
light.position.z = e;
cube.position.z = e;
});
//更新函数
function updata(){
renderer.render(scene, camera);
requestAnimationFrame(updata);
}
updata();
//窗口事件
window.onresize = function(){
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</html>
效果图 :
生成阴影
上面的例子中,有一些光源能生成阴影,而有一些光源不能。因为在three.js中,能形成阴影的光源只有 方向光 和 聚光灯;而相对的能表现阴影效果的材质只有 LambertMaterial 和 PhongMaterial。因此在设置光源和材质的时候,一定要注意这一点。
给物体生成阴影需要4个步骤 :
1、renderer.shadowMapEnabled = true;
告诉渲染器我们需要阴影。为此可以将shadowMapEnabled (允许阴影映射)属性设为true
2、plane.receiveShadow = true;
接受阴影的物体需要把receiveShadow 设为true
3、cube.castShadow = true;
投射阴影的物体需要啊castShadow 设为true
4、light.castShadow = true;
把光源的castShadow 也设为true (需要注意改光源是否能产生阴影)
设置阴影的像素
设置光源的 shadowMapWidth 和shadowMapHeight 可以调整阴影的真实程度。如下图 :
设置之前
设置之后
例子 :
light.shadowMapWidth = 2048; //阴影的宽度用多少像素绘制
light.shadowMapHeight = 2048; //阴影的高度用多少像素绘制
本章代码下载地址 :three.js光源-Web开发代码类资源-CSDN下载