Orillusion / orillusion

Orillusion is a pure Web3D rendering engine which is fully developed based on the WebGPU standard.
https://www.orillusion.com
MIT License
4.47k stars 551 forks source link

[FR]: 文档:如何清理资源 #176

Closed mankeheaven closed 7 months ago

mankeheaven commented 1 year ago

当我离开视图(router), 需要清理Orillusion哪些资源?希望文档能补充对这章的明确说明

我目前用到react,react-router-dom,

orillusion demo代码取自于它 https://www.orillusion.com/guide/getting_start/draw_cube.html

我封装了一个orillusion操作类,当离开react router对应的视图时候(组件销毁),调用dispose,发生了如下截图的错误。

import {
  Engine3D,
  Scene3D,
  Object3D,
  Camera3D,
  LitMaterial,
  BoxGeometry,
  MeshRenderer,
  DirectLight,
  HoverCameraController,
  View3D,
  AtmosphericComponent,
} from "@orillusion/core";

export class Tourial {
    canvas: HTMLCanvasElement
    scene: Scene3D|null = null
    view: View3D | null = null

  constructor(canvas: HTMLCanvasElement) {
    this.canvas = canvas
    return this;
  }

  async initEngine(){
    await Engine3D.init({
        canvasConfig: { canvas: this.canvas },
      });
  }

  async initView() {
    // create new scene as root node
    const scene3D: Scene3D = new Scene3D();
    this.scene = scene3D;
    // add an Atmospheric sky enviroment
    const sky = scene3D.addComponent(AtmosphericComponent);
    sky.sunY = 0.6;
    // create camera
    const cameraObj: Object3D = new Object3D();
    const camera = cameraObj.addComponent(Camera3D);
    // adjust camera view
    camera.perspective(60, Engine3D.aspect, 1, 5000.0);
    // set camera controller
    const controller = cameraObj.addComponent(HoverCameraController);
    controller.setCamera(0, 0, 15);
    // add camera node
    scene3D.addChild(cameraObj);
    // create light
    const light: Object3D = new Object3D();
    // add direct light component
    const component: DirectLight = light.addComponent(DirectLight);
    // adjust lighting
    light.rotationX = 45;
    light.rotationY = 30;
    component.intensity = 1;
    // add light object
    scene3D.addChild(light);
    // create new object
    const obj: Object3D = new Object3D();
    // add MeshRenderer
    const mr: MeshRenderer = obj.addComponent(MeshRenderer);
    // set geometry
    mr.geometry = new BoxGeometry(5, 5, 5);
    // set material
    mr.material = new LitMaterial();
    // set rotation
    obj.rotationY = 45;
    // add object
    scene3D.addChild(obj);
    // create a view with target scene and camera
    const view = new View3D();
    view.scene = scene3D;
    view.camera = camera;
    // start render
    Engine3D.startRenderView(view);
  }

  dispose(){
    console.log('销毁')
    this.view?.dispose()
    this.scene?.dispose()
  }
}

image

mankeheaven commented 1 year ago

测试场景如下:

Engine3D初始化

添加渲染物体,开始渲染

等待5秒钟,销毁所有资源

继续一次上述步骤,Engine3D初始化...

lslzl3000 commented 1 year ago

same as #125 目前引擎还不支持 Engine3D 全局销毁,后面版本会考虑支持

目前只支持 Object3D 和相关几何、贴图数据的销毁

let box  = new Object3D()
let mr = box.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry()
mr.material = new LitMaterial()
...
box.destroy(true) // dispose box and its geometry, material, texture ...
// or
box.destroy() // delete box object only, but the geometry and material resource will not be disposed

但实际上 WebGPU/WebGL 的编程中,很多变量和状态都没有提供手动销毁的方法,依赖于浏览器的 GC 管理,所以想做到彻底销毁最好的办法是利用 iframe 隔离管理一个 Engine3D 实例,当iframe 被移除,浏览器会自动回收所有相关内存和显存资源。

目前主流的多实例演示网站,如 orillusion doc, 官方的 webgpu samples,还包括 WebGL 的引擎,如three docbabylon doc,还有一些做代码 playground 的网站,如 Codepen 都是以 iframe 进行多实例管理,简单高效,避免复杂的状态和内存管理,不用销毁即可

至于利用 react/vue 封装 iframe 就是常规操作了,这里就不展开了,可以自行搜索先关标准和解决方案

mankeheaven commented 1 year ago

iframe这个思路并不能接受,销毁是个基本操作,iframe只是一种特殊情况,并不能覆盖所有场景。

当产生3d canvas与项目本身的通讯的时候,iframe就是一种阻碍了。

一个最基本的场景:

拉取了ajax数据后,要给3d场景展示这些动态数据?这个数据通讯?

lslzl3000 commented 1 year ago

基于 iframe 的数据交换是很成熟技术,e.g postmessage ,如果是同域名下的操作就更简单。

我们后面会提供 Engine3D 层面的销毁,但以目前 webgpu 的标准,很难自动清除所有的内存和显存状态,创建新的示例仍然会有内存或显存溢出的风险。目前主流的引擎无论webgl/webgpu还是native,都需要开发自己管理释放的工作,总体来说是一件很复杂的工程。尤其是在web上,相比较复杂的内存和显存管理,iframe通信的管理要简单很多,这么多web3d项目都不约而同的选择了用 iframe 来管理页面多实例是经过长期实践的结果。