three.js 如何实现模型材质分解,拆分,拆解效果

1,473 阅读2分钟

前言

大多数的3D模型都是由很多不同形状的材质组成一块的模型,在一些业务场景中我们需要将模型不同模块的材质进行拆解展示以达到项目的需要,本篇将给大家介绍一下在three.js中如何实现3D模型的分解和拆解功能

原理:通过修改模型材质的 x,y,z 轴坐标 positon.set( x,y,z) 来实现拆解,分解的效果。

注意:支持模型材质position 修改的材质类型为 type="Mesh" ,其他类型的材质修改了position 可能没有实际效果

在上一篇 Three.js加载外部glb,fbx,gltf,obj 模型文件 的文章基础上

新增模型拆解的方法

模型拆解方法:setModelMeshDecompose

一、安装 tween.js(用于处理模型拆解的位置移动缓冲动画效果)

yarn add @tweenjs/tween.js
import TWEEN from "@tweenjs/tween.js";

二、setModelMeshDecompose 方法

   // decompose 分解的大小距离
	setModelMeshDecompose(decompose ) {
	    // 如果当前模型只有一个材质则不进行拆解
		if (this.glowMaterialList.length <= 1) return false
		// 修改材质位置移动
		const modelDecomposeMove = (obj, position) => {
			new TWEEN.Tween(obj.position)
				.to(position, 500)
				.onUpdate(function (val) {
					obj.position.set(val.x || 0, val.y || 0, val.z || 0);
				})
				.start();
		}
		const length = this.glowMaterialList.length
		const angleStep = (2 * Math.PI) / length;
		// TODD glowMaterialList:当前模型的所有材质列表名称
		this.glowMaterialList.forEach((name, i) => {
		   // 通过getObjectByName 获取 要修改的材质
			const mesh = this.model.getObjectByName(name)
			// 如果 type 类型为Mesh 则修改材质的位置
			if (mesh.type == 'Mesh') {
		     	    // 拆解位置移动的计算公式
                 	        const angle = i * angleStep;
				const x = (decompose) * Math.cos(angle);
				const y = (decompose) * Math.sin(angle);
				const position = {x, y, z: 0}			
				// 执行拆解
				modelDecomposeMove(mesh, position)
			}
		})
	}

三、获取当前模型的所有材质名称的方法

   getFlowMeaterList(){
        const modelMaterialList= []
  		this.model.traverse((v) => {
			if (v.isMesh && v.material) {
			    modelMaterialList.push(v)	
			}
		})
	     this.glowMaterialList = modelMaterialList.map(v=>v.name)
   }

四、在场景渲染动画帧方法中添加 TWEEN.update()

 render(){
	  this.renderer.render(this.scene, this.camera)
	  TWEEN.update()
 }

五、在页面中使用

<script setup>
import { useMeshEditStore } from '@/store/meshEditStore'
const store = useMeshEditStore();

const onChangeDecompose = (decompose) => {
  store.modelApi.setModelMeshDecompose(decompose);
};
</script>

完整的代码可参考:gitee.com/ZHANG_6666/…

界面效果对比

拆解前: image.png

拆解后: image.png