Three.js + WebXR环境下GLB文件动画无法播放求助
问题:Three.js + WebXR环境中GLB模型动画无法播放
我在Three.js + WebXR环境中加载了包含1个动画片段的GLB模型,模型可正常显示,但动画无法播放。该模型在Three.js编辑器中动画播放正常,恳请技术帮助!
import { Mesh, AmbientLight, Clock, AnimationMixer, PerspectiveCamera, Scene, WebGLRenderer, MeshBasicMaterial, RingGeometry, sRGBEncoding } from 'three'; import {ARButton} from 'three/examples/jsm/webxr/ARButton'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js' class App { constructor() { this.clock = new Clock(); this.camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.camera.position.set(0, 1.6, 3); this.scene = new Scene(); this.renderer = new WebGLRenderer({ antialias: true, alpha: true }); this.renderer.setPixelRatio(window.devicePixelRatio); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.outputEncoding = sRGBEncoding; document.body.appendChild(this.renderer.domElement); this.initXR(); this.initScene(); window.addEventListener('resize', this.onWindowResize.bind(this), false); this.renderer.setAnimationLoop(this.render.bind(this)); } initXR() { this.renderer.xr.enabled = true; document.body.appendChild(ARButton.createButton(this.renderer, {requiredFeatures: ['hit-test']})); this.hitTestSourceRequested = false; this.hitTestSource = null; this.controller = this.renderer.xr.getController(0); this.controller.addEventListener('select', this.onSelect.bind(this)); } initScene() { let geometry = new RingGeometry(0.08, 0.10, 32).rotateX(-Math.PI / 2); let material = new MeshBasicMaterial(); this.reticle = new Mesh(geometry, material); this.reticle.matrixAutoUpdate = false; this.reticle.visible = false; this.scene.add(this.reticle); const loader = new GLTFLoader(); loader.load('./models/stylized_character.glb', gltf => { this.myObj = gltf; gltf.scene.scale.set(.25, .25, .25); gltf.scene.visible = true; this.scene.add(gltf.scene); //todo: this doesnt seem to work this.mixer = new AnimationMixer(gltf); var action = this.mixer.clipAction(gltf.animations[0]); action.play(); }); var aLight = new AmbientLight(0xffffff, 1); this.scene.add(aLight) } render(_, frame) { const delta = this.clock.getDelta(); if (this.mixer) { this.mixer.update(delta); } if (frame) { if (this.hitTestSourceRequested === false) { this.requestHitTestSource(); } if (this.hitTestSource) { this.getHitTestResults(frame); } } this.renderer.render(this.scene, this.camera); } onWindowResize() { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.render(this.scene, this.camera); } onSelect() { if (this.reticle.visible) { this.myObj.scene.position.setFromMatrixPosition(this.reticle.matrix); this.myObj.scene.visible = true; } } async requestHitTestSource() { const session = this.renderer.xr.getSession(); session.addEventListener('end', () => { this.hitTestSourceRequested = false; this.hitTestSource = null; }); const referenceSpace = await session.requestReferenceSpace('viewer'); this.hitTestSource = await session.requestHitTestSource({space: referenceSpace, entityTypes: ['plane']}); this.hitTestSourceRequested = true; } getHitTestResults(frame) { const hitTestResults = frame.getHitTestResults(this.hitTestSource); if (hitTestResults.length) { const hit = hitTestResults[0]; const pose = hit.getPose(this.renderer.xr.getReferenceSpace()); this.reticle.visible = true; this.reticle.matrix.fromArray(pose.transform.matrix); } else { this.reticle.visible = false; } } } window.addEventListener('DOMContentLoaded', () => { new App(); });
解决方案
核心问题是AnimationMixer的初始化参数错误,它需要接收模型的场景对象而非完整的GLTF加载结果对象。
步骤1:修正AnimationMixer初始化
将原代码中的:
this.mixer = new AnimationMixer(gltf);
修改为:
this.mixer = new AnimationMixer(gltf.scene);
步骤2:可选优化(XR环境下的计时准确性)
WebXR环境中,使用frame.getDeltaTime()能获取更精准的帧间隔,替换render方法中的delta获取逻辑:
render(_, frame) { const delta = frame ? frame.getDeltaTime() : this.clock.getDelta(); if (this.mixer) { this.mixer.update(delta); } // ...其余代码保持不变 }
验证动画片段存在性
可以在GLTF加载回调中添加日志,确认动画片段是否被正确加载:
loader.load('./models/stylized_character.glb', gltf => { console.log('加载到的动画片段:', gltf.animations); // ...其余代码 });
内容的提问来源于stack exchange,提问作者Ryan Granlund
相关产品推荐
相关产品推荐

