【babylonjs】环形屏幕3d展示

本文介绍了如何使用Babylon.js开发一款能在环形屏幕上运行的3D项目,通过AnnularCamera类,通过多个相机组合解决360°视角限制,详细讲解了相机设置、构造过程和关键API的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0.前言:

前阵子接到一个需求是需要开发一个能够跑在环形屏幕上的3d展示项目

刚接到这个项目的时候我以为能吧相机fov直接调整成360°,后来发现我想多了。。babylonjs中的相机最大视角就是π(180°)

然后我又想说,那我干脆两个相机拼一起。

但是两个相机边缘会有失真,效果不好效果不好。

算了 暴力一点,我写了个全景相机类,想用几个相机拼接用几个相机,相机数量越多拼接的越丝滑,移动的话利用主相机的控制器进行移动,其他副相机都绑在这个相机身上。

(本文完整代码连接如下,为ts编写,需要js移步ts官网的playground编译成自己需要的版本)

AnnularCamera.tshttps://gitee.com/Susiia/babylon-standard-framework/blob/master/src/assets/ts/tools/AnnularCamera.ts


1.使用方法:

首先导入

import AnnularCamera from "./AnnularCamera.ts";

然后使用

  // 默认相机
  private defaultCamera ():void {
    this.camera = new AnnularCamera('defaultCamera', new Vector3(0, 2, -2), this.scene)
    this.camera.ellipsoid = new Vector3(0.15, 0.9, 0.15)
    this.camera.speed = 0.2
    this.camera.checkCollisions = true
    this.camera.applyGravity = true
    this.camera.attachControl(this.canvas, true)
  }

齐活儿


2.代码讲解

首先导入我们需要的东西

import { Scene, UniversalCamera, Vector3, Viewport } from '@babylonjs/core'

创建AnnularCamera类

export default class AnnularCamera {
    constructor (
        name:string, // 相机名
        position:Vector3, // 位置
        scene:Scene, // 场景
        CameraCount?:number // 相机数量
    ){
        //...
    }
}

声明所需要的私有变量

  private _name: string // 相机名
  private readonly scene:Scene // 场景
  private readonly mainCamera:UniversalCamera // 主相机
  private deputyCameras:UniversalCamera[] = [] // 副相机组
  private readonly CameraCount:number // 相机数量
  private _position:Vector3 // 相机位置
  private _ellipsoid!:Vector3 // 碰撞检测盒子大小
  private _speed!: number // 相机速度
  private _checkCollisions!: boolean // 检查碰撞检测
  private _applyGravity!: boolean // 应用重力

在构造函数中进行初始化操作

constructor (
    name:string, // 相机名
    position:Vector3, // 位置
    scene:Scene, // 场景
    CameraCount?:number // 相机数量
  ) {
  // 初始化相机名
    this._name = name
    // 初始化相机位置
    this._position = position
    // 初始化相机数量
    this.CameraCount = (CameraCount || 4) < 4 ? 4 : (CameraCount || 4)
    // 初始化场景
    this.scene = scene
    // 初始化主相机
    this.mainCamera = new UniversalCamera(
      this._name,
      this.position,
      this.scene
    )
    this.mainCamera.fov = Math.PI / (this.CameraCount / 2) // 设置主相机视野
    this.mainCamera.fovMode = UniversalCamera.FOVMODE_HORIZONTAL_FIXED // 设置主相机视野模式
    // eslint-disable-next-line no-unused-expressions
    scene.activeCameras?.push(this.mainCamera) // 主相机推入场景激活相机组
    this.mainCamera.viewport = new Viewport(0, 0, 1 / this.CameraCount, 1) // 设置主相机视口
    // 初始化副相机组
    for (let i = 0; i < this.CameraCount - 1; i++) {
    // 定义副相机
      const deputyCamera = new UniversalCamera(
        this._name + 'Camera' + (i + 1),
        new Vector3(0, 0, 0),
        this.scene
      )
      deputyCamera.parent = this.mainCamera // 设置父级别为主相机
      this.deputyCameras.push(deputyCamera) // 推入副相机组
      // eslint-disable-next-line no-unused-expressions
      scene.activeCameras?.push(deputyCamera) // 副相机推入场景激活相机组
      deputyCamera.rotation = new Vector3(0, (Math.PI / (this.CameraCount / 2)) * (i + 1), 0) // 设置副相机旋转
      deputyCamera.fov = Math.PI / (this.CameraCount / 2) // 设置相机视野
      deputyCamera.fovMode = UniversalCamera.FOVMODE_HORIZONTAL_FIXED // 设置相机视野模式
      deputyCamera.viewport = new Viewport((1 / this.CameraCount) * (i + 1), 0, 1 / this.CameraCount, 1) // 设置相机视口
    }
  }

公开主相机的attachControl

  public attachControl = (canvas: HTMLCanvasElement, noPreventDefault?: boolean | undefined):void => {
    this.mainCamera.attachControl(canvas, noPreventDefault)
  }

将主相机常用的一些方法和属性用setter和getter公开

  /*
  * getter/setter
  */

  // 碰撞检测盒getter/setter
  public get ellipsoid (): Vector3 {
    return this._ellipsoid
  }

  public set ellipsoid (value: Vector3) {
    this.mainCamera.ellipsoid = value
    this._ellipsoid = value
  }

  // 相机位置getter/setter
  public get position (): Vector3 {
    return this._position
  }

  public set position (value: Vector3) {
    this.mainCamera.position = value
    this._position = value
  }

  // 相机名getter/setter
  public get name (): string {
    return this._name
  }

  public set name (value: string) {
    this.mainCamera.name = value
    this._name = value
  }

  // 相机速度
  public get speed (): number {
    return this._speed
  }

  public set speed (value: number) {
    this.mainCamera.speed = value
    this._speed = value
  }

  // 是否应用碰撞检测
  public get checkCollisions (): boolean {
    return this._checkCollisions
  }

  public set checkCollisions (value: boolean) {
    this.mainCamera.checkCollisions = value
    this._checkCollisions = value
  }

  // 是否应用重力
  public get applyGravity (): boolean {
    return this._applyGravity
  }

  public set applyGravity (value: boolean) {
    this.mainCamera.applyGravity = value
    this._applyGravity = value
  }

齐活儿。


3.使用

放映的时候,用英伟达或者amd驱动的跨屏幕融合吧环形屏幕搞成理论上的一整块,然后网页全屏就可以用。


4.后记

其实现在还有一些问题,就是目前移动控制器的正向是主相机的朝向,在上面画面的最左侧,之后还需要优化一下,将主相机挪到画面的中间(最好是能够随意挪动,想放在第几个放在第几个)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值