BabylonJS中有四种类型的灯,灯光的使用会影响网格在光照和颜色方面的可见性。所有网格都允许光线通过,除非激活阴影生成。默认允许的灯光数量为4但这是可以增加的。
一、点光源PointLight
点光源是由世界空间中的唯一点定义的光源。光从这一点向各个方向发射。标准灯泡就是点光源的一个很好的例子。
arduino
import {
Engine,
Scene,
UniversalCamera,
FreeCamera,
ArcRotateCamera,
FollowCamera,
AnaglyphUniversalCamera,
AnaglyphArcRotateCamera,
DeviceOrientationCamera,
Vector3,
MeshBuilder,
PointLight,
DirectionalLight,
SpotLight,
HemisphericLight,
Color3,
Mesh,
StandardMaterial,
ShadowGenerator,
} from '@babylonjs/core'
//创建一个名为 BabylonScene 的类
export class BabylonScene {
engine: Engine
scene: Scene
//private将属性或方法标记为私有,表示它们只能在类的内部被访问,外部无法直接访问。
constructor(private canvas: HTMLCanvasElement) {
this.engine = new Engine(this.canvas, true) //渲染引擎
this.scene = this.CreateScene() //场景
// 渲染场景
this.engine.runRenderLoop(() => {
this.scene.render()
})
}
CreateScene(): Scene {
const scene = new Scene(this.engine) // 创建场景
/**
* 弧形旋转摄像机ArcRotateCamera
* 配置项:相机名称,初始经度,初始纬度,与焦点距离,位置,场景
*/
const camera = new ArcRotateCamera(
'ArcRotateCamera',
Math.PI / 8,
Math.PI / 8,
10,
new Vector3(0, 0, 0),
scene
)
// 相机定位
camera.setPosition(new Vector3(0, 10, 10))
camera.attachControl(this.canvas, true) //让相机控制画布
/**
* 点光源PointLight
* 配置项:名称,位置,场景
*/
const light = new PointLight('pointLight', new Vector3(0, 1, 0), scene)
// 创建球形
const sphere = MeshBuilder.CreateSphere(
'sphere',
{ diameter: 2, segments: 32 },
scene
)
// 将球向上移动球高度的1/2
sphere.position.y = 1
sphere.position.x = 2
// 内置"地面"形状。
const ground = MeshBuilder.CreateGround(
'ground',
{ width: 6, height: 6 },
scene
)
return scene
}
}
二、平行光DirectionalLight
平行光是由一个方向来定义的,光从指定方向的任何地方发射出来,具有无限的范围。当模型被平行光照亮时,向下的光将照亮物体的顶部。
arduino
/**
* 平行光DirectionalLight
* 配置项:名称,位置,场景
*/
const light = new DirectionalLight("DirectionalLight", new Vector3(0, -1, 0), scene);
三、聚光灯SpotLight
聚光灯由位置、方向、角度和指数定义。这些值定义了一个从位置开始,向方向发射的光锥。
角度(以弧度表示)定义了聚光灯锥形光束的大小(照明范围),指数定义了光随距离衰减的速度(到达范围)。
arduino
/**
* 聚光灯SpotLight
* 配置项:名称,位置,方向,角度,指数,场景
*/
const light = new SpotLight(
'spotLight',
new Vector3(0, 10, 0),
new Vector3(0, -1, 0),
Math.PI / 4,
3,
scene
)
四、半球形光源HemisphericLight
半球形光是模拟周围环境光的一种简单方法。半球形的光是由一个方向来定义的,通常是朝向天空。然而,它是通过设置颜色属性来实现完整的效果。
arduino
/**
* 半球形光源HemisphericLight
* 配置项:名称,位置,场景
*/
const light = new HemisphericLight("HemiLight", new Vector3(0, 1, 0), scene);
五、颜色属性
影响颜色的光有三个属性:漫反射(diffuse) 、镜面反射(specular) 、地面反射(groundColor)。
其中两种 漫反射 和 镜面反射 光适用于所有四种类型的光,第三种 地面反射 光只适用于半球形光。
diffuse
(漫反射)为对象提供基本的颜色。specular
(镜面反射)可以在模型对象上生成高亮颜色。groundColor
(地面反射)照射方向刚好与设置的方向相反。就是说,半球光上的漫反射和镜面反射光的方向与地面反射的方向是相反的。
scss
/**
* 半球形光源HemisphericLight
* 配置项:名称,位置,场景
*/
const light = new HemisphericLight('HemiLight', new Vector3(0, 1, 0), scene)
light.diffuse = new Color3(1, 0, 0)//漫反射,red
light.specular = new Color3(0, 1, 0)//镜面反射,green
light.groundColor = new Color3(0, 0, 1)//地面反射,blue
相交光颜色
六、灯光限制
Babylon.js允许创建和注册任意数量的灯光,但要知道单个StandardMaterial只能处理定义数量的同时灯光(默认情况下,此值等于4,表示场景灯光列表的前四个启用灯光)。
ini
/**
* 聚光灯SpotLight
* 配置项:名称,位置,方向,角度,指数,场景
*/
const light = new SpotLight(
'spotLight',
new Vector3(0, 10, 0),
new Vector3(0, -1, 0),
Math.PI / 4,
3,
scene
)
const lightImpostor = new Mesh("sphere1", scene);
const lightImpostorMat = new StandardMaterial("mat", scene);
lightImpostorMat.maxSimultaneousLights = 6;
lightImpostor.material = lightImpostorMat;
lightImpostor.parent = light
但要小心!因为Babylon.js将生成更大的着色器,这可能不兼容手机或小型平板电脑等低端设备。在这种情况下,babylon.js将尝试使用较少的光源重新编译着色器。
但是这种方法扩大光源数量也是有限制的,最多为10个,这是webgl2本身的限制
解决:可以用disableUniformBuffers这个API,禁用统一缓冲区(这会给你更多的空间,但渲染可能会慢一点)
ini
//渲染引擎
const engine = new Engine(canvas, true)
//防止每个网格的灯光受到限制
engine.disableUniformBuffers = true;
七、开启关闭和调光
每盏灯都可以使用开启关闭和强度
属性(要调暗还是调亮灯光);
对于点光源和聚光灯,可以使用范围
属性设置光到达的距离
go
/**
* 聚光灯SpotLight
* 配置项:名称,位置,方向,角度,指数,场景
*/
const light = new SpotLight(
'spotLight',
new Vector3(0, 10, 0),
new Vector3(0, -1, 0),
Math.PI / 4,
3,
scene
)
//开启或关闭灯
light.setEnabled(true);
//强度属性,默认为1,要调暗还是调亮灯光
light.intensity = 0.5;
//范围属性,设置光到达的距离(对于点光源和聚光灯)
light.range = 100;
八、选择要点亮的网格
当一盏灯被创建时,所有当前的网格都将被它点亮,灯光只影响正面而不影响背面。有两种方法可以排除某些网格被点亮:
1.可以将一个网格添加到 excludedMeshes 数组
2.将不被排除的对象添加到 includedOnlyMeshes 数组中
要排除的网格数可以是决定使用哪种方法的一个因素。
arduino
/**
* 聚光灯SpotLight
* 配置项:名称,位置,方向,角度,指数,场景
*/
const light = new SpotLight(
'spotLight',
new Vector3(0, 10, 0),
new Vector3(0, -1, 0),
Math.PI / 4,
3,
scene
)
// 创建球形
const sphere = MeshBuilder.CreateSphere(
'sphere',
{ diameter: 2, segments: 32 },
scene
)
// 将球向上移动球高度的1/2
sphere.position.y = 1
sphere.position.x = 2
// 内置"地面"形状。
const ground = MeshBuilder.CreateGround(
'ground',
{ width: 6, height: 6 },
scene
)
light.excludedMeshes.push(sphere,ground);//排除的网格
light.includedOnlyMeshes.push(sphere,ground)//需要照亮的网格
九、阴影
生成阴影:ShadowGenerator
这个函数使用阴影贴图,从光的角度生成场景的贴图。
阴影生成器的两个参数是:阴影贴图的大小,用于阴影贴图计算的光源
在Babylon.js v3.1中引入了两个新的辅助函数来处理阴影投射器:
addShadowCaster(mesh, includeDescendants)
函数将网格及其后代添加到阴影投射器列表中removeShadowCaster(mesh, includeDescendants)
用于从阴影投射器列表中移除网格及其后代
arduino
/**
* 聚光灯SpotLight
* 配置项:名称,位置,方向,角度,指数,场景
*/
const light = new SpotLight(
'spotLight',
new Vector3(0, 10, 0),
new Vector3(1, -1, 0),
Math.PI / 2,
3,
scene
)
// 创建球形
const sphere = MeshBuilder.CreateSphere(
'sphere',
{ diameter: 0.5, segments: 32 },
scene
)
// 将球向上移动球高度的1/2
sphere.position.y = 1
sphere.position.x = 1
// 内置"地面"形状。
const ground = MeshBuilder.CreateGround(
'ground',
{ width: 6, height: 6 },
scene
)
//阴影生成器
const shadowGenerator = new ShadowGenerator(1024, light)
//定义哪些网格阴影将被渲染,你可以"推"任何你想要的网格
shadowGenerator.getShadowMap().renderList.push(sphere)
// shadowGenerator.addShadowCaster(sphere)
//地面接收阴影
ground.receiveShadows = true
shadowGenerator.getShadowMap().renderList.push(sphere)和shadowGenerator.addShadowCaster(sphere)都能创建阴影
这样就生成一个简单的阴影了:
这里只做简单的阴影展示,可以去官网查看 阴影 示例深入学习阴影相关知识。