ThreeJS中的模型加载以及拍摄

1.1. 模型拍摄

下方为在AI资源平台上传后的模型转动不同角度后的视图,业务场景需要模型调转不同角度进行截图,然后对截图进行保存,然后将保存的图片作为模型封面进行展示,最初的做法是直接使用电脑上自带的截图功能,但该做法每次需要手动将图片保存本地然后再点击上传,整个过程烦琐不易于用户操作,因此提出用户可以通过转动模型,点击拍摄按钮,实现一键式的角度拍摄 && 图片上传。

正面
正面
背面
底部
左侧面
右侧面
头部

整体的处理流程如下所示:

1、threejs模型加载暴露一个GF方法给用户,该方法用于获取当前模型的画面数据

2、当用户点击按钮的时候会调用GF方法获取当前画面数据

3、然后该画面数据会进行转码,通过Blob的方式封装成File对象

4、然后将该文件对象上传到Server服务器

关于GF方法本身并不是threejs自身暴露的,而是在代码内部实现的一个回调方法,它的具体实现是根据threeJS在执行的过程中会暴露一个canvas上下文,当GF调用即用户点击拍摄按钮的时候,首先会执行threeJSrender函数来确定当前画面,然后该过程会暴露canvas,再使用toDataURL来获取base64数据

GF代码实现:

fileResultGet() {
  // 确保视角更新后,重新渲染场景
  this.renderer.render(this.scene, this.camera); // 将此行代码添加在截图逻辑之前
  // 设置渲染器输出高分辨率图片
  const originalWidth = 600;
  const originalHeight = 300;
  const scale = 1;
  this.renderer.setSize(originalWidth * scale, originalHeight * scale);
  // 渲染场景
  this.renderer.render(this.scene, this.camera);
  // 从WebGL canvas获取DataURL
  const imgUrl = this.renderer.domElement.toDataURL('image/png');
  // 将渲染器恢复到原始尺寸供日常渲染使用
  this.renderer.setSize(originalWidth, originalHeight);
  this.renderer.render(this.scene, this.camera);
  return dataURLToFile(imgUrl);
}

1.2. GIF拍摄

因为模型有的是动作,所以拍摄的时候需要在一定时间内捕获当中的动作,来形成GIF图来作为模型的展示,它的实现原理与静态图片拍摄类似,整体的处理流程如下所示:

1、threejs模型加载暴露一个TF方法给用户,该方法用于获取当前模型的动态画面数据

2、当用户点击按钮的时候会调用TF方法获取一段时间内的画面数据,其实现是根据定时器以一定频率不断拍摄静态画面,整个过程属于await状态。

3、将拍摄得到的静态画面队列数据,使用Gif.js库进行gif图合成形成gif文件

4、然后将该文件对象上传到Server服务器

1.3. 进度条展示

本身threeJS方法中的loader加载器接受一个回调函数,该函数中可以不断获取当前模型“加载”的进度,但此“加载”并不是threejs单纯加载模型的耗时,而是threejs发送的请求耗时,本身的耗时相对网络请求可忽略不计

具体的代码展示:

fbx: (url: string, scene: any, keyFrame: string) => {
    return new Promise((res) => {
      regesiterManager(keyFrame);
      new FBXLoader(manager).load(
        url,
        (obj: object) => {
          scene.add(obj);
          res(obj);
        },
        // 回调显示进度条
        (xhr: object) => onProgress(xhr, keyFrame),
      );
    });
  },
  // 回调函数从threejs不断获取进度信息
  const onProgress = function (xhr: object, keyFrame: string) {
    // // 更新进度条的宽度
    let percentComplete = (xhr.loaded / xhr.total) * 100;
    const domProgressValue = document.getElementById(`progressValue-${keyFrame}`);
    const domProgress = document.getElementById(`canvasProgress-${keyFrame}`);
    if (domProgress) {
      domProgress.value = percentComplete.toFixed(2);
      domProgress.style.opacity = '1';
    }
    if (domProgressValue) {
      domProgressValue.innerHTML = `${percentComplete.toFixed(2)}%`;
      domProgressValue.style.opacity = '1';
    }
    if (percentComplete >= 99.9) {
      hideProgress(keyFrame);
    }
  };

当关闭处于正在加载的模型,怎么中断进度条,从上面可知threeJS对模型的加载主要为http请求,如果要实现中断的效果则需要将onProgress的过程外移,即不依赖threeJS内部的fetch,通过自定义fetch先拿到资源数据,这个过程中fetch进度可知且可通过定义AbortController来实现请求中断,具体的实现如下:

async function fetchWithProgress(url) {
    const controller = new AbortController();
    const signal = controller.signal;
  
    try {
      const response = await fetch(url, { signal });
  
      if (!response.body) {
        throw new Error('ReadableStream not supported');
      }
  
      const contentLength = response.headers.get('content-length');
      if (!contentLength) {
        throw new Error('Content-Length response header unavailable');
      }
  
      const totalSize = parseInt(contentLength, 10);
      let loadedSize = 0;
  
      const reader = response.body.getReader();
      let receivedValue;
  
      // 流读取循环
      while (true) {
        const { done, value } = await reader.read();
        if (done) {
          console.log('Download complete');
          break;
        }
        loadedSize += value.length;
        console.log(`Download Progress: ${(loadedSize / totalSize * 100).toFixed(2)}%`);
        receivedValue = new Uint8Array(value);
      }
    } catch (error) {
      if (error.name === 'AbortError') {
        console.log('Download aborted');
      } else {
        console.error('Download failed:', error);
      }
    }
  
    // 中断下载的方法
    function abortDownload() {
      controller.abort();
      console.log('Download has been aborted');
    }
    return {
      abort: abortDownload,
    };
  }
  
  const { abort } = fetchWithProgress('下载模型资源的URL');
  // 如果需要中断下载
  abort();

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值