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 axesHelper = new THREE.AxesHelper(5)
// scene.add(axesHelper)

// hdr环境纹理
// const rgbeLoader = new RGBELoader()
// rgbeLoader.load('../public/assets/texture/038.hdr', texture => {
//   texture.mapping = THREE.EquirectangularReflectionMapping
//   scene.background = texture
//   scene.environment = texture
// })

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 => {
    // console.log('gltf=', gltf)
    gltf.scene.rotation.x = Math.PI

    // 遍历,gltf.scene中的所有对象
    gltf.scene.traverse(item => {
        `【水】`
        if (item.material && item.material.name == 'Water') {
            // console.log('item=', item)
            // 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 => {
                // console.log('gltf=', gltf)
                gltf.scene.traverse(item => {
                    if (item.material && item.material.name == 'Petal') {
                        petal_1 = item
                        console.log('petal_1=', petal_1)
                        // console.log('petal_1.geometry.attributes.position=', petal_1.geometry.attributes.position)

                        `1、检查,petal.geometry 是否有 morphAttributes.position数组,若没有,则初始化一个空数组。(morphAttributes:形态属性。)`
                        if (!petal.geometry.morphAttributes.position) {
                            petal.geometry.morphAttributes.position = []
                        }

                        `2、将,petal_1 的顶点位置,赋值给,petal 的morphAttributes.position数组的第一个元素
                            	  实际上,是将,petal_1 的顶点位置,作为一个形态目标,添加到 petal 上。`
                        petal.geometry.morphAttributes.position[0] = petal_1.geometry.attributes.position

                        `3、更新 petal 的形态目标,这一步是必需的,以确保Three.js能够正确地处理新添加的形态目标。`
                        petal.updateMorphTargets()
                        
                        `4、将,第一个形态目标的权重设置为1,
		                       		意味着,petal 将完全采用这个形态目标(即:petal1 的形状)
                            【morphTargetInfluences】是一个数组,用于控制一个模型(如:Three.js中的Mesh)的多个形态目标的权重,
        	                        通过改变这些权重,可以平滑地过渡到一个模型的多个形态之间。`
                        petal.morphTargetInfluences[0] = 1
                        
                        打印查看,petal,的`morphTargetInfluences`数组【这个数组,定义了,每个形态目标的权重】
                        console.log('petal.morphTargetInfluences=', petal.morphTargetInfluences)

                        console.log('petal.geometry.morphAttributes=', petal.geometry.morphAttributes)

                        gsap.to(params, {
                            value_0: 1,
                            duration: 10, 【持续时间】
                            delay: 0, 【延迟时间】
                            `onUpdate:在动画的每一帧被调用,意味着,随着动画的进行,这个函数会不断执行。`
                            onUpdate: function () {
                                petal.morphTargetInfluences[0] = params.value_0 // 更改,花瓣的权重
                                stem.morphTargetInfluences[0] = params.value_0 // 更改,茎的权重
                            }
                        })
                    }

                    if (item.material && item.material.name == 'Stem') {
                        stem_1 = item
                        if (!stem.geometry.morphAttributes.position) {
                          stem.geometry.morphAttributes.position = []
                        }
                        stem.geometry.morphAttributes.position[0] = stem_1.geometry.attributes.position
                        stem.updateMorphTargets()
                        stem.morphTargetInfluences[0] = 1
                    }
                })
            })  `【花苞】- 结束`

            `【开花】- 开始`
            gltfLoader.load('../public/assets/model-19/f1.glb', gltf => {
                gltf.scene.traverse(item => {
                    if (item.material && item.material.name == 'Petal') {
                        petal_2 = item

                        petal.geometry.morphAttributes.position[1] = petal_2.geometry.attributes.position
                        petal.updateMorphTargets()
                        petal.morphTargetInfluences[1] = 0

                        gsap.to(params, {
                            value_1: 1,
                            duration: 10,
                            delay: 10,
                            // repeat: -1, // 无线循环
                            onUpdate: function () {
                                // console.log(petal.morphTargetInfluences)
                                // console.log(stem.morphTargetInfluences)
                                petal.morphTargetInfluences[0] = params.value_0
                                stem.morphTargetInfluences[0] = params.value_0
                                petal.morphTargetInfluences[1] = params.value_1
                                stem.morphTargetInfluences[1] = params.value_1
                            }
                        })
                    }

                    if (item.material && item.material.name == 'Stem') {
                        stem_2 = item

                        stem.geometry.morphAttributes.position[1] = stem_2.geometry.attributes.position
                        stem.updateMorphTargets()
                        stem.morphTargetInfluences[1] = 0
                    }
                })
            })  `【开花】- 结束`
        }  `【花瓣】- 结束`
    })

    scene.add(gltf.scene)
})



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

gltfLoader.load('../public/assets/model-19/f4.glb', gltf => {
	// console.log('gltf=', gltf)
	gltf.scene.position.y = -20
	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.y = -20
	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.y = -20
	gltf.scene.position.x = 30
	gltf.scene.rotation.x = Math.PI
	scene.add(gltf.scene)
})

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

const renderer = new THREE.WebGLRenderer({
	antialias: true,
	`启用【对数深度缓冲区】有助于减少在深度测试中常见的【z-fighting问题】,特别是在处理远距离物体时`
	logarithmicDepthBuffer: true
})
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true // 阴影效果
renderer.physicallyCorrectLights = true // 开启物理光照效果
// renderer.setClearColor(0xcccccc, 1) // 设置背景颜色
/* 禁用自动清除,每次渲染调用之前,渲染器不会自动清除其颜色、深度和模板缓冲区
    这在,想要在某些帧上,保留前一帧的内容时非常有用,
    比如:实现某些类型的累积效果,或自定义渲染流程。*/
renderer.autoClear = false `和【renderer.autoClear = false】配合使用`

renderer.toneMapping = THREE.ACESFilmicToneMapping // 设置电影渲染模式

`渲染器输出的颜色编码方式为:sRGB方式`(sRGB编码:一种非线性的颜色空间,更接近于人眼对亮度的感知方式,更准确自然)
renderer.outputEncoding = THREE.sRGBEncoding

/* 启用,渲染器的对象排序功能,
        渲染器,会根据对象到摄像机的距离,来排序场景中的对象,
        并且,先渲染较远的对象,再渲染较近的对象。
        有助于,减少由于深度测试引起的渲染问题,如z-fighting(深度冲突),
        并且,可能提高渲染性能,因为,早期深度测试,可以更早地拒绝被遮挡的像素。

  缺点: 需要注意的是,
        对象排序,可能会增加渲染前的处理时间,可能不适用于所有场景。
        特别是,当场景中有大量透明对象,或复杂的层叠关系时,简单的距离排序可能不足以解决问题,甚至可能引入新的问题。*/
renderer.sortObjects = true
// 启用对数深度缓冲区,有助于减少在深度测试中常见的z-fighting问题,特别是在处理远距离物体时。
renderer.logarithmicDepthBuffer = true
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)

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

const clock = new THREE.Clock()
const render = ()=>{
	let time = clock.getElapsedTime()
	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、付费专栏及课程。

余额充值