3.js - 变形动画 - 优化

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
import gsap from 'gsap' // 导入动画库

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(0, 0, 40)
scene.add(camera)

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true

const ambientLight = new THREE.AmbientLight(0xffffff, 1)
scene.add(ambientLight)

// -----------------------------------------------------------------------

const gltfLoader = new GLTFLoader()
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('../public/draco/')
`
  解码器的配置,指定解码器的类型为'js',即:JavaScript解码器
  Draco也支持WebAssembly(Wasm)解码器,
  这里,我们选择JavaScript版本。`
dracoLoader.setDecoderConfig({ type: 'js' })
`
  预加载解码器,
  将Draco加载器,与,GLTF加载器,结合使用之前,
  需要预加载解码器,
  因为,解码器可能需要一些时间从网络加载,并且我们希望,它在模型加载之前就已经准备好了。`
dracoLoader.preload()
gltfLoader.setDRACOLoader(dracoLoader)


let stem = null // 茎
let stem_1 = null // 茎
let stem_2 = null // 茎
let petal = null // 花瓣
let petal_1 = null // 花瓣
let petal_2 = null // 花瓣

let params = { value_0: 0,value_1: 0  }

gltfLoader.load('../public/assets/model-19/f4.glb', gltf_1 => {
	    // console.log('gltf_1=', gltf_1)
	    stem = gltf_1.scene.children[0]
	    petal = gltf_1.scene.children[1]
	    gltf_1.scene.rotation.x = Math.PI

	    // 遍历,gltf.scene中的所有对象
	    gltf_1.scene.traverse(item => {
		        // 水
		        if (item.material && item.material.name == 'Water') {
		            // item.scale.set(0.5, 0.5, 0.5) // 缩放比例,设置为0.8(在三个维度上)
		            item.material = new THREE.MeshStandardMaterial({
		                color: 'red',
		                // side: THREE.DoubleSide,
		                transparent: true,
		                opacity: 0.7,
		                depthWrite: false,
		                depthTest: false
		            })
		        }
	
		        // 茎
		        if (item.material && item.material.name == 'Stem') {
		            stem = item
		        }
	
		        // 花瓣
		        if (item.material && item.material.name == 'Petal') {
		            petal = item
		        }
	    })

	    gltfLoader.load('../public/assets/model-19/f2.glb', gltf_2 => {
		        gltf_2.scene.traverse(item => {
		            // 茎
		            if (item.material && item.material.name == 'Stem') {
		                stem_1 = item
		                stem.geometry.morphAttributes.position = [stem_1.geometry.attributes.position]
		                stem.updateMorphTargets()
		            }
		
		            // 花苞
		            if (item.material && item.material.name == 'Petal') {
		                petal_1 = item
		                petal.geometry.morphAttributes.position = [petal_1.geometry.attributes.position]
		                petal.updateMorphTargets()
		            }
		
		            // 开花
		            gltfLoader.load('../public/assets/model-19/f1.glb', gltf => {
		                gltf.scene.traverse(item => {
		                    if (item.material && item.material.name == 'Stem') {
		                        stem_2 = item
		                        stem.geometry.morphAttributes.position.push(stem_2.geometry.attributes.position)
		                        stem.updateMorphTargets()
		                    }
		
		                    if (item.material && item.material.name == 'Petal') {
		                        petal_2 = item
		                        petal.geometry.morphAttributes.position.push(petal_2.geometry.attributes.position)
		                        petal.updateMorphTargets()
		                    }
		                })
		            })
		        }) 'end - gltf_2.scene.traverse'
	
		        gsap.to(params, {
		            value_0: 1,
		            duration: 4, // 持续时间
		            delay: 0, // 延迟时间
		            /* onUpdate:在动画的每一帧被调用,意味着,随着动画的进行,这个函数会不断执行。*/
		            onUpdate: () => {
		                petal.morphTargetInfluences[0] = params.value_0 // 更改,花瓣的权重
		                stem.morphTargetInfluences[0] = params.value_0 // 更改,茎的权重
		            },
		            // onComplete:动画完成时调用,在这个函数中,启动了另一个gsap动画
		            onComplete: () => {
		                gsap.to(params, {
		                    value_1: 1,
		                    duration: 4,
		                    delay: 1, // 延迟时间
		                    onUpdate: function () {
		                        stem.morphTargetInfluences[1] = params.value_1
		                        petal.morphTargetInfluences[1] = params.value_1
		                    }
		                })
		            }
		        }) 'end - gsap'
	    })

	    scene.add(gltf_1.scene)
})

//#region --------------------- 看看用到的这几个gltf模型长什么样 ---------------------

// 短的,茎,花苞
gltfLoader.load('../public/assets/model-19/f4.glb', gltf => {
    // console.log('gltf=', gltf)
    gltf.scene.position.x = 10
    gltf.scene.rotation.x = Math.PI
    scene.add(gltf.scene)
})

// 长的,茎,花苞
gltfLoader.load('../public/assets/model-19/f2.glb', gltf => {
    // console.log('gltf=', gltf)
    gltf.scene.position.x = 20
    gltf.scene.rotation.x = Math.PI
    scene.add(gltf.scene)
})

// 长的茎,开的花
gltfLoader.load('../public/assets/model-19/f1.glb', gltf => {
	// console.log('gltf=', gltf)
	gltf.scene.position.x = 30
	gltf.scene.rotation.x = Math.PI
	scene.add(gltf.scene)
})

//#endregion --------------------- 看看用到的这几个gltf模型长什么样 ---------------------


//#region renderer
const renderer = new THREE.WebGLRenderer({
	antialias: true,
	logarithmicDepthBuffer: true // 启用对数深度缓冲区,有助于减少在深度测试中常见的z-fighting问题,特别是在处理远距离物体时
})
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true // 阴影
renderer.physicallyCorrectLights = true // 物理光照效果
// 设置电影渲染模式
renderer.toneMapping = THREE.ACESFilmicToneMapping
` 
  设置,渲染器输出的颜色编码方式为:sRGB方式,
  sRGB编码:一种非线性的颜色空间,更接近于人眼对亮度的感知方式,更加准确和自然。`
renderer.outputEncoding = THREE.sRGBEncoding
`
  禁用自动清除,每次渲染调用之前,渲染器不会自动清除其颜色、深度、模板缓冲区,
  这在,想要在某些帧上,保留前一帧的内容时非常有用,
  如:实现某些类型的累积效果,或自定义渲染流程。`
renderer.autoClear = false
`
  渲染器的对象排序功能:
		渲染器会根据,对象到摄像机的距离,来排序场景中的对象,并且,先渲染较远的对象,再渲染较近的对象。
			有助于减少由于深度测试引起的渲染问题,如z-fighting(深度冲突),
			并且,可能提高渲染性能,因为,早期深度测试,可以更早地拒绝被遮挡的像素。
		缺点:
			对象排序,可能会增加渲染前的处理时间,可能不适用于所有场景,
			特别是,当场景中有大量透明对象,或复杂的层叠关系时,简单的距离排序可能不足以解决问题,甚至可能引入新的问题。`
renderer.sortObjects = true
`
  将webgl渲染的canvas内容添加到body`
document.body.appendChild(renderer.domElement)
//#endregion

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true

function render() {
	controls.update()
	renderer.render(scene, camera)
	requestAnimationFrame(render)
}
render()

window.addEventListener('resize', () => {
	// 重置相机的宽高比
	camera.aspect = window.innerWidth / window.innerHeight
	// 更新相机的投影矩阵
	camera.updateProjectionMatrix()
	// 重置渲染器的宽高比
	renderer.setSize(window.innerWidth, window.innerHeight)
	// 更新渲染器的像素比
	renderer.setPixelRatio(window.devicePixelRatio)
})

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值