THREE加载模型FBX、OBJ、GLTF

1 篇文章 0 订阅

加载FBX模型

  • ps 文章断更一个多月了,今天女朋友提醒,再次沉下心来继续记录最近学习过程。生命不止,学习不休。
<script lang="ts" setup>
import * as THREE from "three";
import { onMounted, ref } from "vue";
//引入加载器
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
//引入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
const visible = ref<boolean>(false);
const percent = ref<Number>(0); // 进度条
let raycaster: THREE.Raycaster;
let mouse: THREE.Vector2;
let dom: HTMLCanvasElement | null;
let camera: THREE.PerspectiveCamera
let clickObjects: THREE.Group
let scene:THREE.Scene
onMounted(() => {
  dom = document.querySelector("#three-model");
  let controls: OrbitControls;
  if (dom) {
    scene = new THREE.Scene();
    // 创建相机 倾斜度 画布大小1200/900 最小视距 最大视距
    camera = new THREE.PerspectiveCamera(45, 1200 / 900, 1, 10);
    camera.position.set(2, 2, 4);
    camera.lookAt(new THREE.Vector3());
    const renderer = new THREE.WebGLRenderer({
      canvas: dom,
      antialias: true,
      alpha: true,
    });
    renderer.setClearColor("rgba(0,0,0,1)");
    renderer.setSize(1200, 900);
    // 添加辅助工具 坐标系 与坐标轴
    const axesHelper = new THREE.AxesHelper(5);
    scene.add(axesHelper);
    const pointLigth = new THREE.PointLight("#fff", 1);
    pointLigth.position.set(2, 2, 2);
    scene.add(new THREE.PointLightHelper(pointLigth, 0.1));
    scene.add(new THREE.GridHelper(5, 20));
    //添加光源 有些模型的材质是感光的 不加光源看不到
    const AmbientLight = new THREE.AmbientLight("#fff");
    scene.add(AmbientLight);
    //添加控制器
    controls = new OrbitControls(camera, dom);
    //添加模型 FBX加载
    const loader: FBXLoader = new FBXLoader();
    //加载模型
    loader.load(
      "/models/robot.fbx",
      (object) => {
        percent.value = 0;
        // 模型缩放
        object.scale.set(0.01, 0.01, 0.01);
        scene.add(object);
        clickObjects = object
        console.log(object);
      },
      (xhr) => {
        visible.value = true;
        percent.value = (xhr.loaded / xhr.total) * 100;
        if (percent.value === 100) visible.value = false;
      }
    );
    //GLTF加载
     loader.load(`/models/2CylinderEngine.gltf`, (obj) => {
        const color = new THREE.Color(255, 0, 0)
        obj.scene.traverse(function (child) {
          // 放射光颜色与放射光贴图 不设置可能导致黑模
          if (child.isMesh) {
            if (child.name === 'body_23') {
              child.material.oldColor = child.material.color.clone()
              child.material.color = color
            }
          }
          if (child instanceof THREE.Mesh) {
            // 每个储位单独赋予一个基础材质
            child.material = child.material.clone() // new THREE.MeshBasicMaterial({ color: 0xffffff })
          }
        })
        obj.scene.scale.set(0.001, 0.001, 0.001)
        scene.add(obj.scene)
        this.clickObjects = obj
      })
	// OBJ加载
		const objLoader = new THREE.OBJLoader();
		objLoader.load('/models/xl.obj', (obj) => {
			obj.scale.set(0.05, 0.05, 0.05);
           scene.add(obj)
		})
		
    const render = () => {
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    };
    render();

    // 添加点击事件
    raycaster = new THREE.Raycaster();
    mouse = new THREE.Vector2();
    dom.addEventListener("click", onMouseClick, false);
  }
});
const onMouseClick = (event: any) => {
  if (dom) {
  // 计算点击位置时,是canvas元素距离左上角的距离 不然点击会获取错乱
    var width = dom.offsetWidth;
    var height = dom.offsetHeight;
    var marginLeft = dom.getBoundingClientRect().left;
    var marginTop = dom.getBoundingClientRect().top;
    mouse.x = ((event.clientX - marginLeft) / width) * 2 - 1;
    mouse.y = -((event.clientY - marginTop) / height) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    // 获取raycaster直线和所有模型相交的数组汇合
    var intersects = raycaster.intersectObjects([clickObjects]); // 
    // var intersects = raycaster.intersectObjects(scene.children) // 场景中所有的
    if (intersects.length > 0) {
    // 获取点击界面第一个物体
      console.log(intersects[0]);
    }
  }
};
</script>

关于模型太大优化

THREE开发项目,模型的三角面越多,体量就越大
因为三维模型文件往往比较大,所以Web3D项目相比较普通的前端web项目,需要加载文件体积比较大,需要花费的时间自然比较多,加载时间比较长的情况下,对于用户来说体验肯定不太好。

1、二进制格式
使用不同文件格式,文件的大小会有所不同,如果同一个模型,导出二进制.fbx大小要比文本格式的.obj文件要小1~2倍。常见的GLTF格式可以是文本格式,也可以使二进制格式,为了更好的传输性能可以选择二进制格式,.glTF打包转化为.glb二进制文件。

2、减面和法线贴图
一般3D美术导出模型的时候,会进行减面操作,并导出模型的法线贴图,比如你只是加载一个机械零件模型(非批量),你可以让3D美术进行减面然后导出法线贴图,这样的话在不影响曲面显示质量前提下,减少模型三角形面数,一方面可以降低模型文件大小提高网络传输性能,另一方面可以提高threejs渲染模型的渲染性能。

3、加载进度条
因为Web3D项目加载时间相对普通web页面时间比较长,如果用户一直等着,web页面没有什么反应,可能会关掉,这种情况下,可以在web页面放置一个进度条实时显示模型文件加载进度。

如何获得三维模型文件的加载进度可以查看threejs文档关于FileLoader类的介绍,至于web进度条,可以通过普通HTML和CSS代码去实现,然后和threejs加载进度数据进行绑定即可。

4、动态分批加载
如果一个场景中,有多个网格模型模型,比如室内设计效果展示,里面有沙发、椅子、电视等三维模型,这时候把这些模型分别单独建立一个文件,threejs可以按照一定的顺序分别先后加载这些单独的网格模型文件,然后插入到场景中。这样的话,用户可以以最快速度查看到场景中的部分模型,不用一直等待,没有什么反应,用户体验更好。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值