Three.js中Multiply等三种混合模式失效显示白方块问题排查
问题描述
使用Three.js实现粒子效果时,切换至MultiplyBlending、SubtractiveBlending、NoBlending三种混合模式时,粒子显示为白方块;但使用AdditiveBlending时显示正常。相关代码如下:
片元着色器
uniform sampler2D diffuseTexture; varying vec4 vColor; varying vec2 vAngle; void main() { vec2 coords = (gl_PointCoord - 0.5) * mat2(vAngle.x, vAngle.y, -vAngle.y, vAngle.x) + 0.5; gl_FragColor = texture2D(diffuseTexture, coords) * vColor; }
顶点着色器
uniform float pointMultiplier; attribute float size; attribute float angle; varying vec4 vColor; varying vec2 vAngle; void main() { vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * mvPosition; gl_PointSize = size * pointMultiplier / gl_Position.w; vAngle = vec2(cos(angle), sin(angle)); vColor = color; }
TypeScript实现代码
this.material = new Three.ShaderMaterial({ uniforms: { diffuseTexture: { value: new Three.TextureLoader().load(basicParticle) }, pointMultiplier: { value: window.innerHeight / (2.0 * Math.tan(0.5 * 60.0 * Math.PI / 180.0)) } }, vertexShader, fragmentShader, blending: Three.MultiplyBlending, depthTest: true, depthWrite: false, transparent: true, vertexColors: true }); this.geometry = new Three.BufferGeometry(); new Three.Points(this.geometry, this.material);
问题原因与修复方案
核心原因
- 缺失关键顶点属性数据:顶点着色器依赖
size、angle、color三个attribute,但提供的代码中仅创建了空的BufferGeometry,未填充这些属性的具体数据。GPU读取未初始化的垃圾值后,不同混合模式对异常数值的容错性不同,导致非Additive模式下渲染异常。 - 混合模式与透明设置不兼容:
MultiplyBlending/SubtractiveBlending下,transparent: true启用的alpha混合逻辑与默认混合因子不匹配,若纹理或顶点颜色异常,会直接输出白色。NoBlending模式下开启transparent: true属于冗余设置,会触发不必要的alpha处理,引发渲染错误。
- 未处理纹理透明区域:片元着色器未对纹理的透明区域做丢弃处理,透明区域的异常值参与混合后可能导致白色方块。
修复步骤
1. 补全BufferGeometry的顶点属性
必须为position、size、angle、color添加有效数据,示例代码:
const particleCount = 100; // 粒子数量 // 创建数据数组 const positions = new Float32Array(particleCount * 3); const sizes = new Float32Array(particleCount); const angles = new Float32Array(particleCount); const colors = new Float32Array(particleCount * 3); // 填充粒子数据 for (let i = 0; i < particleCount; i++) { // 随机位置 positions[i * 3] = Math.random() * 10 - 5; positions[i * 3 + 1] = Math.random() * 10 - 5; positions[i * 3 + 2] = Math.random() * 10 - 5; // 随机大小 sizes[i] = Math.random() * 20 + 10; // 随机旋转角度 angles[i] = Math.random() * Math.PI * 2; // 随机颜色 colors[i * 3] = Math.random(); colors[i * 3 + 1] = Math.random(); colors[i * 3 + 2] = Math.random(); } // 将数据添加到BufferGeometry this.geometry.setAttribute('position', new Three.BufferAttribute(positions, 3)); this.geometry.setAttribute('size', new Three.BufferAttribute(sizes, 1)); this.geometry.setAttribute('angle', new Three.BufferAttribute(angles, 1)); this.geometry.setAttribute('color', new Three.BufferAttribute(colors, 3));
2. 调整混合模式对应的材质配置
MultiplyBlending/SubtractiveBlending:
保持transparent: true,可显式指定匹配的混合因子,并启用纹理预乘alpha:const texture = new Three.TextureLoader().load(basicParticle); texture.premultiplyAlpha = true; // 开启预乘alpha,适配混合逻辑 this.material = new Three.ShaderMaterial({ uniforms: { diffuseTexture: { value: texture }, pointMultiplier: { value: window.innerHeight / (2.0 * Math.tan(0.5 * 60.0 * Math.PI / 180.0)) } }, vertexShader, fragmentShader, blending: Three.MultiplyBlending, // 或SubtractiveBlending blendSrc: Three.SrcAlpha, blendDst: Three.OneMinusSrcAlpha, depthTest: true, depthWrite: false, transparent: true, vertexColors: true });NoBlending:
关闭transparent,开启深度写入:this.material = new Three.ShaderMaterial({ uniforms: { diffuseTexture: { value: new Three.TextureLoader().load(basicParticle) }, pointMultiplier: { value: window.innerHeight / (2.0 * Math.tan(0.5 * 60.0 * Math.PI / 180.0)) } }, vertexShader, fragmentShader, blending: Three.NoBlending, depthTest: true, depthWrite: true, transparent: false, vertexColors: true });
3. 优化片元着色器的透明处理
添加alpha测试,丢弃完全透明的片元,避免异常值参与渲染:
uniform sampler2D diffuseTexture; varying vec4 vColor; varying vec2 vAngle; void main() { vec2 coords = (gl_PointCoord - 0.5) * mat2(vAngle.x, vAngle.y, -vAngle.y, vAngle.x) + 0.5; vec4 texColor = texture2D(diffuseTexture, coords); // 丢弃透明区域,阈值可根据纹理调整 if (texColor.a < 0.1) discard; gl_FragColor = texColor * vColor; }
内容的提问来源于stack exchange,提问作者Get Off My Lawn
相关产品推荐
相关产品推荐

