Three.js-灯光与阴影

目录

1.常见的光源类型

1.1 环境光(AmbientLight)

1.1.1 构造函数

1.1.2 属性

1.1.3 方法

1.1.4 环境光效果

1.2 平行光(DriectionalLight)

1.2.1 构造函数

1.2.2 属性

1.2.3 方法

1.2.4 平行光效果

1.3 点光源(PointLight)

1.3.1 构造函数

1.3.2 属性

1.3.3 点光源效果 

 1.4 聚光灯光源(SpotLight) 

1.4.1 构造函数

1.4.2 属性

1.4.3 聚光灯效果

2.阴影 

2.1 平行光投影计算代码

 2.2 聚光光源投影计算代码

2.3 点光源投影计算代码

 2.4 模型.castShadow属性

2.5 .receiveShadow属性

2.6 光源.castShadow属性

2.7 光源.shadow属性

2.8 阴影对象基类LightShadow

2.8.1 LightShadow属性.camera

2.8.2 LightShadow属性.mapSize

2.8.3 LightShadow属性.map


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,使用内置摄像头生成的深度图; 超出像素深度的位置在阴影中。 在渲染期间内部计算。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HM-hhxx!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值