Three.js 实现模型材质分解,拆分,拆解效果

原理:通过修改模型材质的 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()
}

完整的代码可参考:

https://gitee.com/ZHANG_6666/Three.js3D
https://github.com/zhangbo126/Three3d-view
界面效果对比
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现模型波纹效果,可以使用three.js中的ShaderMaterial和RenderTarget实现。具体步骤如下: 1. 创建两个RenderTarget,一个用于存储模型的深度信息,另一个用于存储波纹效果的纹理信息。 ```javascript var depthRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter } ); var rippleRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter } ); ``` 2. 创建一个ShaderMaterial,该材质需要使用深度RenderTarget和波纹RenderTarget中的信息来计算出波纹效果的纹理。 ```javascript var rippleMaterial = new THREE.ShaderMaterial( { uniforms: { depthTexture: { value: depthRenderTarget.texture }, rippleTexture: { value: rippleRenderTarget.texture }, time: { value: 0 }, resolution: { value: new THREE.Vector2( window.innerWidth, window.innerHeight ) } }, vertexShader: document.getElementById( 'rippleVertexShader' ).textContent, fragmentShader: document.getElementById( 'rippleFragmentShader' ).textContent } ); ``` 3. 将该ShaderMaterial应用到模型上,并将模型渲染到深度RenderTarget中。 ```javascript var model = ...; // 创建模型 var scene = new THREE.Scene(); scene.add( model ); var camera = ...; // 创建相机 var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); renderer.setRenderTarget( depthRenderTarget ); renderer.render( scene, camera ); ``` 4. 创建一个平面,使用上面创建的ShaderMaterial来渲染该平面,并将该平面渲染到波纹RenderTarget中。 ```javascript var ripplePlaneMaterial = new THREE.MeshBasicMaterial( { map: rippleRenderTarget.texture } ); var ripplePlaneGeometry = new THREE.PlaneGeometry( window.innerWidth, window.innerHeight ); var ripplePlane = new THREE.Mesh( ripplePlaneGeometry, ripplePlaneMaterial ); scene.add( ripplePlane ); var rippleCamera = ...; // 创建相机 var rippleRenderer = new THREE.WebGLRenderer(); rippleRenderer.setSize( window.innerWidth, window.innerHeight ); rippleRenderer.setRenderTarget( rippleRenderTarget ); rippleRenderer.render( rippleScene, rippleCamera ); ``` 5. 在循环渲染中更新ShaderMaterial的uniform变量,并重新渲染波纹RenderTarget。 ```javascript function animate() { requestAnimationFrame( animate ); rippleMaterial.uniforms.time.value += 0.1; rippleRenderer.setRenderTarget( rippleRenderTarget ); rippleRenderer.render( rippleScene, rippleCamera ); rippleRenderer.setRenderTarget( null ); renderer.render( scene, camera ); } ``` 6. 在ShaderMaterial的vertexShader和fragmentShader中实现波纹效果的计算。 vertexShader: ```glsl uniform float time; varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); // 计算波纹效果 float frequency = 10.0; float amplitude = 0.2; float speed = 1.0; vec3 pos = position; pos.z += sin( pos.x * frequency + time * speed ) * amplitude; pos.z += sin( pos.y * frequency + time * speed ) * amplitude; gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 ); } ``` fragmentShader: ```glsl uniform sampler2D depthTexture; uniform sampler2D rippleTexture; uniform vec2 resolution; varying vec2 vUv; void main() { // 获取深度信息 float depth = texture2D( depthTexture, vUv ).r; // 获取波纹信息 float ripple = texture2D( rippleTexture, vUv ).g; // 根据深度和波纹信息计算出颜色 vec3 color = vec3( depth * ripple ); gl_FragColor = vec4( color, 1.0 ); } ``` 这样就可以在模型实现波纹效果了。具体实现可以参考以下示例代码: https://codepen.io/wanbo/pen/XWpXzjV

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值