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)
},(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)
},(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)
版权声明: 本文为 InfoQ 作者【3D建模设计】的原创文章。
原文链接:【http://xie.infoq.cn/article/52258ce831e58217436607e12】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论