BabylonJS-灯光及其颜色属性、阴影

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)

其中两种 漫反射镜面反射 光适用于所有四种类型的光,第三种 地面反射 光只适用于半球形光。

  1. diffuse(漫反射)为对象提供基本的颜色。
  2. specular(镜面反射)可以在模型对象上生成高亮颜色。
  3. 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)都能创建阴影

这样就生成一个简单的阴影了:

这里只做简单的阴影展示,可以去官网查看 阴影 示例深入学习阴影相关知识。

相关推荐
xw531 分钟前
npm几个实用命令
前端·npm
!win !36 分钟前
npm几个实用命令
前端·npm
代码狂想家40 分钟前
使用openEuler从零构建用户管理系统Web应用平台
前端
dorisrv2 小时前
优雅的React表单状态管理
前端
蓝瑟2 小时前
告别重复造轮子!业务组件多场景复用实战指南
前端·javascript·设计模式
dorisrv3 小时前
高性能的懒加载与无限滚动实现
前端
韭菜炒大葱3 小时前
别等了!用 Vue 3 让 AI 边想边说,字字蹦到你脸上
前端·vue.js·aigc
StarkCoder3 小时前
求求你,别在 Swift 协程开头写 guard let self = self 了!
前端
清妍_3 小时前
一文详解 Taro / 小程序 IntersectionObserver 参数
前端
电商API大数据接口开发Cris3 小时前
构建异步任务队列:高效批量化获取淘宝关键词搜索结果的实践
前端·数据挖掘·api