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

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

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

相关推荐
qq_3643717244 分钟前
Vue 内置组件 keep-alive 中 LRU 缓存淘汰策略和实现
前端·vue.js·缓存
y先森2 小时前
CSS3中的弹性布局之侧轴的对齐方式
前端·css·css3
y先森7 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy7 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189117 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿8 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡9 小时前
commitlint校验git提交信息
前端
虾球xz9 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇9 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒9 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript