Three.js中如何判断场景是否完全加载渲染完成?
解决Three.js中判断所有对象与精灵完全加载并就绪的方案
嗨,针对你遇到的场景加载判断问题,我整理了几个实用的方案,帮你准确捕捉到所有对象加载完成、精灵纹理调整完毕且场景渲染就绪的时机:
1. 用LoadingManager统一管控所有加载流程
Three.js自带的LoadingManager是管理所有资源加载的核心工具,它能监听**所有加载器(TextureLoader、GLTFLoader等)**的加载开始、进度和完成事件。哪怕精灵纹理因为非2幂尺寸被自动调整,这个调整过程也是在纹理加载完成后同步执行的,所以当LoadingManager的onLoad回调触发时,意味着所有资源(包括调整后的精灵纹理)都已准备就绪。
示例代码:
// 创建全局加载管理器 const loadingManager = new THREE.LoadingManager(); // 所有加载器都关联这个管理器 const textureLoader = new THREE.TextureLoader(loadingManager); const objectLoader = new THREE.ObjectLoader(loadingManager); // 监听全部加载完成事件 loadingManager.onLoad = function() { console.log("所有资源加载完成,精灵纹理已调整完毕!"); // 这里可以执行场景就绪后的逻辑,比如隐藏加载动画 }; // 加载你的300个对象和30个精灵资源 // 比如加载精灵纹理: const spriteTextures = []; for (let i = 0; i < 30; i++) { textureLoader.load(`sprite_${i}.png`, (texture) => { spriteTextures.push(texture); // 创建精灵并添加到场景 const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: texture })); scene.add(sprite); }); }
2. 监听精灵纹理的onUpdate事件追踪调整完成
如果需要单独确认精灵纹理的调整是否完成,可以给每个精灵的纹理绑定onUpdate事件——当Three.js自动调整纹理大小后,这个事件会被触发。你可以通过计数的方式,确认所有精灵纹理都完成调整:
示例代码:
let resizedSpriteCount = 0; const totalSprites = 30; function handleSpriteTextureUpdate() { resizedSpriteCount++; if (resizedSpriteCount === totalSprites) { console.log("所有精灵纹理已完成大小调整!"); // 结合加载完成事件,就能确认整个场景就绪 } } // 加载精灵时绑定事件 textureLoader.load('sprite.png', (texture) => { texture.onUpdate = handleSpriteTextureUpdate; const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: texture })); scene.add(sprite); });
3. 结合渲染帧确认场景完全渲染
有时候资源加载完成后,还需要等待至少一帧的渲染才能确保所有对象在场景中可见且动画正常运行。你可以在加载完成的回调中,通过requestAnimationFrame等待下一帧,或者监听渲染器的渲染循环:
示例代码:
loadingManager.onLoad = function() { // 等待一次渲染完成后再执行逻辑 requestAnimationFrame(() => { console.log("场景已完成首次渲染,所有对象可见且就绪!"); // 这里可以正式启动交互、动画等逻辑 }); };
4. 自定义状态追踪(适合复杂场景)
如果你的场景有动态添加对象的情况,可以给每个对象/精灵添加自定义状态标记,比如isLoaded和isResized,然后在渲染循环中定期检查所有标记的状态:
示例代码:
// 存储所有需要追踪的对象和精灵 const trackedObjects = []; // 创建对象/精灵时添加状态 const sprite = new THREE.Sprite(material); sprite.userData.isLoaded = false; sprite.userData.isResized = false; trackedObjects.push(sprite); // 加载纹理时更新状态 textureLoader.load('sprite.png', (texture) => { sprite.material.map = texture; sprite.userData.isLoaded = true; texture.onUpdate = () => { sprite.userData.isResized = true; }; }); // 在渲染循环中检查状态 function animate() { requestAnimationFrame(animate); const allReady = trackedObjects.every(obj => { return obj.userData.isLoaded && obj.userData.isResized; }); if (allReady) { console.log("所有对象已加载、调整完毕且渲染就绪!"); // 可以移除这个检查逻辑,避免重复执行 animate = () => requestAnimationFrame(animate); } renderer.render(scene, camera); } animate();
额外注意点
- 精灵纹理的尺寸调整是同步执行的,所以只要纹理加载完成,调整就会立刻完成,
onUpdate事件会同步触发(除非你开启了纹理的异步更新,但默认是关闭的)。 - 如果使用了
SpriteMaterial之外的材质,也要确保对应的纹理加载和调整被正确追踪。
内容的提问来源于stack exchange,提问作者LiH
相关产品推荐
相关产品推荐

