Skip to content

Commit 6ea315d

Browse files
author
Thayer J Andrews
committed
CCEffectBloom - Fix threshold math
When applying the luminance threshold, don't check the luminance of the blurred result pixel and instead check the luminance of the inputs to the blur operation. If the luminance of an input falls below the threshold just use black as the input instead. Because the threshold happens before the blur, the boundaries of the thresholded areas are still nicely blurred. Doing the threshold after the blur results in hard boundaries that don't achieve the effect we want. Note that the addition of the luminance calculation and the step() function does have a negative performance impact. We're going with this implementation for now but this is an argument for supporting multiple shaders / implementations per-effect. With multiple implementations, we could select one that does not pay the performance penalty for the threshold check if it's not needed.
1 parent 3453c29 commit 6ea315d

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

cocos2d/CCEffectBloom.m

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,27 @@ -(void)buildFragmentFunctions
169169

170170
[shaderString appendString:@"if(u_enableGlowMap == 0.0) {\n"];
171171

172+
[shaderString appendString:@"const vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n"];
173+
[shaderString appendString:@"vec4 srcPixel; float luminanceCheck;\n"];
174+
172175
// Inner texture loop
173-
[shaderString appendFormat:@"src += texture2D(cc_PreviousPassTexture, v_blurCoordinates[0]) * %f;\n", standardGaussianWeights[0]];
176+
[shaderString appendFormat:@"srcPixel = texture2D(cc_PreviousPassTexture, v_blurCoordinates[0]);\n"];
177+
[shaderString appendString:@"luminanceCheck = step(u_luminanceThreshold, dot(srcPixel.rgb, luminanceWeighting));\n"];
178+
[shaderString appendFormat:@"src += luminanceCheck * srcPixel * %f;\n", standardGaussianWeights[0]];
174179

175180
for (NSUInteger currentBlurCoordinateIndex = 0; currentBlurCoordinateIndex < numberOfOptimizedOffsets; currentBlurCoordinateIndex++)
176181
{
177182
GLfloat firstWeight = standardGaussianWeights[currentBlurCoordinateIndex * 2 + 1];
178183
GLfloat secondWeight = standardGaussianWeights[currentBlurCoordinateIndex * 2 + 2];
179184
GLfloat optimizedWeight = firstWeight + secondWeight;
180-
181-
[shaderString appendFormat:@"src += texture2D(cc_PreviousPassTexture, v_blurCoordinates[%lu]) * %f;\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 1), optimizedWeight];
182-
[shaderString appendFormat:@"src += texture2D(cc_PreviousPassTexture, v_blurCoordinates[%lu]) * %f;\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 2), optimizedWeight];
185+
186+
[shaderString appendFormat:@"srcPixel = texture2D(cc_PreviousPassTexture, v_blurCoordinates[%lu]);\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 1)];
187+
[shaderString appendString:@"luminanceCheck = step(u_luminanceThreshold, dot(srcPixel.rgb, luminanceWeighting));\n"];
188+
[shaderString appendFormat:@"src += luminanceCheck * srcPixel * %f;\n", optimizedWeight];
189+
190+
[shaderString appendFormat:@"srcPixel = texture2D(cc_PreviousPassTexture, v_blurCoordinates[%lu]);\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 2)];
191+
[shaderString appendString:@"luminanceCheck = step(u_luminanceThreshold, dot(srcPixel.rgb, luminanceWeighting));\n"];
192+
[shaderString appendFormat:@"src += luminanceCheck * srcPixel * %f;\n", optimizedWeight];
183193
}
184194

185195
// If the number of required samples exceeds the amount we can pass in via varyings, we have to do dependent texture reads in the fragment shader
@@ -194,16 +204,17 @@ -(void)buildFragmentFunctions
194204

195205
GLfloat optimizedWeight = firstWeight + secondWeight;
196206
GLfloat optimizedOffset = (firstWeight * (currentOverlowTextureRead * 2 + 1) + secondWeight * (currentOverlowTextureRead * 2 + 2)) / optimizedWeight;
197-
198-
[shaderString appendFormat:@"src += texture2D(cc_PreviousPassTexture, v_blurCoordinates[0] + singleStepOffset * %f) * %f;\n", optimizedOffset, optimizedWeight];
199-
[shaderString appendFormat:@"src += texture2D(cc_PreviousPassTexture, v_blurCoordinates[0] - singleStepOffset * %f) * %f;\n", optimizedOffset, optimizedWeight];
207+
208+
[shaderString appendFormat:@"srcPixel = texture2D(cc_PreviousPassTexture, v_blurCoordinates[0] + singleStepOffset * %f);\n", optimizedOffset];
209+
[shaderString appendString:@"luminanceCheck = step(u_luminanceThreshold, dot(srcPixel.rgb, luminanceWeighting));\n"];
210+
[shaderString appendFormat:@"src += luminanceCheck * srcPixel * %f;\n", optimizedWeight];
211+
212+
[shaderString appendFormat:@"srcPixel = texture2D(cc_PreviousPassTexture, v_blurCoordinates[0] - singleStepOffset * %f);\n", optimizedOffset];
213+
[shaderString appendString:@"luminanceCheck = step(u_luminanceThreshold, dot(srcPixel.rgb, luminanceWeighting));\n"];
214+
[shaderString appendFormat:@"src += luminanceCheck * srcPixel * %f;\n", optimizedWeight];
200215
}
201216
}
202217

203-
[shaderString appendString:@"const vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n\
204-
float luminance = dot(src.rgb, luminanceWeighting);\n\
205-
if(luminance < u_luminanceThreshold)\n discard;\n"];
206-
207218
[shaderString appendString:@"} else {\n"];
208219
[shaderString appendString:@"\
209220
dst = texture2D(cc_MainTexture, cc_FragTexCoord1);\
@@ -328,7 +339,7 @@ -(void)buildRenderPasses
328339

329340
pass.shaderUniforms[CCShaderUniformPreviousPassTexture] = previousPassTexture;
330341
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_enableGlowMap"]] = [NSNumber numberWithFloat:0.0f];
331-
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_luminanceThreshold"]] = [NSNumber numberWithFloat:_luminanceThreshold];
342+
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_luminanceThreshold"]] = [NSNumber numberWithFloat:0.0f];
332343
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_intensity"]] = [NSNumber numberWithFloat:_transformedIntensity];
333344

334345
GLKVector2 dur = GLKVector2Make(0.0, 1.0 / (previousPassTexture.pixelHeight / previousPassTexture.contentScale));
@@ -344,7 +355,7 @@ -(void)buildRenderPasses
344355

345356
pass.shaderUniforms[CCShaderUniformPreviousPassTexture] = previousPassTexture;
346357
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_enableGlowMap"]] = [NSNumber numberWithFloat:1.0f];
347-
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_luminanceThreshold"]] = [NSNumber numberWithFloat:_luminanceThreshold];
358+
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_luminanceThreshold"]] = [NSNumber numberWithFloat:0.0f];
348359
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_intensity"]] = [NSNumber numberWithFloat:_transformedIntensity];
349360

350361
} copy]];

0 commit comments

Comments
 (0)