diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts index bfb01c7f51ad921e5eb2eb82846a0e5d3abeee2d..ab2b06dad0aadb4e9af05d4c67ff6554d836773b 100644 --- a/src/mol-canvas3d/passes/postprocessing.ts +++ b/src/mol-canvas3d/passes/postprocessing.ts @@ -79,6 +79,7 @@ const ShadowsSchema = { uProjection: UniformSpec('m4'), uInvProjection: UniformSpec('m4'), + uBounds: UniformSpec('v4'), dOrthographic: DefineSpec('number'), uNear: UniformSpec('f'), @@ -106,6 +107,7 @@ function getShadowsRenderable(ctx: WebGLContext, depthTexture: Texture): Shadows uProjection: ValueCell.create(Mat4.identity()), uInvProjection: ValueCell.create(Mat4.identity()), + uBounds: ValueCell.create(Vec4()), dOrthographic: ValueCell.create(0), uNear: ValueCell.create(1), @@ -501,13 +503,14 @@ export class PostprocessingPass { const invProjection = Mat4.identity(); Mat4.invert(invProjection, camera.projection); + const [w, h] = this.renderable.values.uTexSize.ref.value; + const v = camera.viewport; + if (props.occlusion.name === 'on') { ValueCell.update(this.ssaoRenderable.values.uProjection, camera.projection); ValueCell.update(this.ssaoRenderable.values.uInvProjection, invProjection); - const [w, h] = this.renderable.values.uTexSize.ref.value; const b = this.ssaoRenderable.values.uBounds; - const v = camera.viewport; const s = this.ssaoScale; Vec4.set(b.ref.value, Math.floor(v.x * s) / (w * s), @@ -583,6 +586,14 @@ export class PostprocessingPass { ValueCell.update(this.shadowsRenderable.values.uProjection, camera.projection); ValueCell.update(this.shadowsRenderable.values.uInvProjection, invProjection); + Vec4.set(this.shadowsRenderable.values.uBounds.ref.value, + v.x / w, + v.y / h, + (v.x + v.width) / w, + (v.y + v.height) / h + ); + ValueCell.update(this.shadowsRenderable.values.uBounds, this.shadowsRenderable.values.uBounds.ref.value); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near); ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far); ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic); diff --git a/src/mol-gl/shader/postprocessing.frag.ts b/src/mol-gl/shader/postprocessing.frag.ts index 720bd65e3a0aa99d5ebcd42423ac30ae99743717..d41cb9449bea753a2ea3d4f35421acd938d9272d 100644 --- a/src/mol-gl/shader/postprocessing.frag.ts +++ b/src/mol-gl/shader/postprocessing.frag.ts @@ -125,7 +125,7 @@ void main(void) { if (!isBackground(opaqueDepth)) { viewDist = abs(getViewZ(opaqueDepth)); fogFactor = smoothstep(uFogNear, uFogFar, viewDist); - vec4 shadow = texture2D(tShadows, coords + uOcclusionOffset); + vec4 shadow = texture2D(tShadows, coords); if (!uTransparentBackground) { color.rgb = mix(mix(vec3(0), uFogColor, fogFactor), color.rgb, shadow.a); } else { diff --git a/src/mol-gl/shader/shadows.frag.ts b/src/mol-gl/shader/shadows.frag.ts index 1963b2148fcb7a7bf1ce69d453f6b3c733c275a0..fb79dcc5794d749f3ac202f96c21ab93b477bfb6 100644 --- a/src/mol-gl/shader/shadows.frag.ts +++ b/src/mol-gl/shader/shadows.frag.ts @@ -14,6 +14,7 @@ precision highp sampler2D; uniform sampler2D tDepth; uniform vec2 uTexSize; +uniform vec4 uBounds; uniform float uNear; uniform float uFar; @@ -34,7 +35,11 @@ bool isBackground(const in float depth) { return depth == 1.0; } -float getViewZ(in float depth) { +bool outsideBounds(const in vec2 p) { + return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w; +} + +float getViewZ(const in float depth) { #if dOrthographic == 1 return orthographicDepthToViewZ(depth, uNear, uFar); #else @@ -50,8 +55,13 @@ float getDepth(const in vec2 coords) { #endif } +float screenFade(const in vec2 coords) { + vec2 fade = max(12.0 * abs(coords - 0.5) - 5.0, vec2(0.0)); + return saturate(1.0 - dot(fade, fade)); +} + // based on https://panoskarabelas.com/posts/screen_space_shadows/ -float screenSpaceShadow(in vec2 coords, in vec3 position, in vec3 lightDirection, in float stepLength) { +float screenSpaceShadow(const in vec3 position, const in vec3 lightDirection, const in float stepLength) { // Ray position and direction (in view-space) vec3 rayPos = position; vec3 rayDir = -lightDirection; @@ -66,23 +76,27 @@ float screenSpaceShadow(in vec2 coords, in vec3 position, in vec3 lightDirection // Step the ray rayPos += rayStep; - // Compute the difference between the ray's and the camera's depth rayCoords = uProjection * vec4(rayPos, 1.0); rayCoords.xyz = (rayCoords.xyz / rayCoords.w) * 0.5 + 0.5; + + if (outsideBounds(rayCoords.xy)) + return 1.0; + + // Compute the difference between the ray's and the camera's depth float depth = getDepth(rayCoords.xy); float viewZ = getViewZ(depth); float zDelta = rayPos.z - viewZ; if (zDelta < uTolerance) { occlusion = 1.0; + + // Fade out as we approach the edges of the screen + occlusion *= screenFade(rayCoords.xy); + break; } } - // Fade out as we approach the edges of the screen - vec2 fade = max(12.0 * abs(rayCoords.xy - 0.5) - 5.0, vec2(0.0)); - occlusion *= saturate(1.0 - dot(fade, fade)); - return 1.0 - (uBias * occlusion); } @@ -105,7 +119,7 @@ void main(void) { float sh[dLightCount]; #pragma unroll_loop_start for (int i = 0; i < dLightCount; ++i) { - sh[i] = screenSpaceShadow(selfCoords, selfViewPos, uLightDirection[i], stepLength); + sh[i] = screenSpaceShadow(selfViewPos, uLightDirection[i], stepLength); o = min(o, sh[i]); } #pragma unroll_loop_end