diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index a846906bcbb19169b5598281158ab593d3d9d19b..9cb5fa513bebca3ea4d65335db9fb29f7752b4d0 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -428,6 +428,15 @@ namespace Canvas3D { p.ambientOcclusion.radius = props.ambientOcclusion.radius ValueCell.update(ssaoPass.values.uRadius, props.ambientOcclusion.radius) } + + if (props.ambientOcclusion.edgeScale !== undefined) { + p.ambientOcclusion.edgeScale = props.ambientOcclusion.edgeScale + ValueCell.update(ssaoPass.values.uEdgeScale, props.ambientOcclusion.edgeScale * webgl.pixelRatio) + } + if (props.ambientOcclusion.edgeThreshold !== undefined) { + p.ambientOcclusion.edgeThreshold = props.ambientOcclusion.edgeThreshold + ValueCell.update(ssaoPass.values.uEdgeThreshold, props.ambientOcclusion.edgeThreshold) + } } if (props.renderer) renderer.setProps(props.renderer) diff --git a/src/mol-canvas3d/passes/ssao-pass.ts b/src/mol-canvas3d/passes/ssao-pass.ts index 91a6dd0fb67b8b52a25e3c3e9d03e37298d46e60..23dd4ee451df33d9587d0f6439c3ee7701cf39e2 100644 --- a/src/mol-canvas3d/passes/ssao-pass.ts +++ b/src/mol-canvas3d/passes/ssao-pass.ts @@ -25,6 +25,9 @@ const SSAOPassSchema = { uKernelSize: UniformSpec('i'), uBias: UniformSpec('f'), uRadius: UniformSpec('f'), + + uEdgeScale: UniformSpec('f'), + uEdgeThreshold: UniformSpec('f'), } export const SSAOPassParams = { @@ -32,6 +35,9 @@ export const SSAOPassParams = { kernelSize: PD.Numeric(4, { min: 1, max: 100, step: 1 }), bias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }), radius: PD.Numeric(128, { min: 0, max: 256, step: 1 }), + + edgeScale: PD.Numeric(1, { min: 0, max: 10, step: 1 }), + edgeThreshold: PD.Numeric(0.8, { min: 0, max: 1, step: 0.01 }), } export type SSAOPassProps = PD.Values<typeof SSAOPassParams> @@ -47,6 +53,9 @@ export function getSSAOPassRenderable(ctx: WebGLContext, colorTexture: Texture, uKernelSize: ValueCell.create(p.kernelSize), uBias: ValueCell.create(p.bias), uRadius: ValueCell.create(p.radius), + + uEdgeScale: ValueCell.create(p.edgeScale * ctx.pixelRatio), + uEdgeThreshold: ValueCell.create(p.edgeThreshold), } const schema = { ...SSAOPassSchema } diff --git a/src/mol-gl/shader/passes/ssao.frag b/src/mol-gl/shader/passes/ssao.frag index bbef5eba021b17e6bcf5f261c8d88f0765977e2e..0c46b26e3e4ee1003b536fe86bb55642cb64674d 100644 --- a/src/mol-gl/shader/passes/ssao.frag +++ b/src/mol-gl/shader/passes/ssao.frag @@ -11,6 +11,9 @@ uniform int uKernelSize; uniform float uBias; uniform float uRadius; +uniform float uEdgeScale; +uniform float uEdgeThreshold; + const float noiseAmount = 0.0002; float noise(vec2 coords) { @@ -31,13 +34,34 @@ float calcSSAO(in vec2 coords, in float depth) { vec2 coordsDelta = coords + uRadius / float(uKernelSize) * vec2(float(i) / uTexSize.x, float(j) / uTexSize.y); coordsDelta += noiseAmount * (noise(coordsDelta) - 0.5) / uTexSize; coordsDelta = clamp(coordsDelta, 0.5 / uTexSize, 1.0 - 1.0 / uTexSize); - if (texture(tDepth, coordsDelta).r < depth) occlusionFactor += 1.0; + if (texture2D(tDepth, coordsDelta).r < depth) occlusionFactor += 1.0; } } return occlusionFactor / float((2 * uKernelSize + 1) * (2 * uKernelSize + 1)); } +float calcEdgeDepth(in vec2 coords) { + vec2 invTexSize = 1.0 / uTexSize; + float halfScaleFloor = floor(uEdgeScale * 0.5); + float halfScaleCeil = ceil(uEdgeScale * 0.5); + + vec2 bottomLeftUV = coords - invTexSize * halfScaleFloor; + vec2 topRightUV = coords + invTexSize * halfScaleCeil; + vec2 bottomRightUV = coords + vec2(invTexSize.x * halfScaleCeil, -invTexSize.y * halfScaleFloor); + vec2 topLeftUV = coords + vec2(-invTexSize.x * halfScaleFloor, invTexSize.y * halfScaleCeil); + + float depth0 = texture2D(tDepth, bottomLeftUV).r; + float depth1 = texture2D(tDepth, topRightUV).r; + float depth2 = texture2D(tDepth, bottomRightUV).r; + float depth3 = texture2D(tDepth, topLeftUV).r; + + float depthFiniteDifference0 = depth1 - depth0; + float depthFiniteDifference1 = depth3 - depth2; + + return sqrt(pow(depthFiniteDifference0, 2.0) + pow(depthFiniteDifference1, 2.0)) * 100.0; +} + void main(void) { vec2 coords = gl_FragCoord.xy / uTexSize; vec4 color = texture(tColor, coords); @@ -48,6 +72,8 @@ void main(void) { float occlusionFactor = calcSSAO(coords, depth); color = mix(color, vec4(0.0, 0.0, 0.0, 1.0), uBias * occlusionFactor); } + + color.rgb *= (step(calcEdgeDepth(coords), uEdgeThreshold)); gl_FragColor = color; } \ No newline at end of file