Three morph图形变换实例

基础环境搭建:

在这里插入图片描述

拷贝官方文件夹RobotExpressive至models/gltf文件夹下
导入外部glb文件并在控制台打印出来,添加到场景中:
在这里插入图片描述
在这里插入图片描述

场景背景、地面、雾化及添加网格辅助:

GridHelper:坐标格辅助对象,坐标格实际上是2维线数组。
GridHelper( size : number, divisions : Number, colorCenterLine : Color, colorGrid : Color )

在这里插入图片描述
morph图形变换:

  1. 导入GUI,调用控制面板创建函数:

调用控制面板创建函数:

load回调函数...
        function (gltf) {
            console.log(gltf)
            const model = gltf.scene
            const clips = gltf.animations
            scene.add(model)
            mixer = new THREE.AnimationMixer(model)
            const face = model.getObjectByName('Head_4')
            buildGUI(model, clips, face)
        }
        ...
        function buildGUI(model, clips, face) {
            gui = new GUI()
        }
  1. 面部表情测试:
    console.log(face)
    console.log(face.morphTargetDictionary)
    console.log(face.morphTargetInfluences)
    face.morphTargetInfluences[0] = 1

在这里插入图片描述

  1. 关键变量准备

几个全局变量说明:

let actions = {}  //{'动画片段名1':AnimationAction1,'动画片段名2':AnimationAciton2...}
let activeAction, previousAction  //当前选中的Action动画动作;上个执行的Action动画动作
let activeActionObject = { state: 'Walking' }  //用来操作gui

buildGUI:

    const clipNames = []  //动画片段名列表-动画controller
    for (let i = 0; i < clips.length; i++) {
        const clip = clips[i]
        const action = mixer.clipAction(clip)//->return AnimationAction
        actions[clip.name]=action//->actions={}
        clipNames.push(clip.name)//->clipNames
    }
    activeAction = actions['Walking']
    activeAction.play()
  1. 创建动画选取调试器:

gui.add(object, property, [min], [max], [step])
向GUI添加一个新的控制器,创建的控制器类型是从对象[property]的初始值推断出来的。有关颜色属性,请参见addColor。
Kind: instance method of GUI
Returns: Controller - The controller that was added to the GUI.
在这里插入图片描述
在这里插入图片描述

    const clipFolder = gui.addFolder("动画")
    clipFolder.add(activeActionObject, 'state').options(clipNames).onChange(function () {
        const nextActionName = activeActionObject.state
        fadeToAction(nextActionName, 0.5)   //duratio时间内上个动画片段停止,下个动画片段开始
    })
  1. 动画切换函数:

.fadeIn ( durationInSeconds : Number ) : this
.fadeOut ( durationInSeconds : Number ) : this
在传入的时间间隔内,逐渐将此动作的权重(weight)由0升到1/由1降至0,两方法均可链式调用。

function fadeToAction(nextActionName, duration) {
    previousAction = activeAction
    activeAction = actions[nextActionName]
    if(activeAction!==previousAction){
        previousAction.fadeOut(duration)
    }
    activeAction.reset().fadeIn(duration).play()
}
  1. 创建表情变换调试器:

Object.keys():获得对象上所有可枚举的实例属性。这个方法接受一个对象作为参数,返回包含该对象所有可枚举属性名称的字符串数组。
在这里插入图片描述

    const morphFolder = gui.addFolder('表情')
    const morphNames = Object.keys(faces.morphTargetDictionary)//表情变换名称列表
    for (let i = 0; i < morphNames.length; i++) {
        morphFolder.add(faces.morphTargetInfluences, i, 0, 1, 0.01).name(morphNames[i])
    }
  1. 创建复合动作调试器:
    const states = ['Idle', 'Walking', 'Running', 'Dance', 'Death', 'Sitting', 'Standing']
    const emotes = ['Jump', 'Yes', 'No', 'Wave', 'Punch', 'ThumbsUp']
    const api = {}//{动画片段名:表情切换函数}
    const complexFolder = gui.addFolder('穿插')
    complexFolder.add(activeActionObject, 'state').options(states).onChange(function () {
        const nextActionName = activeActionObject.state
        fadeToAction(nextActionName, 0.5)
    })
    for (let i = 0; i < emotes.length; i++) {
            const name = emotes[i]
            api[name] = function () {
            fadeToAction(name , 0.2)
            mixer.addEventListener('finished', restoreState)
        }
        complexFolder.add(api, emotes[i])
    }
    function restoreState() {
        mixer.removeEventListener('finished', restoreState)
        fadeToAction(activeActionObject.state, 0.2)
    }
  1. buildGUI设置循环播放的动作,以及只播放一次的动作(比如出拳、跳、死亡等,只需要播放一次,没必要重复播放进行)
    const loopActions = ['Idle', 'Walking', 'Running', 'Dance']
    ...
    if (!loopActions.includes(clip.name)) {
        action.clampWhenFinished = true
        action.loop = THREE.LoopOnce
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值