// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. // Based on Kawase Dual Filter Blur // https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_slides.pdf CCEffect %{ techniques: - passes: - vert: bloom-vs frag: prefilter-fs pass: cc-bloom-prefilter rasterizerState: cullMode: none depthStencilState: depthTest: false depthWrite: false - vert: bloom-vs frag: downsample-fs pass: cc-bloom-downsample rasterizerState: cullMode: none depthStencilState: depthTest: false depthWrite: false - vert: bloom-vs frag: upsample-fs pass: cc-bloom-upsample rasterizerState: cullMode: none depthStencilState: depthTest: false depthWrite: false - vert: bloom-vs frag: combine-fs pass: cc-bloom-combine rasterizerState: cullMode: none depthStencilState: depthTest: false depthWrite: false blendState: targets: - blend: true blendSrc: one blendDst: one blendSrcAlpha: zero blendDstAlpha: one }% CCProgram bloom-vs %{ precision highp float; #include #include out vec2 v_uv; void main() { StandardVertInput In; CCDecode(In); FLIP_VULKAN_NDC(In.position); gl_Position = In.position; v_uv = a_texCoord; FLIP_SAMPLE_FROM_RT(v_uv); } }% CCProgram prefilter-fs %{ precision highp float; #include in vec2 v_uv; #pragma rate BloomUBO pass uniform BloomUBO { mediump vec4 bloomParams; // x: useHDRIlluminance z: threshold, w: enableAlphaMask }; #pragma rate inputTexture pass uniform sampler2D inputTexture; // hdr input layout(location = 0)out vec4 fragColor; float luminance(vec3 color) { return dot(color, vec3(0.3, 0.5, 0.2)); } void main() { vec4 color = texture(inputTexture, v_uv); float contribute = step(bloomParams.z, luminance(color.rgb)); contribute *= mix(1.0, step(253.0 / 255.0, color.a), bloomParams.w); fragColor = vec4(color.xyz * contribute, 1.0); } }% CCProgram downsample-fs %{ precision highp float; in vec2 v_uv; #pragma rate BloomTexUBO pass uniform BloomTexUBO { mediump vec4 bloomTexSize; // size }; #pragma rate bloomTexture pass uniform sampler2D bloomTexture; layout(location = 0)out vec4 fragColor; #pragma define SAM(uv) texture(bloomTexture, uv).xyz vec3 downsample(vec2 uv, vec2 halfpixel) { // halfpixel is: // 1. half of the pixel size of the output texture // 2. pixel size of the input texture vec3 sum = SAM(uv) * 4.0; sum += SAM(uv - halfpixel.xy); sum += SAM(uv + halfpixel.xy); halfpixel.y = -halfpixel.y; sum += SAM(uv - halfpixel.xy); sum += SAM(uv + halfpixel.xy); return sum / 8.0; } vec3 downsample4taps(vec2 uv, vec2 halfpixel) { vec3 sum = SAM(uv + vec2(-halfpixel.x, halfpixel.y)); sum += SAM(uv + vec2(halfpixel.x, halfpixel.y)); sum += SAM(uv + vec2(halfpixel.x, - halfpixel.y)); sum += SAM(uv + vec2(-halfpixel.x, - halfpixel.y)); return sum / 4.0; } void main() { vec3 result = downsample4taps(v_uv, 1.0 / bloomTexSize.xy).rgb; fragColor = vec4(result, 1.0); } }% CCProgram upsample-fs %{ precision highp float; in vec2 v_uv; #pragma rate BloomTexUBO pass uniform BloomTexUBO { mediump vec4 bloomTexSize; }; #pragma rate bloomTexture pass uniform sampler2D bloomTexture; layout(location = 0)out vec4 fragColor; #pragma define SAM(uv) texture(bloomTexture, uv).xyz vec3 upsample(vec2 uv, vec2 halfpixel) { // halfpixel is: // 1. half of the pixel size of the input texture // 2. pixel size of the output texture vec3 sum = SAM(uv + vec2(-halfpixel.x * 2.0, 0.0)); sum += SAM(uv + vec2(-halfpixel.x, halfpixel.y)) * 2.0; sum += SAM(uv + vec2(0.0, halfpixel.y * 2.0)); sum += SAM(uv + vec2(halfpixel.x, halfpixel.y)) * 2.0; sum += SAM(uv + vec2(halfpixel.x * 2.0, 0.0)); sum += SAM(uv + vec2(halfpixel.x, - halfpixel.y)) * 2.0; sum += SAM(uv + vec2(0.0, - halfpixel.y * 2.0)); sum += SAM(uv + vec2(-halfpixel.x, - halfpixel.y)) * 2.0; return sum / 12.0; } vec3 upsample4taps(vec2 uv, vec2 halfpixel) { vec3 sum = SAM(uv + vec2(-halfpixel.x, halfpixel.y)); sum += SAM(uv + vec2(halfpixel.x, halfpixel.y)); sum += SAM(uv + vec2(halfpixel.x, - halfpixel.y)); sum += SAM(uv + vec2(-halfpixel.x, - halfpixel.y)); return sum / 4.0; } void main() { vec3 result = upsample(v_uv, 0.5 / bloomTexSize.xy).rgb; fragColor = vec4(result, 1.0); } }% CCProgram combine-fs %{ precision highp float; in vec2 v_uv; #pragma rate BloomUBO pass uniform BloomUBO { mediump vec4 bloomParams; // x: useHDRIlluminance z: threshold, w: enableAlphaMask }; #pragma rate bloomTexture pass uniform sampler2D bloomTexture; layout(location = 0)out vec4 fragColor; void main() { vec3 bloomColor = texture(bloomTexture, v_uv).rgb * bloomParams.w; fragColor = vec4(bloomColor, 0); } }%