GLTF动画

在本课中,我们将创建与 FBX 动画课程中创建的项目等效的 GLTF模型

我们使用Blender将主要的FBX模型及其相关的动画文件转换为GLB文件。

资源

如果您不想使用Blender将文件转换为视频中所示的文件,则可以直接下载它们并保存到fbxglb./dist/client/models

可使用GLTF编辑器预览、编辑这几个模型。

启动脚本

./src/client/client.ts

import * as THREE from 'three'

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

import Stats from 'three/examples/jsm/libs/stats.module'

import { GUI } from 'dat.gui'

const scene = new THREE.Scene()

scene.add(new THREE.AxesHelper(5))

const light1 = new THREE.PointLight(0xffffff, 100)

light1.position.set(2.5, 2.5, 2.5)

scene.add(light1)

const light2 = new THREE.PointLight(0xffffff, 100)

light2.position.set(-2.5, 2.5, 2.5)

scene.add(light2)

const camera = new THREE.PerspectiveCamera(

75,

window.innerWidth / window.innerHeight,

0.1,

1000

)

camera.position.set(0.8, 1.4, 1.0)

const renderer = new THREE.WebGLRenderer()

renderer.setSize(window.innerWidth, window.innerHeight)

document.body.appendChild(renderer.domElement)

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

controls.enableDamping = true

controls.target.set(0, 1, 0)

let mixer: THREE.AnimationMixer

let modelReady = false

const animationActions: THREE.AnimationAction[] = []

let activeAction: THREE.AnimationAction

let lastAction: THREE.AnimationAction

const gltfLoader = new GLTFLoader()

gltfLoader.load(

'models/vanguard.glb',

(gltf) => {

// gltf.scene.scale.set(.01, .01, .01)

    mixer = new THREE.AnimationMixer(gltf.scene)

    const animationAction = mixer.clipAction((gltf as any).animations[0])
    animationActions.push(animationAction)
    animationsFolder.add(animations, 'default')
    activeAction = animationActions[0]

    scene.add(gltf.scene)

    // //add an animation from another file
    // gltfLoader.load(
    //     'models/vanguard@samba.glb',
    //     (gltf) => {
    //         console.log('loaded samba')
    //         const animationAction = mixer.clipAction(
    //             (gltf as any).animations[0]
    //         )
    //         animationActions.push(animationAction)
    //         animationsFolder.add(animations, 'samba')

    //         //add an animation from another file
    //         gltfLoader.load(
    //             'models/vanguard@bellydance.glb',
    //             (gltf) => {
    //                 console.log('loaded bellydance')
    //                 const animationAction = mixer.clipAction(
    //                     (gltf as any).animations[0]
    //                 )
    //                 animationActions.push(animationAction)
    //                 animationsFolder.add(animations, 'bellydance')

    //                 //add an animation from another file
    //                 gltfLoader.load(
    //                     'models/vanguard@goofyrunning.glb',
    //                     (gltf) => {
    //                         console.log('loaded goofyrunning');
    //                         (gltf as any).animations[0].tracks.shift() //delete the specific track that moves the object forward while running
    //                         const animationAction = mixer.clipAction(
    //                             (gltf as any).animations[0]
    //                         )
    //                         animationActions.push(animationAction)
    //                         animationsFolder.add(animations, 'goofyrunning')

    //                         modelReady = true
    //                     },
    //                     (xhr) => {
    //                         console.log(
    //                             (xhr.loaded / xhr.total) * 100 + '% loaded'
    //                         )
    //                     },
    //                     (error) => {
    //                         console.log(error)
    //                     }
    //                 )
    //             },
    //             (xhr) => {
    //                 console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    //             },
    //             (error) => {
    //                 console.log(error)
    //             }
    //         )
    //     },
    //     (xhr) => {
    //         console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    //     },
    //     (error) => {
    //         console.log(error)
    //     }
    // )
},
(xhr) => {
    console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
    console.log(error)
}

)

window.addEventListener('resize', onWindowResize, false)

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight

camera.updateProjectionMatrix()

renderer.setSize(window.innerWidth, window.innerHeight)

render()

}

const stats = new Stats()

document.body.appendChild(stats.dom)

const animations = {

default: function () {

setAction(animationActions[0])

},

samba: function () {

setAction(animationActions[1])

},

bellydance: function () {

setAction(animationActions[2])

},

goofyrunning: function () {

setAction(animationActions[3])

},

}

const setAction = (toAction: THREE.AnimationAction) => {

if (toAction != activeAction) {

lastAction = activeAction

activeAction = toAction
//lastAction.stop()

lastAction.fadeOut(1)

activeAction.reset()

activeAction.fadeIn(1)

activeAction.play()

}

}

const gui = new GUI()

const animationsFolder = gui.addFolder('Animations')

animationsFolder.open()

const clock = new THREE.Clock()

function animate() {

requestAnimationFrame(animate)

controls.update()

if (modelReady) mixer.update(clock.getDelta())

render()

stats.update()

}

function render() {

renderer.render(scene, camera)

}

animate()

最终脚本

./src/client/client.ts

import * as THREE from 'three'

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

import Stats from 'three/examples/jsm/libs/stats.module'

import { GUI } from 'dat.gui'

const scene = new THREE.Scene()

scene.add(new THREE.AxesHelper(5))

const light1 = new THREE.PointLight(0xffffff, 1000)

light1.position.set(2.5, 2.5, 2.5)

scene.add(light1)

const light2 = new THREE.PointLight(0xffffff, 1000)

light2.position.set(-2.5, 2.5, 2.5)

scene.add(light2)

const camera = new THREE.PerspectiveCamera(

75,

window.innerWidth / window.innerHeight,

0.1,

1000

)

camera.position.set(0.8, 1.4, 1.0)

const renderer = new THREE.WebGLRenderer()

renderer.setSize(window.innerWidth, window.innerHeight)

document.body.appendChild(renderer.domElement)

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

controls.enableDamping = true

controls.target.set(0, 1, 0)

let mixer: THREE.AnimationMixer

let modelReady = false

const animationActions: THREE.AnimationAction[] = []

let activeAction: THREE.AnimationAction

let lastAction: THREE.AnimationAction

const gltfLoader = new GLTFLoader()

gltfLoader.load(

'models/vanguard.glb',

(gltf) => {

// gltf.scene.scale.set(.01, .01, .01)

    mixer = new THREE.AnimationMixer(gltf.scene)

    const animationAction = mixer.clipAction((gltf as any).animations[0])
    animationActions.push(animationAction)
    animationsFolder.add(animations, 'default')
    activeAction = animationActions[0]

    scene.add(gltf.scene)

    //add an animation from another file
    gltfLoader.load(
        'models/vanguard@samba.glb',
        (gltf) => {
            console.log('loaded samba')
            const animationAction = mixer.clipAction(
                (gltf as any).animations[0]
            )
            animationActions.push(animationAction)
            animationsFolder.add(animations, 'samba')

            //add an animation from another file
            gltfLoader.load(
                'models/vanguard@bellydance.glb',
                (gltf) => {
                    console.log('loaded bellydance')
                    const animationAction = mixer.clipAction(
                        (gltf as any).animations[0]
                    )
                    animationActions.push(animationAction)
                    animationsFolder.add(animations, 'bellydance')

                    //add an animation from another file
                    gltfLoader.load(
                        'models/vanguard@goofyrunning.glb',
                        (gltf) => {
                            console.log('loaded goofyrunning')
                            ;(gltf as any).animations[0].tracks.shift() //delete the specific track that moves the object forward while running
                            const animationAction = mixer.clipAction(
                                (gltf as any).animations[0]
                            )
                            animationActions.push(animationAction)
                            animationsFolder.add(animations, 'goofyrunning')

                            modelReady = true
                        },
                        (xhr) => {
                            console.log(
                                (xhr.loaded / xhr.total) * 100 + '% loaded'
                            )
                        },
                        (error) => {
                            console.log(error)
                        }
                    )
                },
                (xhr) => {
                    console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
                },
                (error) => {
                    console.log(error)
                }
            )
        },
        (xhr) => {
            console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
        },
        (error) => {
            console.log(error)
        }
    )
},
(xhr) => {
    console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
    console.log(error)
}

)

window.addEventListener('resize', onWindowResize, false)

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight

camera.updateProjectionMatrix()

renderer.setSize(window.innerWidth, window.innerHeight)

render()

}

const stats = new Stats()

document.body.appendChild(stats.dom)

const animations = {

default: function () {

setAction(animationActions[0])

},

samba: function () {

setAction(animationActions[1])

},

bellydance: function () {

setAction(animationActions[2])

},

goofyrunning: function () {

setAction(animationActions[3])

},

}

const setAction = (toAction: THREE.AnimationAction) => {

if (toAction != activeAction) {

lastAction = activeAction

activeAction = toAction
//lastAction.stop()

lastAction.fadeOut(1)

activeAction.reset()

activeAction.fadeIn(1)

activeAction.play()

}

}

const gui = new GUI()

const animationsFolder = gui.addFolder('Animations')

animationsFolder.open()

const clock = new THREE.Clock()

function animate() {

requestAnimationFrame(animate)

controls.update()

if (modelReady) mixer.update(clock.getDelta())

render()

stats.update()

}

function render() {

renderer.render(scene, camera)

}

animate()

原文链接:GLTF动画 (mvrlink.com)

相关推荐
qq_3643717225 分钟前
Vue 内置组件 keep-alive 中 LRU 缓存淘汰策略和实现
前端·vue.js·缓存
y先森1 小时前
CSS3中的弹性布局之侧轴的对齐方式
前端·css·css3
Elihuss1 小时前
ONVIF协议操作摄像头方法
开发语言·php
Swift社区5 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
new出一个对象5 小时前
uniapp接入BMapGL百度地图
javascript·百度·uni-app
没头脑的ht5 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht5 小时前
Swift闭包的本质
开发语言·ios·swift
wjs20245 小时前
Swift 数组
开发语言
你挚爱的强哥6 小时前
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
javascript·vue.js·jquery
stm 学习ing6 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga