Three.js开启Bloom泛光时PNG贴图Sprite显示异常如何解决
Three.js UnrealBloomPass 下PNG贴图Sprite正常显示方案
核心原因
现有分层Bloom实现的暗化逻辑仅判断了对象的isMesh属性,Three.js中Sprite对象的类型标识为isSprite,未被纳入暗化处理范围,导致Bloom渲染阶段Sprite贴图被泛光效果覆盖,出现显示异常。
落地方案
方案1:补全暗化逻辑的类型覆盖(改造成本最低)
- 修改场景遍历的判断条件,从仅匹配
isMesh调整为同时匹配obj.isMesh || obj.isSprite,覆盖Sprite类型对象 - 提前初始化纯黑色的
SpriteMaterial作为Sprite的暗化替换材质,注意将材质的transparent属性设为true,适配PNG贴图的透明通道 - 遍历替换材质时先缓存对象的原始材质,待UnrealBloomPass渲染流程完成后,再遍历所有对象恢复原始材质即可
- 核心逻辑代码参考:
// 提前初始化暗化材质 const darkMeshMat = new THREE.MeshBasicMaterial({ color: 0x000000 }); const darkSpriteMat = new THREE.SpriteMaterial({ color: 0x000000, transparent: true }); // Bloom渲染前的暗化遍历 scene.traverse(obj => { if (obj.isMesh || obj.isSprite) { // 非泛光层对象替换为暗化材质 if (!obj.layers.test(bloomTargetLayer)) { obj.userData.originMat = obj.material; obj.material = obj.isMesh ? darkMeshMat : darkSpriteMat; } } }); // 执行完BloomPass渲染后,恢复原材质 scene.traverse(obj => { if (obj.userData.originMat) { obj.material = obj.userData.originMat; delete obj.userData.originMat; } });
方案2:平面网格模拟Sprite(复用现有逻辑无需额外适配)
如果不想修改现有暗化逻辑,可以直接用平面网格替代原生Sprite,实现完全一致的效果:
- 用
PlaneGeometry搭配加载了PNG贴图的MeshBasicMaterial替代原Sprite对象 - 在每帧渲染调用前,执行
planeMesh.lookAt(camera.position),即可实现平面始终朝向相机,和原生Sprite的表现完全一致,满足标签类使用需求 - 该方案下平面属于Mesh类型,原有针对Mesh的暗化逻辑可以直接生效,无需额外调整
避坑说明
- 不要尝试仅通过图层隔离跳过Sprite的暗化处理:UnrealBloomPass默认会读取全场景的渲染结果,未做暗化处理的非泛光层Sprite会被泛光计算覆盖原有颜色,无法正常显示
- 暗化用的SpriteMaterial不要绑定原贴图,保持纯黑即可,避免残留贴图内容干扰Bloom的亮度计算结果
内容的提问来源于stack exchange,提问作者jImmy
相关产品推荐
相关产品推荐

