UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

33 lines (30 loc) 3.87 kB
import { RenderPassShaderQuad } from '../../scene/graphics/render-pass-shader-quad.js'; import { ChunkUtils } from '../../scene/shader-lib/chunk-utils.js'; /** * Render pass implementation of a depth-aware bilateral blur filter. * * @category Graphics * @ignore */ class RenderPassDepthAwareBlur extends RenderPassShaderQuad { execute() { this.filterSizeId.setValue(4); this.sourceTextureId.setValue(this.sourceTexture); var { width, height } = this.sourceTexture; this.sourceInvResolutionValue[0] = 1.0 / width; this.sourceInvResolutionValue[1] = 1.0 / height; this.sourceInvResolutionId.setValue(this.sourceInvResolutionValue); super.execute(); } constructor(device, sourceTexture, cameraComponent, horizontal){ super(device); this.sourceTexture = sourceTexture; var screenDepth = ChunkUtils.getScreenDepthChunk(device, cameraComponent.shaderParams); this.shader = this.createQuadShader("DepthAware" + (horizontal ? 'Horizontal' : 'Vertical') + "BlurShader", /* glsl */ screenDepth + "\n\n " + (horizontal ? '#define HORIZONTAL' : '') + "\n\n varying vec2 uv0;\n\n uniform sampler2D sourceTexture;\n uniform vec2 sourceInvResolution;\n uniform int filterSize;\n\n float random(const highp vec2 w) {\n const vec3 m = vec3(0.06711056, 0.00583715, 52.9829189);\n return fract(m.z * fract(dot(w, m.xy)));\n }\n\n mediump float bilateralWeight(in mediump float depth, in mediump float sampleDepth) {\n mediump float diff = (sampleDepth - depth);\n return max(0.0, 1.0 - diff * diff);\n }\n\n void tap(inout float sum, inout float totalWeight, float weight, float depth, vec2 position) {\n\n mediump float color = texture2D(sourceTexture, position).r;\n mediump float textureDepth = -getLinearScreenDepth(position);\n \n mediump float bilateral = bilateralWeight(depth, textureDepth);\n\n bilateral *= weight;\n sum += color * bilateral;\n totalWeight += bilateral;\n }\n\n // TODO: weights of 1 are used for all samples. Test with gaussian weights\n void main() {\n\n // handle the center pixel separately because it doesn't participate in bilateral filtering\n mediump float depth = -getLinearScreenDepth(uv0);\n mediump float totalWeight = 1.0;\n mediump float color = texture2D(sourceTexture, uv0 ).r;\n mediump float sum = color * totalWeight;\n\n for (mediump int i = -filterSize; i <= filterSize; i++) {\n mediump float weight = 1.0;\n\n #ifdef HORIZONTAL\n vec2 offset = vec2(i, 0) * sourceInvResolution;\n #else\n vec2 offset = vec2(0, i) * sourceInvResolution;\n #endif\n\n tap(sum, totalWeight, weight, depth, uv0 + offset);\n }\n\n mediump float ao = sum / totalWeight;\n\n // simple dithering helps a lot (assumes 8 bits target)\n // this is most useful with high quality/large blurs\n // ao += ((random(gl_FragCoord.xy) - 0.5) / 255.0);\n\n gl_FragColor.r = ao;\n }\n "); var scope = this.device.scope; this.sourceTextureId = scope.resolve('sourceTexture'); this.sourceInvResolutionId = scope.resolve('sourceInvResolution'); this.sourceInvResolutionValue = new Float32Array(2); this.filterSizeId = scope.resolve('filterSize'); } } export { RenderPassDepthAwareBlur };