Part 1 Light介绍
1. Light概述
现实中,物体通常不会主动发出光线,而是通过接收光源照射,例如太阳光、月光,对光线进行反射、吸收等物理过程,最终形成我们看到的效果。
在三维渲染中,Light光照系统就是用于简化模拟现实世界中的光线效果,通过计算光线与物体表面的交互关系,生成最终画面上的像素颜色。
需要注意的是,三维场景中的可见性并不完全依赖Light,如果物体材质存在自发光Emissive可以不依靠外部官员直接产生颜色表现,但对于大多数情况而言,光照仍是影响视觉效果不可或缺的一部分。
在 Babylon 中,Light 光照是场景中的一种基础对象,用于向材质计算提供光照信息。它本身不会直接改变 Mesh 的几何结构,而是在渲染过程中影响物体材质Material的表现。
通常一个完整的三维渲染结果通常由多个因素共同决定:
最终画面
=
Mesh(几何结构) //描述物体的形状和空间结构;
+
Material(材质属性) //描述物体表面的颜色、粗糙度、金属度等;
+
Light(光照信息) //提供光照方向、光源颜色、光照强度等
+
Camera(观察角度) //决定最终观察的位置和角度等
因此,Light 并不是简单地增加场景亮度,而是参与三维场景中光线计算的重要组成部分。
不同类型的 Light与不同的光照配置,以及不同的材质,会直接影响最终渲染效果。
2. Light的作用
一个光源通常包含多个基本属性,例如位置、方向、颜色以及强度等,这些属性共同决定了光线如何作用于场景中的物体。
光源位置Position,确定光源产生的位置,但不同类型的Light对位置的依赖程度不同,例如PointLight、SpotLight具有明确的位置概念。
光源方向Direction,表示光线传播方向,DirectionalLight就是通过方向来模拟太阳光的平行光效果。
光源颜色Color,决定光线本身的颜色,它会参与颜色计算但不代表最终颜色,例如蓝色环境光会让整个场景产生冷色调。
光源强度Intensity,表示光照能量的大小,会影响场景的明暗程度,但不是绝对的,需要合理的材质参数、后处理效果等配合最终效果呈现。
Light
|
| 位置
| 方向
| 颜色
| 强度
↓
光照计算
↓
Normal + Material
↓
Mesh最终表现
物体本身材质也会直接影响光照效果,例如材质的金属感、粗糙度、透明度,以及材质自身的漫反射、高光等。
物体的法线Normal是很重要的概念,简单来说它表示物体表面某个点朝向的方向。
在进行光照计算时,需要比较光线方向、物体法线方向,当它们接近一致时说明光线正面照射物体,该区域会更亮。
反之,当光线方向与法线夹角较大时,受到的光照会减弱。
3. 小结
| position | 光源位置,确定光照产生的位置 |
| direction | 光照方向,影响哪些物体表面可以接收到光照 |
| diffuse | 光源颜色,会参与物体最终颜色计算 |
| intensity | 光照强度,会影响场景整体明亮效果 |
Part 2 Light基类与子类
1. Light抽象基类
在 Babylon 中,所有光源类型都继承自 Light 抽象基类。
Light基类定义了所有光源共有的基础能力,例如是否启用、光源颜色、光照强度等。
Light不能直接被实例化,它本身只是所有光源的抽象定义,实际使用需要创建它的子类。
const light = new BABYLON.Light(
name: string, //必填项
scene?: Sene //非必填
);
2. ShadowLight抽象类
ShadowLight 是 Babylon 中支持阴影计算的抽象类,它继承自Light基类。
它在Light基础上增加了光源方向、阴影投射能力与相关计算能力。
ShadowLight不能直接实例化,它主要承担阴影光源的公共能力抽象,实际使用需要创建它的子类。
3. HemisphericLight类
HemisphericLight是Babylon中一种特殊的光源类型,用于模拟环境光效果,它继承自Light基类。
与其他光源不同,它模拟现实环境中来自天空和地面的散射光,它不继承ShadowLight。
const light = new BABYLON.HemisphericLight(
name: string, //必填项
direction: Vector3, //必填项,光照方向
scene?: Scene //非必填
);
-
HemisphericLight没有产生阴影的能力,更适合作为场景基础补光;
-
HemisphericLight可以通过 diffuse 设置天空方向光颜色,通过 groundColor 设置地面反射光颜色;
-
direction 用于控制上下两个半球光照方向,通常设置为 (0,1,0) 表示来自天空方向的环境光。
4. DirectionalLight类
DirectionalLight是Babylon最常用的光源之一,用于模拟类似太阳光的平行光,它继承自ShadowLight类。
它光照效果主要由光线方向决定,而不是由光源位置决定,简单地说,我们只需要定义光线传播方向,而无需关心光源位置。
const light = new BABYLON.DirectionalLight(
name: string, //必填项
direction: Vector3, //必填项,光照方向
scene?: Scene //非必填
);
-
DirectionalLight不存在距离衰减,理论上它可以照亮整个Scene,适用于大范围场景以及室外环境;
-
DirectionalLight的Position主要对阴影计算产生影响,不会影响其光照范围;
5. PointLight类
PointLight用于模拟点光源,例如灯泡、蜡烛等,它继承自ShadowLight类。
PointLight 的光线从一个固定空间位置向四周发散,因此光照效果主要受到光源位置和距离影响。
const light = new BABYLON.PointLight(
name: string, // 必填项
position: Vector3, // 必填项,光源位置
scene?: Scene // 非必填
);
-
PointLight会随着距离增加产生光照衰减,适用于室内灯光等局部照明场景;
6. SpotLight类
SpotLight是用于模拟聚光灯效果的光源类型,例如手电筒、舞台灯等,它继承自ShadowLight类。
它同时具备位置和方向两个属性,通过限制光照范围形成锥形照射区域。
const light = new BABYLON.SpotLight(
name: string, // 必填项
position: Vector3, // 必填项,光源位置
direction: Vector3, // 必填项,光照方向
angle: number, //必填项,聚光范围
exponent: number, //必填项,光照集中程度
scene?: Scene // 非必填
);
7. AreaLight抽象类
AreaLight 是 Babylon 中用于表示区域光源的抽象类,它继承自Light基类。
它在Light基础上定义了区域光源共有的基础能力。
AreaLight不能直接实例化,它主要承担区域光源的公共能力抽象,实际使用需要创建它的子类。
8. RectAreaLight类
RectAreaLight是 Babylon 中用于模拟矩形区域光源的光源类型,它继承自 AreaLight类。
与点光源不同,RectAreaLight的发光源是一个具有宽度和高度的矩形区域。
const light = new BABYLON.RectAreaLight(
name: string, // 必填项
position: Vector3, // 必填项,光源位置
width: number, // 必填项,光源宽度
height: number, // 必填项,光源高度
scene?: Scene // 非必填
);
-
RectAreaLight 通过 width 和 height 控制光源区域大小,更适合模拟真实室内照明效果;
9. 小结
抽象类(不能直接实例化):
| Light | extends Node | 所有光源的基础定义 |
| ShadowLight | extends Light | 在Light基础上增加阴影相关能力 |
| AreaLight | extends Light | 在Light基础上定义区域光源基础能力 |
子类:
| HemisphericLight | extends Light | 模拟天空与地面产生的环境光,不依赖光源位置,不支持阴影,适合作为场景基础补光 |
| DirectionalLight | extends ShadowLight | 模拟平行光,不存在距离衰减,光照效果主要由方向决定,支持阴影,适合作为室外场景主光源 |
| PointLight | extends ShadowLight | 模拟点光源,受距离影响产生衰减,光照效果主要由位置决定,支持阴影,适合作为室内局部照明 |
| SpotLight | extends ShadowLight | 模拟聚光灯,通过位置、方向、角度形成锥形光照区域,支持阴影,适合作为重点区域照明 |
| RectAreaLight | extends AreaLight | 模拟矩形区域光,通过一定面积发射光线,不支持阴影,照明效果更柔和,适合作为室内灯光 |
Part 3 Light实例成员
1. Light基类成员
name、id、uniqueId、parent、metadata等来自于Node类,这里不再汇总。
| diffuse | Color3 | 光源颜色,用于定义光线本身的颜色 |
| specular | Color3 | 光源高光颜色,用于影响物体表面的高光效果 |
| falloffType | number | 光照衰减计算类型,用于控制光照随距离变化的计算方式 |
| intensity | number | 光照强度,用于控制光源的亮度 |
| range | number | 光照影响范围,用于限制光源能够影响的空间距离 |
| intensityMode | number | 光照强度计算模式,用于指定强度的计算方式 |
| radius | number | 光源半径,用于部分光源类型模拟光源尺寸 |
| shadowEnabled | boolean | 是否启用该光源的阴影计算 |
| includedOnlyMeshes | AbstractMesh[] | 指定该光源仅影响的 Mesh 列表 |
| excludedMeshes | AbstractMesh[] | 指定该光源排除影响的 Mesh 列表 |
| excludeWithLayerMask | number | 根据 LayerMask 排除受该光源影响的对象 |
| includeOnlyWithLayerMask | number | 根据 LayerMask 指定受该光源影响的对象 |
| lightmapMode | number | 光照贴图计算模式,用于控制 Light 与 Lightmap 的结合方式 |
| getViewMatrix(_faceIndex?: number) | Nullable<Matrix> | 获取光源视图矩阵,主要用于光照空间转换和阴影计算 |
| getProjectionMatrix(_viewMatrix?: Matrix, _renderList?: Array<AbstractMesh>) | Nullable<Matrix> | 获取光源投影矩阵,主要用于阴影投影计算 |
| transferTexturesToEffect(effect: Effect, lightIndex: string) | Light | 将光源相关数据传递给 Shader Effect,用于渲染计算 |
| getClassName() | string | 获取当前 Light 类型名称 |
| toString(fullDetails?: boolean) | string | 返回 Light 的字符串描述信息 |
| setEnabled(value: boolean) | void | 设置光源是否启用 |
| getShadowGenerator(camera?: Nullable<Camera>) | IShadowGenerator | null | 获取当前光源关联的阴影生成器 |
| getShadowGenerators() | Map<Camera | null, IShadowGenerator> | null | 获取当前光源关联的所有阴影生成器 |
| getAbsolutePosition() | Vector3 | 获取光源在世界空间中的绝对位置 |
| canAffectMesh(mesh: AbstractMesh) | boolean | 判断当前光源是否会影响指定 Mesh |
| dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean) | void | 释放 Light 占用的资源 |
| getTypeID() | number | 获取当前 Light 类型 ID |
| getScaledIntensity() | number | 获取经过强度模式计算后的实际光照强度 |
| clone(name: string, newParent?: Nullable<Node>) | Light | null | 克隆当前 Light,并可以指定新的名称和父节点 |
| serialize() | any | 将 Light 序列化为可保存的数据结构 |
2. ShadowLight类成员
ShadowLight继承自Light基类,所以它拥有Light基类的所有成员。
| position | Vector3 | 光源在世界空间中的位置,用于确定光源空间位置以及阴影计算 |
| direction | Vector3 | 光线传播方向,用于确定光照方向以及阴影投射方向 |
| shadowMinZ | number | 阴影投影近裁剪距离,用于控制阴影摄像机的近裁剪范围 |
| shadowMaxZ | number | 阴影投影远裁剪距离,用于控制阴影摄像机的远裁剪范围 |
| customProjectionMatrixBuilder | (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) | 自定义阴影投影矩阵计算函数,用于覆盖默认的投影矩阵计算逻辑 |
| transformedPosition | Vector3 | 经过变换后的光源位置,用于光照计算 |
| transformedDirection | Vector3 | 经过变换后的光照方向,用于光照计算 |
| computeTransformedInformation() | boolean | 计算光源变换后的位置信息和方向信息 |
| getDepthScale() | number | 获取阴影深度缩放比例,用于阴影深度计算 |
| getShadowDirection(faceIndex?: number) | Vector3 | 获取指定面的阴影投射方向,主要用于阴影计算 |
| getAbsolutePosition() | Vector3 | 获取光源在世界空间中的绝对位置 |
| setDirectionToTarget(target: Vector3) | Vector3 | 根据目标位置设置光照方向 |
| getRotation() | Vector3 | 获取光源当前旋转角度 |
| needCube() | boolean | 判断当前光源是否需要使用立方体阴影贴图,主要用于点光源 |
| needProjectionMatrixCompute() | boolean | 判断是否需要重新计算阴影投影矩阵 |
| forceProjectionMatrixCompute() | void | 强制下一次渲染时重新计算投影矩阵 |
| computeWorldMatrix(force?: boolean) | Matrix | 计算并获取光源世界矩阵 |
| getDepthMinZ(activeCamera: Nullable<Camera>) | number | 根据当前摄像机获取阴影深度计算的最小范围 |
| getDepthMaxZ(activeCamera: Nullable<Camera>) | number | 根据当前摄像机获取阴影深度计算的最大范围 |
| setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>) | IShadowLight | 设置阴影投影矩阵,用于自定义阴影空间计算 |
| getViewMatrix(faceIndex?: number) | Matrix | null | 获取光源视图矩阵,将世界空间转换到光源观察空间,用于阴影计算 |
| getProjectionMatrix(viewMatrix?: Matrix, renderList?: Array<AbstractMesh>) | Matrix | null | 获取光源投影矩阵,将光源空间映射到裁剪空间,用于生成 ShadowMap |
3. HemisphericLight类成员
HemisphericLight继承自Light基类,所以它拥有Light基类的所有成员。
| groundColor | Color3 | 地面方向光照颜色,用于模拟来自地面的环境反射光 |
| direction | Vector3 | 光照方向,用于确定天空方向的光照来源 |
| getClassName() | string | 获取当前 Light 类型名称 |
| setDirectionToTarget(target: Vector3) | Vector3 | 根据目标位置设置光照方向 |
| getShadowGenerator() | IShadowGenerator | null | 获取阴影生成器,由于 HemisphericLight 不支持阴影,通常返回 null |
| transferToEffect(_effect: Effect, lightIndex: string) | HemisphericLight | 将当前光源数据传递到 Shader Effect,用于渲染计算 |
| transferToNodeMaterialEffect(effect: Effect, lightDataUniformName: string) | HemisphericLight | 将当前光源数据传递给 Node Material 使用的 Shader Effect |
| computeWorldMatrix() | Matrix | 计算并获取光源世界矩阵 |
| getTypeID() | number | 获取当前 Light 类型 ID |
| prepareLightSpecificDefines(defines: any, lightIndex: number) | void | 准备当前光源类型对应的 Shader 宏定义,用于渲染时区分光源类型 |
4. DirectionalLight类成员
DirectionalLight继承自ShadowLight类,所以它拥有ShadowLight类的所有成员。
| shadowFrustumSize | number | 阴影视锥体大小,用于控制方向光阴影覆盖范围 |
| shadowOrthoScale | number | 正交阴影投影缩放比例,用于调整阴影投影范围 |
| autoUpdateExtends | boolean | 是否根据受影响 Mesh 自动更新阴影投影范围 |
| autoCalcShadowZBounds | boolean | 是否自动计算阴影深度范围,用于优化阴影裁剪区域 |
| orthoLeft | number | 阴影正交投影区域左侧边界 |
| orthoRight | number | 阴影正交投影区域右侧边界 |
| orthoTop | number | 阴影正交投影区域顶部边界 |
| orthoBottom | number | 阴影正交投影区域底部边界 |
| getClassName() | string | 获取当前 Light 类型名称 |
| getTypeID() | number | 获取当前 Light 类型 ID |
| transferToEffect(effect: Effect, lightIndex: string) | DirectionalLight | 将当前方向光数据传递给 Shader Effect,用于渲染计算 |
| transferToNodeMaterialEffect(effect: Effect, lightDataUniformName: string) | Light | 将当前方向光数据传递给 Node Material 使用的 Shader Effect |
| prepareLightSpecificDefines(defines: any, lightIndex: number) | void | 准备方向光对应的 Shader 宏定义,用于渲染时区分光源类型 |
5. PointLight类成员
PointLight继承自ShadowLight类,所以它拥有ShadowLight类的所有成员。
| shadowAngle | number | 阴影投射角度,用于控制点光源阴影计算范围 |
| direction | Vector3 | 光照方向,用于部分光照计算场景下的方向控制 |
| getClassName() | string | 获取当前 Light 类型名称 |
| getTypeID() | number | 获取当前 Light 类型 ID |
| needCube() | boolean | 判断当前光源是否需要使用立方体阴影贴图,点光源由于向四周发射光线,返回 true |
| getShadowDirection(faceIndex?: number) | Vector3 | 获取指定阴影面对应的光照方向,用于点光源六面体阴影计算 |
| transferToEffect(effect: Effect, lightIndex: string) | PointLight | 将当前点光源数据传递给 Shader Effect,用于渲染计算 |
| transferToNodeMaterialEffect(effect: Effect, lightDataUniformName: string) | PointLight | 将当前点光源数据传递给 Node Material 使用的 Shader Effect |
| prepareLightSpecificDefines(defines: any, lightIndex: number) | void | 准备点光源对应的 Shader 宏定义,用于渲染时区分光源类型 |
6. SpotLight类成员
SpotLight继承自ShadowLight类,所以它拥有ShadowLight类的所有成员。
| iesProfileTexture | BaseTexture | null | IES 光照分布纹理,用于加载真实灯具的光照分布数据 |
| angle | number | 聚光灯照射角度,用于控制光锥范围大小 |
| innerAngle | number | 聚光灯内部照射角度,用于控制中心区域的光照范围 |
| shadowAngleScale | number | 阴影角度缩放比例,用于调整阴影投射范围 |
| exponent | number | 光照衰减指数,用于控制光线从中心向边缘的集中程度 |
| projectionTextureMatrix | Matrix | 投影纹理矩阵,用于计算投影纹理坐标 |
| projectionTextureLightNear | number | 投影纹理光源近裁剪距离 |
| projectionTextureLightFar | number | 投影纹理光源远裁剪距离 |
| projectionTextureUpDirection | Vector3 | 投影纹理计算时使用的向上方向 |
| projectionTexture | BaseTexture | null | 投影纹理,用于将纹理投射到受光物体上 |
| projectionTextureProjectionLightMatrix | Matrix | 投影纹理对应的光源投影矩阵 |
| getClassName() | string | 获取当前 Light 类型名称 |
| getTypeID() | number | 获取当前 Light 类型 ID |
| transferToEffect(effect: Effect, lightIndex: string) | SpotLight | 将当前聚光灯数据传递给 Shader Effect,用于渲染计算 |
| transferToNodeMaterialEffect(effect: Effect, lightDataUniformName: string) | SpotLight | 将当前聚光灯数据传递给 Node Material 使用的 Shader Effect |
| dispose() | void | 释放 SpotLight 占用的资源 |
| prepareLightSpecificDefines(defines: any, lightIndex: number | void | 准备聚光灯对应的 Shader 宏定义,用于渲染时区分光源类型 |
7. AreaLight类成员
AreaLight继承自Light基类,所以它拥有Light基类的所有成员。
| position | Vector3 | 区域光源在世界空间中的位置,用于确定光源所在空间位置 |
| transferTexturesToEffect(effect: Effect) | Light | 将区域光源相关纹理数据传递给 Shader Effect,用于渲染计算 |
| prepareLightSpecificDefines(defines: any, lightIndex: number) | void | 准备区域光源对应的 Shader 宏定义,用于渲染时区分光源类型 |
8. RectAreaLight类成员
RectAreaLight继承自AreaLight类,所以它拥有RectAreaLight类的所有成员。
| width | number | 矩形区域光源的宽度 |
| height | number | 矩形区域光源的高度 |
| getClassName() | string | 获取当前 Light 类型名称 |
| getTypeID() | number | 获取当前 Light 类型 ID |
| transferToEffect(effect: Effect, lightIndex: string) | RectAreaLight | 将当前区域光源数据传递给 Shader Effect,用于渲染计算 |
| ransferToNodeMaterialEffect(effect: Effect, lightDataUniformName: string) | RectAreaLight | 将当前区域光源数据传递给 Node Material 使用的 Shader Effect |
Part 4 Shadow系统
1. Shadow概述
阴影Shadow用于模拟光线被物体遮挡后产生的暗部区域。
在Babylon中Shadow 并不是由Light单独完成的,而是通过Light、ShadowGenerator 以及ShadowMap共同实现。
支持阴影的光源均继承自ShadowLight抽象类:
Light
|
+– ShadowLight
|
+– DirectionalLight
+– PointLight
+– SpotLight
2. ShadowGenerator类
阴影生成器ShadowGenerator是 Babylon 中负责管理阴影的核心对象,它不负责光源,而是生成阴影的管理器。
ShadowGenerator通过绑定支持Shadow的Light对象,根据Light的光源位置Position、光源方向Direction、光照范围Range等信息,判断哪些位置该生成阴影。
同时,ShadowGenerator还负责管理哪些Mesh可以产生阴影并配置阴影效果,生成深度纹理ShadowMap,将数据传递给接收阴影的物体,使其参与最终颜色效果的计算。
new ShadowGenerator(
mapSize: number, //必填项,阴影贴图的分辨率
light: IShadowLight, //必填项,用于生成阴影的光源对象
usefullFloatFirst?: boolean, //可选,是否优先使用完整浮点纹理存储 ShadowMap 数,可提高阴影深度精度
camera?: Nullable<Camera>, //可选,指定使用的 Camera
useRedTextureType?: boolean, //可选,是否使用单通道红色纹理格式存储 ShadowMap 数据,控制ShadowMap 的纹理格式
forceGLSL?: boolean //可选,是否强制使用 GLSL Shader,主要用于兼容性控制
)
ShadowGenerator的阴影管理,主要对阴影产生物体ShadowCaster进行管理,它表示能够遮挡光线并产生阴影的 Mesh。
Mesh需开启receiveShadows能力使自身成为阴影接收物体ShadowReceiver。
阴影效果的呈现以上两者缺一不可,如果没有产生阴影的物体,即时配置接收阴影的物体也没有效果;如果没有接收阴影的物体,即时全部物体可以产生阴影也不会有效果。
3. ShadowGenerator类成员
| id | string | 唯一标识名称 |
| customShaderOptions | ICustomShaderOptions | 自定义阴影 Shader 配置项,用于扩展阴影渲染逻辑 |
| customAllowRendering | (subMesh: SubMesh) => boolean | 自定义判断 SubMesh 是否参与阴影渲染的函数 |
| bias | number | 阴影偏移量,用于减少 ShadowMap 深度比较误差导致的阴影痤疮问题 |
| normalBias | number | 基于物体法线方向的阴影偏移,用于进一步改善阴影边缘错误 |
| blurBoxOffset | number | 阴影模糊采样范围偏移,用于控制模糊效果 |
| blurScale | number | 阴影模糊缩放比例,用于调整模糊范围 |
| blurKernel | number | 阴影模糊采样核大小,用于控制阴影柔化程度 |
| useKernelBlur | boolean | 是否启用 Kernel Blur 模糊算法 |
| depthScale | number | 深度计算缩放比例,用于调整阴影深度精度 |
| filter | number | 阴影过滤方式,用于选择不同 ShadowMap 采样算法 |
| usePoissonSampling | boolean | 是否使用 Poisson 采样优化阴影边缘效果 |
| useExponentialShadowMap | boolean | 是否启用指数阴影贴图ESM算法 |
| useBlurExponentialShadowMap | boolean | 是否启用带模糊处理的指数阴影贴图 |
| useCloseExponentialShadowMap | boolean | 是否启用近距离优化的指数阴影贴图 |
| useBlurCloseExponentialShadowMap | boolean | 是否启用带模糊处理的近距离指数阴影贴图 |
| usePercentageCloserFiltering | boolean | 是否启用 PCF阴影过滤,使阴影边缘更加平滑 |
| filteringQuality | number | 阴影过滤质量级别,用于控制 PCF 等过滤效果质量 |
| useContactHardeningShadow | boolean | 是否启用接触硬化阴影,使阴影根据距离产生软硬变化 |
| contactHardeningLightSizeUVRatio | number | 接触硬化阴影中光源尺寸与 UV 比例,用于控制软阴影范围 |
| darkness | number | 阴影黑暗程度,控制阴影区域的暗度 |
| transparencyShadow | boolean | 是否支持透明物体产生透明阴影 |
| enableSoftTransparentShadow | boolean | 是否启用透明物体的柔和阴影效果 |
| useOpacityTextureForTransparentShadow | boolean | 是否使用透明贴图参与透明阴影计算 |
| frustumEdgeFalloff | number | 阴影视锥边缘衰减范围,用于减少阴影边缘突然消失的问题 |
| forceBackFacesOnly | boolean | 是否强制仅使用 Mesh 背面生成阴影,用于减少阴影偏差问题 |
| mapSize | number | ShadowMap尺寸大小,决定阴影贴图分辨率和阴影精度 |
| getDarkness() | number | 获取当前阴影黑暗程度 |
| setDarkness(darkness: number) | ShadowGenerator | 设置阴影黑暗程度 |
| setTransparencyShadow(transparent: boolean) | ShadowGenerator | 设置是否启用透明阴影 |
| getShadowMap() | RenderTargetTexture | null | 获取用于保存阴影信息的 ShadowMap 纹理 |
| getShadowMapForRendering() | RenderTargetTexture | null | 获取当前用于渲染流程中的 ShadowMap |
| getClassName() | string | 获取当前对象类型名称 |
| addShadowCaster(mesh: AbstractMesh, includeDescendants?: boolean) | ShadowGenerator | 添加产生阴影的 Mesh |
| removeShadowCaster(mesh: AbstractMesh, includeDescendants?: boolean) | ShadowGenerator | 移除产生阴影的 Mesh |
| getLight() | IShadowLight | 获取当前绑定的光源 |
| forceCompilation(onCompiled?: (generator: IShadowGenerator) => void, options?: Partial<{ useInstances: boolean; }>) | void | 强制编译阴影相关 Shader |
| forceCompilationAsync(options?: Partial<{ useInstances: boolean; }>) | Promise<void> | 异步编译阴影 Shader |
| isReady(subMesh: SubMesh, useInstances: boolean, isTransparent: boolean) | boolean | 判断指定 SubMesh 是否已经准备好进行阴影渲染 |
| prepareDefines(defines: any, lightIndex: number) | void | 准备阴影相关 Shader 宏定义 |
| bindShadowLight(lightIndex: string, effect: Effect) | void | 将阴影光源数据绑定到 Shader Effect |
| viewMatrix() | Matrix | 获取阴影计算使用的光源视图矩阵 |
| projectionMatrix() | Matrix | 获取阴影计算使用的光源投影矩阵 |
| getTransformMatrix() | Matrix | 获取阴影变换矩阵,用于将世界坐标转换到 ShadowMap 空间 |
| recreateShadowMap() | void | 重新创建 ShadowMap |
| dispose() | void | 释放 ShadowGenerator 相关资源 |
| serialize() | any | 将 ShadowGenerator 序列化为可保存的数据结构 |
ICustomShaderOptions的配置内容包括:
| shaderName | string | Shader 名称,用于标识当前自定义 Shader,Babylon 会根据该名称查找对应的 Vertex Shader 与 Fragment Shader 源码 |
| attributes | string[] | undefined | 定义 Vertex Shader 使用的顶点属性名称,用于声明需要从 Geometry 顶点缓冲区读取的数据 |
| uniforms | string[] | undefined | 定义 Shader 使用的全局变量名称,用于传递 CPU 侧数据到 GPU |
| samplers | string[] | undefined | 定义 Shader 使用的纹理采样器名称,用于声明需要绑定到 Shader 中的纹理资源 |
| defines | string[] | undefined | 定义 Shader 编译时的宏条件,用于控制 Shader 编译逻辑,实现不同功能分支或优化 |
4. 从三维世界到屏幕的过程
在Camera篇中讲到,一个物体最终呈现在屏幕的位置,由物体的世界坐标通过视图矩阵Camera View Matrix再到投影矩阵Camera Projection Matrix转换而来。
简单的说,一个物体最终在屏幕中的位置,由Camera的矩阵变换决定。
那么物体最终在屏幕上的呈现效果呢?
物体最终的视觉效果由Light光照计算、Material材质计算、Shadow阴影计算、PostProcess后处理效果共同决定,其中:
-
Light 决定物体受到的光照强弱以及明暗关系;
-
Material 决定物体表面的颜色、金属度、粗糙度、纹理等材质表现;
-
Shadow 根据光源遮挡关系计算阴影区域,对光照结果进行衰减;
-
PostProcess 对最终渲染结果进行屏幕后处理;
这里我们不对Material材质计算与PostProcess后处理效果进行深入说明,后续单独篇章中会讲到。
Light 光照计算通过光源参数与物体表面法线的关系,计算物体表面受到的光照贡献,从而决定物体的明暗和光照效果。
光照计算是计算光源颜色、光照强度以及物体法线与光照方向的过程,它决定的是物体表面的明暗效果。
简单来讲,它只负责描述物体表面哪部分更亮,哪部分更暗。
Shadow阴影计算则稍微复杂,在较大的场景中也会带来明显的性能开销。
首先ShadowGenerator基于它所绑定的Light,通过光源视图矩阵Light View Matrix和光源投影矩阵Light Projection Matrix建立光源空间。
光源视图矩阵Light View Matrix负责将世界空间中的物体转换到 Light 的观察空间。
光源投影矩阵Light Projection Matrix将光源观察空间中的坐标转换到 ShadowMap 使用的二维空间。
建立光源空间后ShadowGenerator会生成对应的ShadowMap,它本质上是一张特殊的深度纹理,不保存颜色信息,而是从光源角度记录每个位置距离光源的关系。
Shader计算时,会根据ShadowMap的深度信息,对Light光照计算结果进行衰减,综合Material材质计算与PostProcess后处理效果计算最终的呈现效果。
Part 5 Light常用功能
1. HemisphericLight场景基础补光
HemisphericLight不依赖光源位置,通常作为作为场景环境补光。
常用配置项包括:
| direction | Vector3 | 决定天空光照射方向,通常(0, 1, 0)表示从上方向下照射 |
| diffuse | Color3 | 设置天空光颜色 |
| groundColor | Color3 | 设置地面反射光颜色 |
| intensity | number | 设置光照强度 |
-
HemisphericLight无法产生阴影,不能作为ShadowGenerator的阴影光源;
-
intensity通常作为基础环境光,不建议设置过强;
2. DirectionalLight场景主光源
DirectionalLight光线方向固定且不会随着距离产生衰减,通常作为场景中的主光源。
常用配置项包括:
| direction | Vector3 | 设置光照方向,决定光线从哪个方向照射场景 |
| position | Vector3 | 设置光源位置,由于它不会随距离产生衰减,因此主要用于阴影计算 |
| diffuse | Color3 | 设置直射光颜色 |
| specular | Color3 | 设置地高光反射颜色 |
| intensity | number | 设置光照强度 |
-
DirectionalLight支持ShadowGenerator生成阴影,是三维场景中最常用的阴影光源类型;
-
intensity避免过高导致场景过曝,实际使用中建议配合HemisphericLight进行调整;
3. ShadowGenerator生成阴影
ShadowGenerator用于根据光源与场景物体之间的遮挡关系生成阴影效果,在较大场景中一般是主要的性能瓶颈之一。
常用配置包括:
| mapSize | number | 设置阴影贴图分辨率,越高越清晰 |
| bias | number | 设置阴影偏移量,用于解决阴影自遮挡产生的阴影痤疮 |
| normalBias | number | 根据表面法线方向调整阴影偏移,减少斜面阴影异常问题 |
| filter | number | 设置阴影过滤方式,用于优化阴影边缘效果 |
| usePercentageCloserFiltering | boolean | 开启PCF阴影过滤,使阴影边缘更加平滑 |
| darkness | number | 设置阴影黑暗程度,控制阴影区域的透明效果 |
| blurScale | number | 设置阴影模糊强度,用于改善硬阴影边缘效果 |
| addShadowCaster(mesh: AbstractMesh, includeDescendants?: boolean) | ShadowGenerator | 添加产生阴影的 Mesh |
| removeShadowCaster(mesh: AbstractMesh, includeDescendants?: boolean) | ShadowGenerator | 移除产生阴影的 Mesh |
-
要开启阴影效果,首先依赖于支持阴影的光照Light及其合理配置,HemisphericLight与RectAreaLight不支持阴影;
-
生成阴影首先要创建ShadowGenerator实例,并通过addShadowCaster设置产生阴影的Mesh;
-
需要有开启了receiveShadows的Mesh作为阴影接收者,才能看见阴影效果;
总之,要实现阴影效果,ShadowLight光照、ShadowCaster阴影生成者、ShadowReceiver阴影接收者三者的配置缺一不可;
-
mapSize过高会增加GPU压力,在大型三维场景中需要平衡性能与效果;
-
开启阴影会增加额外渲染开销,需要避免将大量Mesh加入ShadowCaster中;
Part 6 踩坑记录
1. 阴影配置不生效
-
首先检查是否正确创建支持阴影的光源,且是否在正确的Scene中;
-
检查全局配置scene.lightsEnabled与scene.shadowsEnabled是否为开启状态;
-
检查是否在对应的Scene场景中创建ShadowGenerator,并添加addShadowCaster列表是否正确添加Mesh或是否为空;
-
检查是否对需要接收阴影的Mesh配置了receiveShadows = true;
-
检查光照的方向、强度是否合理,避免光照未覆盖目标区域导致无法观察阴影;
-
检查接收阴影的Mesh是否在阴影投射范围;
2. 阴影边缘出现条纹、闪烁或黑色噪点
-
首先确认问题是否由 ShadowGenerator 引起,可以临时关闭阴影进行对比;
-
检查 ShadowGenerator.bias 是否过小,导致模型自身深度比较产生误判;
-
检查 normalBias 是否需要调整,尤其是建筑、地面等大面积倾斜模型;
-
检查 ShadowMap 的mapSize分辨率是否过低,低分辨率可能导致阴影精度不足:
3. Light与Shadow性能调优
-
首先场景中的Light数量不宜过多,尤其避免大量PointLight、SpotLight参与实时光照计算;
-
检查ShadowGenerator的mapSize是否合理,过大的ShadowMap会增加GPU显存占用和渲染压力;
-
检查ShadowGenerator中添加的ShadowCaster数量是否过多,避免将所有Mesh加入阴影计算;
-
检查ShadowGenerator的阴影过滤方式,例如usePercentageCloserFiltering、useContactHardeningShadow等,高质量过滤会增加额外计算成本;
-
检查ShadowGenerator的bias、normalBias设置,避免为了修复阴影痤疮问题过度增加偏移导致阴影质量下降;
-
检查ShadowGenerator的filter类型选择,根据场景需求选择PCF、PCF Soft、ESM等阴影算法;
-
检查阴影范围是否合理,避免Shadow Camera覆盖过大的无效区域导致阴影精度下降;
-
检查是否存在大量透明模型参与阴影计算,避免产生额外Shadow Pass开销;
总结
Light 是 Babylon 中负责模拟真实世界光照效果的核心模块,它决定了场景中物体如何受到光线影响,是连接三维空间、材质表现以及最终视觉效果的重要组成部分。虽然Light本身的API结构相对简单,但其背后涉及光照计算、法线、材质响应、阴影生成以及GPU渲染流程等多个三维核心概念,在实际项目中也是最容易影响场景表现和性能的模块之一。
本文主要整理了 Light 的基础概念、不同类型光源、光照计算流程、常用配置、ShadowGenerator 阴影机制以及实际开发过程中遇到的常见问题与性能调优方案。希望通过 API 梳理与项目实践结合的方式,帮助开发者不仅了解不同光源的使用方式,也能够理解 Light 与 Shadow 在最终渲染效果中的作用关系,以及遇到光照异常时的排查思路。
在实际三维项目中,Light 并不是简单的“增加亮度”,而是需要根据场景规模、模型数量以及展示需求合理组合使用。通常通过环境补光、主光源以及必要的阴影效果共同构建场景光照,同时结合性能优化避免过多光源和阴影计算带来的额外开销。
后续会继续整理 Babylon.js 8.x 其他核心模块。

