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/[email protected]',
    //     (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/[email protected]',
    //             (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/[email protected]',
    //                     (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/[email protected]',
        (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/[email protected]',
                (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/[email protected]',
                        (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)

你可能感兴趣的:(前端,javascript,开发语言)