目录
1.常见的光源类型
Threejs虚拟光源是对自然界光照的模拟,threejs搭建虚拟场景的时候,为了更好的渲染场景,往往需要设置不同的光源,设置不同的光照强度,就像摄影师给你拍照要设置各种辅助灯光一样。
常用的有环境光(AmbientLight)、平行光(DriectionalLight)、点光源(PointLight)、聚光灯光源(SpotLight)四种。
此外还有半球光(HemisphereLight)、平面光光源(RectAreaLight),这些光源类型都继承于同一个光源基类-Light,所有其他的光类型都继承了该类描述的属性和方法。
1)构造器(Constructor)
Light( color : Integer, intensity : Float )
color - (可选参数) 16进制表示光的颜色。 缺省值 0xffffff (白色)。
intensity - (可选参数) 光照强度。 缺省值 1。
创造一个新的光源。注意,这并不是直接调用的(而是使用派生类之一)。
2)属性
公共属性请查看基类Object3D。
.color : Color
光源的颜色。如果构造的时候没有传递,默认会创建一个新的 Color 并设置为白色。
.intensity : Float
光照的强度,或者说能量。 在 physically correct 模式下, color 和强度 的乘积被解析为以坎德拉(candela)为单位的发光强度。 默认值 - 1.0
. isLight :Boolean
检查给定对象是否为 Light 类型的只读标志。
3)方法
公共方法请查看基类 Object3D。
.copy ( source : Light ) : this
从source复制 color, intensity 的值到当前光源对象中。
.toJSON ( meta : Object ) : Object
以JSON格式返回光数据。
meta -- 包含有元数据的对象,例如该对象的材质、纹理或图片。 将该light对象转换为 three.js JSON Object/Scene format(three.js JSON 物体/场景格式)。
1.1 环境光(AmbientLight)
环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。
环境光是当你在平常晴天时在室外看到的光的类型。虽然太阳的光线在一天的不同时刻以不同角度照射这个世界,但是大多数的东西都是可见的,即使它们在阴影中。因为光线能从任何物体上反弹,最终照射到所有物体,所以不被太阳光直接照射的物体也会被照亮。从这个角度来说上,甚至是房间里的灯泡也像表现得如同太阳一样传播环境光,因为如果房间不是很大的话,每一件物体都会被均等的照亮。环境光被描述为没有原点,没有方向,并且对场景中的所有物体都有相同效果的光。
代码示例:
const light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
1.1.1 构造函数
AmbientLight( color : Integer, intensity : Float )
color - (参数可选)颜色的rgb数值。缺省值为 0xffffff。
intensity - (参数可选)光照的强度。缺省值为 1。
1.1.2 属性
公共属性请查看基类 Light。
.castShadow : Boolean
这个参数在对象构造的时候就被设置成了 undefined 。因为环境光不能投射阴影。
.isAmbientLight : Boolean
Read-only flag to check if a given object is of type AmbientLight.
1.1.3 方法
公共方法请查看基类Light。
1.1.4 环境光效果
1.2 平行光(DriectionalLight)
平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。
平行光的位置是从position到target的位置,而不是一个只有旋转分量的自由光。
代码示例:
// White directional light at half intensity shining from the top.
const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
scene.add( directionalLight );
1.2.1 构造函数
DirectionalLight( color : Integer, intensity : Float )
color - (可选参数) 16进制表示光的颜色。 缺省值为 0xffffff (白色)。
intensity - (可选参数) 光照的强度。缺省值为1。
创建一个新的 DirectionalLight。
1.2.2 属性
公共属性请查看基类 Light。
.castShadow : Boolean
如果设置为 true 该平行光会产生动态阴影。 警告: 这样做的代价比较高而且需要一直调整到阴影看起来正确. 查看 DirectionalLightShadow 了解详细信息。该属性默认为 false。
.isDirectionalLight : Boolean
Read-only flag to check if a given object is of type DirectionalLight.
.position : Vector3
假如这个值设置等于 Object3D.DefaultUp (0, 1, 0),那么光线将会从上往下照射。
.shadow : DirectionalLightShadow
这个 DirectionalLightShadow 对象用来计算该平行光产生的阴影。
.target : Object3D
平行光的方向是从它的位置到目标位置。默认的目标位置为原点 (0,0,0)。
注意: 对于目标的位置,要将其更改为除缺省值之外的任何位置,它必须被添加到 scene 场景中去。
scene.add( light.target );
这使得属性target中的 matrixWorld 会每帧自动更新。
它也可以设置target为场景中的其他对象(任意拥有 position 属性的对象), 示例如下:
const targetObject = new THREE.Object3D();
scene.add(targetObject);
light.target = targetObject;
完成上述操作后,平行光现在就可以追踪到目标对像了。
1.2.3 方法
公共方法请查看基类 Light。
.copy ( source : DirectionalLight ) : this
复制 source 的值到这个平行光源对象。
1.2.4 平行光效果
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 10, 10);
directionalLight.castShadow = true;
scene.add(directionalLight);
1.3 点光源(PointLight)
从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。
代码示例
const light = new THREE.PointLight( 0xff0000, 1, 100 );
light.position.set( 50, 50, 50 );
scene.add( light );
1.3.1 构造函数
PointLight( color : Integer, intensity : Float, distance : Number, decay : Float )
color - (可选参数)) 十六进制光照颜色。 缺省值 0xffffff (白色)。
intensity - (可选参数) 光照强度。 缺省值 1。
distance - 这个距离表示从光源到光照强度为0的位置。 当设置为0时,光永远不会消失(距离无穷大)。缺省值 0.
decay - 沿着光照距离的衰退量。缺省值 1。 在 physically correct 模式中,decay = 2。
创建一个新的点光源(PointLight)。
1.3.2 属性
公共属性请查看基类Light。
.decay : Float
沿着光照距离的衰减量
在 physically correct 模式下,decay 设置为等于2将实现现实世界的光衰减。
缺省值为 1。
.distance : Float
如果非零,那么光强度将会从最大值当前灯光位置处按照距离线性衰减到0。 缺省值为 0.0。
.power : Float
光功率
在 physically correct 模式中, 表示以"流明(光通量单位)"为单位的光功率。 缺省值 - 4Math.PI。
该值与 intensity 直接关联power = intensity * 4π
修改该值也会导致光强度的改变。
.shadow : PointLightShadow
PointLightShadow用与计算此光照的阴影。
此对象的摄像机被设置为 fov 为90度,aspect为1, 近裁剪面 near 为0,远裁剪面far 为500的透视摄像机 PerspectiveCamera。
1.3.3 点光源效果
//点光源
const pointLight = new THREE.PointLight(0xff0000, 1);
pointLight.position.set(1, 1, 1);
pointLight.castShadow = true;
// 设置阴影贴图模糊度
pointLight.shadow.radius = 20;
// 设置阴影贴图的分辨率
pointLight.shadow.mapSize.set(512, 512);
pointLight.decay = 2;
scene.add(pointLight);
1.4 聚光灯光源(SpotLight)
光线从一个点沿一个方向射出,随着光线照射的变远,光线圆锥体的尺寸也逐渐增大。
代码示例
// white spotlight shining from the side, casting a shadow
const spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 100, 1000, 100 );
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 500;
spotLight.shadow.camera.far = 4000;
spotLight.shadow.camera.fov = 30;
scene.add( spotLight );
1.4.1 构造函数
SpotLight( color : Integer, intensity : Float, distance : Float, angle : Radians, penumbra : Float, decay : Float )
color - (可选参数) 十六进制光照颜色。 缺省值 0xffffff (白色)。
intensity - (可选参数) 光照强度。 缺省值 1。
distance - 从光源发出光的最大距离,其强度根据光源的距离线性衰减。
angle - 光线散射角度,最大为Math.PI/2。
penumbra - 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。
decay - 沿着光照距离的衰减量。
创建一个新的聚光灯。
1.4.2 属性
公共属性请查看基类Light。
.angle : Float
从聚光灯的位置以弧度表示聚光灯的最大范围。应该不超过 Math.PI/2。默认值为 Math.PI/3。
.castShadow : Boolean
此属性设置为 true 聚光灯将投射阴影。警告: 这样做的代价比较高而且需要一直调整到阴影看起来正确。 查看 SpotLightShadow 了解详细信息。 默认值为 false
.decay : Float
沿着光照距离的衰减量
在 physically correct 模式下,decay 设置为等于2将实现现实世界的光衰减。
缺省值为 1。
.distance : Float
如果非零,那么光强度将会从最大值当前灯光位置处按照距离线性衰减到0。 缺省值为 0.0。
.isSpotLight : Boolean
Read-only flag to check if a given object is of type SpotLight.
.penumbra : Float
聚光锥的半影衰减百分比。在0和1之间的值。 默认值 — 0.0。
.position : Vector3
假如这个值设置等于 Object3D.DefaultUp (0, 1, 0),那么光线将会从上往下照射。
.power : Float
光功率
在 physically correct 模式中, 表示以"流明(光通量单位)"为单位的光功率。 缺省值 - 4Math.PI。
该值与 intensity 直接关联
power = intensity * 4π
修改该值也会导致光强度的改变。
.shadow : SpotLightShadow
SpotLightShadow用与计算此光照的阴影。
.target : Object3D
聚光灯的方向是从它的位置到目标位置.默认的目标位置为原点 (0,0,0)。
注意: 对于目标的位置,要将其更改为除缺省值之外的任何位置,它必须被添加到 scene 场景中去。
scene.add( light.target );
这使得属性target中的 matrixWorld 会每帧自动更新。
它也可以设置target为场景中的其他对象(任意拥有 position 属性的对象),
示例如下:
const targetObject = new THREE.Object3D();
scene.add(targetObject);
light.target = targetObject;
完成上述操作后,聚光灯现在就可以追踪到目标对像了。
1.4.3 聚光灯效果
2.阴影
在具有方向光源的作用下,物体会形成阴影投影效果。Three.js物体投影模拟计算主要设置三部分,一个是设置产生投影的模型对象,一个是设置接收投影效果的模型,最后一个是光源对象本身的设置,光源如何产生投影。
灯光阴影设置流程:
// 1、材质要满足能够对光照有反应
// 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
// 3、设置光照投射阴影 directionalLight.castShadow = true;
// 4、设置物体投射阴影 sphere.castShadow = true;
// 5、设置物体接收阴影 plane.receiveShadow = true;
2.1 平行光投影计算代码
var geometry = new THREE.BoxGeometry(40, 100, 40);
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff
});
var mesh = new THREE.Mesh(geometry, material);
// mesh.position.set(0,0,0)
scene.add(mesh);
// 设置产生投影的网格模型
mesh.castShadow = true;
//创建一个平面几何体作为投影面
var planeGeometry = new THREE.PlaneGeometry(300, 200);
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0x999999
});
// 平面网格模型作为投影面
var planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(planeMesh); //网格模型添加到场景中
planeMesh.rotateX(-Math.PI / 2); //旋转网格模型
planeMesh.position.y = -50; //设置网格模型y坐标
// 设置接收阴影的投影面
planeMesh.receiveShadow = true;
// 方向光
var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源位置
directionalLight.position.set(60, 100, 40);
scene.add(directionalLight);
// 设置用于计算阴影的光源对象
directionalLight.castShadow = true;
// 设置计算阴影的区域,最好刚好紧密包围在对象周围
// 计算阴影的区域过大:模糊 过小:看不到或显示不完整
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 300;
directionalLight.shadow.camera.left = -50;
directionalLight.shadow.camera.right = 50;
directionalLight.shadow.camera.top = 200;
directionalLight.shadow.camera.bottom = -100;
// 设置mapSize属性可以使阴影更清晰,不那么模糊
// directionalLight.shadow.mapSize.set(1024,1024)
console.log(directionalLight.shadow.camera);
2.2 聚光光源投影计算代码
下面代码是聚光光源的设置,其它部分代码和平行光一样。
// 聚光光源
var spotLight = new THREE.SpotLight(0xffffff);
// 设置聚光光源位置
spotLight.position.set(50, 90, 50);
// 设置聚光光源发散角度
spotLight.angle = Math.PI /6
scene.add(spotLight); //光对象添加到scene场景中
// 设置用于计算阴影的光源对象
spotLight.castShadow = true;
// 设置计算阴影的区域,注意包裹对象的周围
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 300;
spotLight.shadow.camera.fov = 20;
2.3 点光源投影计算代码
示例:
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 目标:灯光与阴影
// 灯光阴影
// 1、材质要满足能够对光照有反应
// 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
// 3、设置光照投射阴影 directionalLight.castShadow = true;
// 4、设置物体投射阴影 sphere.castShadow = true;
// 5、设置物体接收阴影 plane.receiveShadow = true;
// 1、创建场景
const scene = new THREE.Scene();
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// 设置相机位置
camera.position.set(0, 0, 10);
scene.add(camera);
const sphereGeometry = new THREE.SphereBufferGeometry(1, 20, 20);
const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xffff00 });
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
// 投射阴影
sphere.castShadow = true;
scene.add(sphere);
// // 创建平面
const planeGeometry = new THREE.PlaneBufferGeometry(50, 50);
const planeMaterial = new THREE.MeshStandardMaterial();
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 接收阴影
plane.receiveShadow = true;
scene.add(plane);
// 灯光
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.8); // soft white light
scene.add(light);
//点光源
const pointLight = new THREE.PointLight(0xff0000, 1);
pointLight.position.set(1, 1, 1);
pointLight.castShadow = true;
// 设置阴影贴图模糊度
pointLight.shadow.radius = 20;
// 设置阴影贴图的分辨率
pointLight.shadow.mapSize.set(512, 512);
pointLight.decay = 2;
scene.add(pointLight);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 开启场景中的阴影贴图
renderer.shadowMap.enabled = true;
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);
// // 使用渲染器,通过相机将场景渲染进来
// renderer.render(scene, camera);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让控制器更有真实效果,必须在动画循环里调用.update()。
controls.enableDamping = true;
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 设置时钟
const clock = new THREE.Clock();
function render() {
controls.update();
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
// console.log("画面变化了");
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比
renderer.setPixelRatio(window.devicePixelRatio);
});
实现效果:
2.4 模型.castShadow属性
.castShadow属性值是布尔值,默认false,用来设置一个模型对象是否在光照下产生投影效果。具体查看threejs文档Object3D
// 设置产生投影的网格模型
mesh.castShadow = true;
2.5 .receiveShadow属性
.receiveShadow属性值是布尔值,默认false,用来设置一个模型对象是否在光照下接受其它模型的投影效果。具体查看threejs文档Object3D
// 设置网格模型planeMesh接收其它模型的阴影(planeMesh作为投影面使用)
planeMesh.receiveShadow = true;
2.6 光源.castShadow属性
如果属性设置为 true, 光源将投射动态阴影. 警告: 这需要很多计算资源,需要调整以使阴影看起来正确. 更多细节,查看DirectionalLightShadow. 默认值false.
// 设置用于计算阴影的光源对象
directionalLight.castShadow = true;
// spotLight.castShadow = true;
2.7 光源.shadow属性
平行光DirectionalLight的.shadow属性值是平行光阴影对象DirectionalLightShadow,聚光源SpotLight的.shadow属性值是聚光源阴影对象SpotLightShadow。关于DirectionalLightShadow和SpotLightShadow两个类的具体介绍可以参考Three.js文档Lights / Shadows分类.
2.8 阴影对象基类LightShadow
平行光阴影对象DirectionalLightShadow和聚光源阴影对象SpotLightShadow两个类的基类是LightShadow.
2.8.1 LightShadow属性.camera
观察光源的相机对象. 从光的角度来看,以相机对象的观察位置和方向来判断,其他物体背后的物体将处于阴影中。
// 聚光源设置
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 300;
spotLight.shadow.camera.fov = 20;
2.8.2 LightShadow属性.mapSize
定义阴影纹理贴图宽高尺寸的一个二维向量Vector2.
较高的值会以计算时间为代价提供更好的阴影质量. 宽高分量值必须是2的幂, 直到给定设备的WebGLRenderer.capabilities.maxTextureSize, 尽管宽度和高度不必相同 (例如,(512, 1024)是有效的). 默认值为 ( 512, 512 ).
directionalLight.shadow.mapSize.set(1024,1024)
2.8.3 LightShadow属性.map
该属性的值是WebGL渲染目标对象WebGLRenderTarget,使用内置摄像头生成的深度图; 超出像素深度的位置在阴影中。 在渲染期间内部计算。