嗨,我是小路。今天主要和大家分享的主题是“vue+three.js 加载fbx动画模型”。        

在现代网页开发中,3D 图形和动画的应用越来越广泛,从产品展示、虚拟展厅到游戏、教育等领域,三维技术正在不断刷新用户体验。而作为前端开发者,如何将高性能的 3D 动画无缝集成到 Vue 项目中?今天从网上找了一个fbx动画模型,然后将其加载出来,并让模型动起来。

项目示意图

1.FBXLoader加载器

定义:主要用来加载fbx格式的动画模型。

二、实例代码

<!--
**加载fbx文件
-->
<template>
  <div class="pageBox">
    <div class="leftBox" ref="leftRef"></div>
    <div class="rightBox" ref="rightRef" :style="{ background: bgColor }"></div>
  </div>

</template>
<script setup>
import { onMounted, reactive, ref } from 'vue';
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入gltf模型加载库GLTFLoader.js
import { FBXLoader } from 'three/addons/loaders/FBXLoader';

const bgColor = ref("")

const leftRef = ref();
const rightRef = ref()
// 定义相机输出画布的尺寸(单位:像素px)
let width = 800; //宽度
let height = window.innerHeight; //高度

const clock = new THREE.Clock();
// 创建FBX加载器对象
const loader = new FBXLoader();

// 创建3D场景对象Scene
let scene,camera,spotLight,renderer,ambient,controls ;
const initThree = () => {
  scene = new THREE.Scene();
  //设置背景色
  scene.background = new THREE.Color("#dfe9f3");
  camera = new THREE.PerspectiveCamera(50, width / height, 2, 6000);
   // 根据需要设置相机位置具体值
  camera.position.set(200, 200, 200);
  spotLight = new THREE.SpotLight(0xffffff, 1.0);
  scene.add(spotLight);//光源添加到场景中
  renderer = new THREE.WebGLRenderer();
  //环境光:没有特定方向,整体改变场景的光照明暗
  ambient = new THREE.AmbientLight(0xffffff, 0.4);
  scene.add(ambient);

  renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
  leftRef.value.append(renderer.domElement);
  //添加相机空间
  controls = new OrbitControls(camera, renderer.domElement);
  // 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
  controls.addEventListener('change', function () {
    renderer.render(scene, camera); //执行渲染操作
  });//监听鼠标、键盘事件
}

const modelObj = reactive({ index: 1, url: './models/animate.fbx' });

onMounted(() => {

  initThree();
  loadGltfData();
  render();
  // 处理窗口大小变化 只需要设置相机 和重新渲染
  window.addEventListener("resize", () => {
    camera.aspect = width / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(width, window.innerHeight);
  });
})

let mixer = "";
let action = "";

//加载gltf模型
const loadGltfData = () => {
  modelObj.url && loader.load(modelObj.url, function (fbx) {
    fbx.scale.setScalar(1); // 调整模型大小
    fbx.position.set(0, -100, 0); // 调整模型位置
    
    // 创建动画混合器
    mixer = new THREE.AnimationMixer(fbx);

    // 播放所有动画
    const animations = fbx.animations;
    if (animations && animations.length > 0) {
      action = mixer.clipAction(animations[0]);
      action.play();
    }
    //获取模型的长、宽、高
    let scale = getScale(fbx)
    //同比例放大,模型不变形
    fbx.scale.setScalar(scale)
    scene.add(fbx);
  }, function (xhr) {
    //加载时
    console.log((xhr.loaded / xhr.total * 100) + '% loaded');
  }, function (error) {
    console.log('加载失败', error);
  })
}

//获取模型长宽高
const getScale = (model)=>{
  // 计算模型的边界框
  const box = new THREE.Box3().setFromObject(model);
  
  // 获取边界框的尺寸
  const size = new THREE.Vector3();
  box.getSize(size);
  //以屏幕的一般高度为放缩比例
  let scale = (height/8)/size.z;
  return scale;
}

//渲染
const render = () => {
  //解决加载gltf格式模型纹理贴图和原图不一样问题
  renderer.outputEncoding = THREE.sRGBEncoding;
  //播放动画,要及时更新动画混合播放器
  mixer ? mixer.update(clock.getDelta()) : null;
  renderer.render(scene, camera); //执行渲染操作
  //重复渲染
  requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}

</script>
<style scoped lang="less">
.pageBox {
  width: 100%;
  height: 100vh;
  padding: 0;
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;

  .rightBox {
    width: 100%;
    height: 100%;
    background: #dfe9f3;
  }
}
</style>

三、复盘总结

       1、fbx动画模型加载和glft模型加载思路是一样的,需要注意的是在加载模型的处理。gltf有是加载gltf.scene;而fbx是将本身添加到scene。

        2、注意代码的封装。当使用代码越多,越要将其中的部分代码进行封装,用作为了开发的储备,这样遇到问题,可以直接从自己的练习库中寻找。编程做到最后,自然就是越做越轻松。也许后期,真的可以cltr+c + cltr+v。

都看到这里了,记得【点赞】+【关注】哟。

参考文档:

threeJs+vue 加载gltf模型、获取模型尺寸、播放模型动画-CSDN博客

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐