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)都能创建阴影

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

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

相关推荐
IT_陈寒11 分钟前
Java并发编程实战:从入门到精通的5个关键技巧,让我薪资涨了40%
前端·人工智能·后端
全栈前端老曹12 分钟前
【包管理】read-pkg-up 快速上手教程 - 读取最近的 package.json 文件
前端·javascript·npm·node.js·json·nrm·package.json
程序员爱钓鱼38 分钟前
Node.js 编程实战:测试与调试 —— 调试技巧与性能分析
前端·后端·node.js
JQLvopkk41 分钟前
Vue框架技术详细介绍及阐述
前端·javascript·vue.js
vyuvyucd41 分钟前
插件式开发:C++与C#实战指南
java·前端·数据库
C_心欲无痕43 分钟前
ts - 类型收窄
前端·typescript
笔COOL创始人1 小时前
requestAnimationFrame 动画优化实践指南
前端·javascript·面试
sophie旭1 小时前
性能监控之首屏性能监控小实践
前端·javascript·性能优化
Amumu121381 小时前
React 前端请求
前端·react.js·okhttp
3824278272 小时前
JS表单提交:submit事件的关键技巧与注意事项
前端·javascript·okhttp