Skip to content

场景数据对接服务端

提示

由于是纯前端项目,对于场景中的数据持久化存储方式使用的是toJSON+indexedDB来实现的

对接后端接口

这里只需要修改两处代码即可

@/views/sceneEdit/components/SceneHeader/index

将保存至 indexedDB 中的方法改为后端接口即可

js
/**
 * 保存场景到indexDb
 */
const saveSceneIndexDb = async () => {
  try {
    if (!store.sceneApi) {
      throw new Error('场景未初始化');
    }
    let newScene = cloneDeep(store.sceneApi?.scene);
    const transformControlsRoot = newScene?.getObjectByProperty(
      'isTransformControlsRoot',
      true
    );
    const boxHelper = newScene?.getObjectByProperty('type', 'BoxHelper');
    const particles = newScene?.getObjectByProperty('type', 'Points');
    newScene?.remove(transformControlsRoot as THREE.Object3D);
    newScene?.remove(boxHelper as THREE.BoxHelper);
    newScene?.remove(particles as THREE.Points);
    // 创建一个新的对象来存储序列化后的数据
    let jsonData = {
      scene: newScene?.toJSON(),
      camera: store.sceneApi.camera?.toJSON(),
      weather: toRaw(store.sceneApi.weatherEffectsModules.weatherConfig),
    };
    let sceneInfo = {
      sceneBlobData: IndexDbStoreKeyPath.sceneBlobData,
      ...jsonData,
    };
    const oldData = await indexDbStore.indexDbUtil?.get(
      IndexDbStoreName.scene,
      IndexDbStoreKeyPath.sceneBlobData
    );

    if (oldData) { 
      await indexDbStore.indexDbUtil?.update(IndexDbStoreName.scene, {
        ...oldData,
        ...jsonData,
      });
    } else {
      await indexDbStore.indexDbUtil?.add(IndexDbStoreName.scene, sceneInfo);
    }

   // 后端接口
    const res = await updateSceneData(sceneInfo)

    disposeScene(newScene);
  } catch (error) {
    console.error('保存场景失败:', error);
    return Promise.reject(error);
  } finally {
    return Promise.resolve();
  }
};

@/utils/renderScene.ts

在初始化场景时也会先获取历史数据,这里也需要换成后端接口

js
 /**
   * 初始化场景
   * @returns Promise<boolean>
   */
  init(): Promise<boolean> {
    return new Promise(async (resolve, reject) => {
      if (!this.container) {
        reject(new Error('Container not found'));
        return;
      }
      this.initCamera();
      this.initRender();
      await this.initScene();
      // 获取indexDb场景数据
      const loadSceneData = (await indexDbStore.indexDbUtil?.get(
        IndexDbStoreName.scene,
        IndexDbStoreKeyPath.sceneBlobData
      )) as IndexDbSceneData;

     // 通过后端接口获取
      const loadSceneData  = await getSceneDataInfo()

      // 如果存在场景数据则加载场景数据
      if (loadSceneData) {
        await this.loadIndexDbSceneData(loadSceneData);//
      } else {
        // 如果不存在场景数据则初始化变换控制器
        this.transformControlsModules.init();
      }
      await this.initPlaneGround(loadSceneData);
      await this.initControls();
      this.sceneAnimation();
      this.addEvenListMouseListener();
      this.onWindowResizes();
      resolve(true);
    });
  }

为什么是toJSON方式存储方式?

答:因为项目是一个场景编辑器,实现的是在一个场景中编辑多个模型,灯光,几何体,外部模型等,并且每个材质的可编辑属性值也非常多,如果采用传统的属性+属性值键值对的方式json的方式来存储

那就意味着场景中每多一个内容和新增一个可编辑值我们都要在一个循环遍历方法中多执行一次 Three.js 模型数据修改的方法,这样的性能消耗将会是巨大的

而使用 toJSON 则会将整个场景内容转化为 Three.js 特定的数据格式,我们只关心数据的存储和读取即可,这就意味着将减少我们很多的工作量

本文档内容版权属于threejs-3dmodel-edit作者,保留所有权利