写点什么

GLTF 动画

作者:3D建模设计
  • 2023-09-18
    湖北
  • 本文字数:5134 字

    阅读完需:约 17 分钟

GLTF动画

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


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


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


Vanguard.glbvanguard@samba.glbvanguard@bellydance.glbvanguard@goofyrunning.glb 可使用 GLTF 编辑器预览、编辑这几个模型。


启动脚本./src/client/client.tsimport * 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 = truecontrols.target.set(0, 1, 0)


let mixer: THREE.AnimationMixerlet modelReady = falseconst animationActions: THREE.AnimationAction[] = []let activeAction: THREE.AnimationActionlet lastAction: THREE.AnimationActionconst 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.innerHeightcamera.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 = activeActionactiveAction = 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.tsimport * 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 = truecontrols.target.set(0, 1, 0)


let mixer: THREE.AnimationMixerlet modelReady = falseconst animationActions: THREE.AnimationAction[] = []let activeAction: THREE.AnimationActionlet lastAction: THREE.AnimationActionconst 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 filegltfLoader.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.innerHeightcamera.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 = activeActionactiveAction = 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)

发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2023-04-14 加入

还未添加个人简介

评论

发布
暂无评论
GLTF动画_3D动画_3D建模设计_InfoQ写作社区