BabylonJs实现上传本地模型到后端生成预览图

BabylonJs实现上传本地模型到后端生成预览图前言 最近有个需求,需要本地上传3D模型到后端,并截图生成预览图。 思路 简单来书,上传模型时,用Babylon.js渲染模型,然后使用画布截图的功能。 但要注意的是,本地模型不一定就一个模型文件,还

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

最近有个需求,需要本地上传3D模型到后端,并截图生成预览图。

思路

简单来书,上传模型时,用Babylon.js渲染模型,然后使用画布截图的功能。 但要注意的是,本地模型不一定就一个模型文件,还需要考虑模型的相关贴图和文件,比如说MTL,PNG等资源文件。

查看Babylon的文档和源码发现,Babylon的loader支持直接读取File文件,FileInput类提供了加载FileList功能,这个类会把批量上传的文件列表中的贴图资源,做一层Name-File的映射,当Loader读取到对应的贴图文件时,将会去读取对应的File.

所以,我们需要实现一个FilePreview类,这个类传入FileList,然后解析FileList渲染到画布上,然后截图上传到后端,获取到预览图url后,在把url和模型一起发动到后端。

这篇文章仅实现前端截图部分.

实现

创建一个FilePreviewer类,先贴具体实现代码

import {
  ArcRotateCamera,
  Color3,
  Engine,
  FilesInput,
  FramingBehavior,
  Observable,
  Scene,
  StandardMaterial,
  Tools,
} from "@babylonjs/core";

export class FilePreviewer {
  private filesInput: FilesInput;
  private engine: Engine;
  private scene: Scene;
  private onFileLoadedObserver = new Observable<File>();
  private isRendered = false;
  constructor(canvas: HTMLCanvasElement) {
    this.engine = new Engine(canvas, false, {
      premultipliedAlpha: false,
      preserveDrawingBuffer: true,
      antialias: false,
    });

    this.scene = new Scene(this.engine);
    this.scene.createDefaultCameraOrLight();
    this.scene.render();

    let filesInput = new FilesInput(
      this.engine,
      null,
      (sceneFile, scene) => {
        this.scene = scene;
        const isGLTF =
          sceneFile.name.endsWith(".glb") || sceneFile.name.endsWith(".gltf");
        this.prepareCamera(isGLTF);
        (scene.materials as StandardMaterial[]).forEach((m) => {
          m.diffuseColor = Color3.White();
          m.backFaceCulling = false;
          m.emissiveColor = Color3.Black();
        });
        this.onFileLoadedObserver.notifyObservers(sceneFile);
      },
      (e) => {},
      () => {
        this.isRendered = true;
      },
      (r) => {},
      () => {},
      null,
      () => {}
    );

    this.filesInput = filesInput;
  }
  //模型缩放到全屏空间
  prepareCamera(isGLTF = false) {
    this.scene.createDefaultCameraOrLight(true, true);
    const camera = this.scene.activeCamera as ArcRotateCamera;

    if (isGLTF) camera.alpha += Math.PI;

    camera.useFramingBehavior = true;

    const framingBehavior = camera.getBehaviorByName(
      "Framing"
    ) as FramingBehavior;
    framingBehavior.framingTime = 0;
    framingBehavior.elevationReturnTime = -1;

    if (this.scene.meshes.length) {
      camera.lowerRadiusLimit = null;

      const worldExtends = this.scene.getWorldExtends(function (mesh) {
        return mesh.isVisible && mesh.isEnabled();
      });
      framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
    }

    camera.pinchPrecision = 200 / camera.radius;
    camera.upperRadiusLimit = 5 * camera.radius;

    camera.wheelDeltaPercentage = 0.01;
    camera.pinchDeltaPercentage = 0.01;

    camera.attachControl();
  }
  loadLocalFile(evt: any) {
    this.isRendered = false;
    this.filesInput.loadFiles(evt);
  }
  async getPreviewUrl(): Promise<string> {
    await this.waitRendered();

    return new Promise((res) => {
      Tools.CreateScreenshot(
        this.engine,
        this.scene.activeCamera!,
        400,
        (data) => {
          res(data);
        }
      );
    });
  }
  async waitRendered() {
    return new Promise((res) => {
      setInterval(() => {
        if (this.isRendered) res(null);
      }, 100);
    });
  }
  destory() {
    this.filesInput.dispose();
    this.onFileLoadedObserver.clear();
    this.engine.dispose();
  }
}

抛开初始化Babylon初始化场景不谈,这个类主要传入一个画布初始化类,通过loadLocalFile接口,接受file input 的event,开始解析文件列表,加载完成后把模型最大化的全屏空间,添加一个标记,在截图前判断是否模型已经被加载

eg.gif

源码地址

今天的文章BabylonJs实现上传本地模型到后端生成预览图分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19045.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注