• 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)

    1. mixer = new THREE.AnimationMixer(gltf.scene)
    2. const animationAction = mixer.clipAction((gltf as any).animations[0])
    3. animationActions.push(animationAction)
    4. animationsFolder.add(animations, 'default')
    5. activeAction = animationActions[0]
    6. scene.add(gltf.scene)
    7. // //add an animation from another file
    8. // gltfLoader.load(
    9. // 'models/vanguard@samba.glb',
    10. // (gltf) => {
    11. // console.log('loaded samba')
    12. // const animationAction = mixer.clipAction(
    13. // (gltf as any).animations[0]
    14. // )
    15. // animationActions.push(animationAction)
    16. // animationsFolder.add(animations, 'samba')
    17. // //add an animation from another file
    18. // gltfLoader.load(
    19. // 'models/vanguard@bellydance.glb',
    20. // (gltf) => {
    21. // console.log('loaded bellydance')
    22. // const animationAction = mixer.clipAction(
    23. // (gltf as any).animations[0]
    24. // )
    25. // animationActions.push(animationAction)
    26. // animationsFolder.add(animations, 'bellydance')
    27. // //add an animation from another file
    28. // gltfLoader.load(
    29. // 'models/vanguard@goofyrunning.glb',
    30. // (gltf) => {
    31. // console.log('loaded goofyrunning');
    32. // (gltf as any).animations[0].tracks.shift() //delete the specific track that moves the object forward while running
    33. // const animationAction = mixer.clipAction(
    34. // (gltf as any).animations[0]
    35. // )
    36. // animationActions.push(animationAction)
    37. // animationsFolder.add(animations, 'goofyrunning')
    38. // modelReady = true
    39. // },
    40. // (xhr) => {
    41. // console.log(
    42. // (xhr.loaded / xhr.total) * 100 + '% loaded'
    43. // )
    44. // },
    45. // (error) => {
    46. // console.log(error)
    47. // }
    48. // )
    49. // },
    50. // (xhr) => {
    51. // console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    52. // },
    53. // (error) => {
    54. // console.log(error)
    55. // }
    56. // )
    57. // },
    58. // (xhr) => {
    59. // console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    60. // },
    61. // (error) => {
    62. // console.log(error)
    63. // }
    64. // )
    65. },
    66. (xhr) => {
    67. console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    68. },
    69. (error) => {
    70. console.log(error)
    71. }

    )

    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)

    1. controls.update()
    2. if (modelReady) mixer.update(clock.getDelta())
    3. render()
    4. 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)

    1. mixer = new THREE.AnimationMixer(gltf.scene)
    2. const animationAction = mixer.clipAction((gltf as any).animations[0])
    3. animationActions.push(animationAction)
    4. animationsFolder.add(animations, 'default')
    5. activeAction = animationActions[0]
    6. scene.add(gltf.scene)
    7. //add an animation from another file
    8. gltfLoader.load(
    9. 'models/vanguard@samba.glb',
    10. (gltf) => {
    11. console.log('loaded samba')
    12. const animationAction = mixer.clipAction(
    13. (gltf as any).animations[0]
    14. )
    15. animationActions.push(animationAction)
    16. animationsFolder.add(animations, 'samba')
    17. //add an animation from another file
    18. gltfLoader.load(
    19. 'models/vanguard@bellydance.glb',
    20. (gltf) => {
    21. console.log('loaded bellydance')
    22. const animationAction = mixer.clipAction(
    23. (gltf as any).animations[0]
    24. )
    25. animationActions.push(animationAction)
    26. animationsFolder.add(animations, 'bellydance')
    27. //add an animation from another file
    28. gltfLoader.load(
    29. 'models/vanguard@goofyrunning.glb',
    30. (gltf) => {
    31. console.log('loaded goofyrunning')
    32. ;(gltf as any).animations[0].tracks.shift() //delete the specific track that moves the object forward while running
    33. const animationAction = mixer.clipAction(
    34. (gltf as any).animations[0]
    35. )
    36. animationActions.push(animationAction)
    37. animationsFolder.add(animations, 'goofyrunning')
    38. modelReady = true
    39. },
    40. (xhr) => {
    41. console.log(
    42. (xhr.loaded / xhr.total) * 100 + '% loaded'
    43. )
    44. },
    45. (error) => {
    46. console.log(error)
    47. }
    48. )
    49. },
    50. (xhr) => {
    51. console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    52. },
    53. (error) => {
    54. console.log(error)
    55. }
    56. )
    57. },
    58. (xhr) => {
    59. console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    60. },
    61. (error) => {
    62. console.log(error)
    63. }
    64. )
    65. },
    66. (xhr) => {
    67. console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    68. },
    69. (error) => {
    70. console.log(error)
    71. }

    )

    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)

    1. controls.update()
    2. if (modelReady) mixer.update(clock.getDelta())
    3. render()
    4. stats.update()

    }

    function render() {
    renderer.render(scene, camera)
    }

    animate()

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

  • 相关阅读:
    win10 docker .vhdx 文件过大
    Java多线程-简单使用Lock(锁)
    Matlab 如何计算正弦信号的幅值和初始相角
    jQuery效果演示
    循环队列c语言版
    Understanding Entity Relationship Behaviors in Microsoft Dynamics 365/CRM
    【SpringMVC】参数传递与用户请求和响应
    百度程序员:进来看看这个代码,值T几的水平?丨黑马头条
    线性反馈移位寄存器的输出(未解出)
    java培训Lock接口里的实现方法
  • 原文地址:https://blog.csdn.net/ygtu2018/article/details/132999343