diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b1af7997c7adb668c82012dec8cbece7eb37c92..e95b9b96470cc64e3b5d6c29a5583c4b00bf89bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Add screen-space shadow post-processing effect + ## [v3.25.1] - 2022-11-20 - Fix edge-case in `Structure.eachUnitPair` with single-element units diff --git a/src/apps/docking-viewer/viewport.tsx b/src/apps/docking-viewer/viewport.tsx index 6e59f3c3d685c3b7c930e6ce31bf0532e52dc9d3..d26684d7881a78bc9705f3e0a31094ae8c28f617 100644 --- a/src/apps/docking-viewer/viewport.tsx +++ b/src/apps/docking-viewer/viewport.tsx @@ -31,7 +31,8 @@ function shinyStyle(plugin: PluginContext) { postprocessing: { ...plugin.canvas3d!.props.postprocessing, occlusion: { name: 'off', params: {} }, - outline: { name: 'off', params: {} } + shadow: { name: 'off', params: {} }, + outline: { name: 'off', params: {} }, } } }); } @@ -49,10 +50,8 @@ function occlusionStyle(plugin: PluginContext) { radius: 5, samples: 32, resolutionScale: 1, - shadow: { name: 'off', params: {} }, - closeAO: { name: 'off', params: {} }, - softAO: { name: 'off', params: {} } } }, + shadow: { name: 'off', params: { } }, outline: { name: 'on', params: { scale: 1.0, threshold: 0.33, diff --git a/src/extensions/cellpack/model.ts b/src/extensions/cellpack/model.ts index 77c040b624464d272749754c1ef868f79734889e..45b425eb3606e2aa4fda5a9f8ac2be24791b9167 100644 --- a/src/extensions/cellpack/model.ts +++ b/src/extensions/cellpack/model.ts @@ -604,9 +604,15 @@ export const LoadCellPackModel = StateAction.build({ bias: 1, blurKernelSize: 15, resolutionScale: 1, - shadow: { name: 'off', params: {} }, - softAO: { name: 'off', params: {} }, - closeAO: { name: 'off', params: {} } + } + }, + shadow: { + name: 'on', + params: { + bias: 0.6, + maxDistance: 80, + steps: 1, + tolerance: 1.0, } }, outline: { diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts index cf8e4916c3fa66912258d9896cb9a0be05c80392..11980c1827f753b7b692fe0e714060b67185889b 100644 --- a/src/mol-canvas3d/passes/postprocessing.ts +++ b/src/mol-canvas3d/passes/postprocessing.ts @@ -3,6 +3,7 @@ * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz> + * @author Ludovic Autin <ludovic.autin@gmail.com> */ import { CopyRenderable, createCopyRenderable, QuadSchema, QuadValues } from '../../mol-gl/compute/util'; @@ -31,7 +32,7 @@ import { isTimingMode } from '../../mol-util/debug'; import { BackgroundParams, BackgroundPass } from './background'; import { AssetManager } from '../../mol-util/assets'; import { Light } from '../../mol-gl/renderer'; -// import { debug } from 'console'; +import { shadows_frag } from '../../mol-gl/shader/shadows.frag'; const OutlinesSchema = { ...QuadSchema, @@ -71,6 +72,62 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d return createComputeRenderable(renderItem, values); } +const ShadowsSchema = { + ...QuadSchema, + tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), + uTexSize: UniformSpec('v2'), + + uProjection: UniformSpec('m4'), + uInvProjection: UniformSpec('m4'), + + dOrthographic: DefineSpec('number'), + uNear: UniformSpec('f'), + uFar: UniformSpec('f'), + + dSteps: DefineSpec('number'), + uMaxDistance: UniformSpec('f'), + uTolerance: UniformSpec('f'), + uBias: UniformSpec('f'), + + uLightDirection: UniformSpec('v3[]'), + uLightColor: UniformSpec('v3[]'), + dLightCount: DefineSpec('number'), +}; +type ShadowsRenderable = ComputeRenderable<Values<typeof ShadowsSchema>> + +function getShadowsRenderable(ctx: WebGLContext, depthTexture: Texture): ShadowsRenderable { + const width = depthTexture.getWidth(); + const height = depthTexture.getHeight(); + + const values: Values<typeof ShadowsSchema> = { + ...QuadValues, + tDepth: ValueCell.create(depthTexture), + uTexSize: ValueCell.create(Vec2.create(width, height)), + + uProjection: ValueCell.create(Mat4.identity()), + uInvProjection: ValueCell.create(Mat4.identity()), + + dOrthographic: ValueCell.create(0), + uNear: ValueCell.create(1), + uFar: ValueCell.create(10000), + + dSteps: ValueCell.create(1), + uMaxDistance: ValueCell.create(3.0), + uTolerance: ValueCell.create(1.0), + uBias: ValueCell.create(0.6), + + uLightDirection: ValueCell.create([]), + uLightColor: ValueCell.create([]), + dLightCount: ValueCell.create(0), + }; + + const schema = { ...ShadowsSchema }; + const shaderCode = ShaderCode('shadows', quad_vert, shadows_frag); + const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values); + + return createComputeRenderable(renderItem, values); +} + const SsaoSchema = { ...QuadSchema, tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), @@ -88,34 +145,6 @@ const SsaoSchema = { uRadius: UniformSpec('f'), uBias: UniformSpec('f'), - uCloseAO: UniformSpec('i'), - uCloseBias: UniformSpec('f'), - uCloseDistance: UniformSpec('f'), - - uCDistanceCutoff: UniformSpec('f'), - uCCutoffFalloff: UniformSpec('f'), - uCIntensity: UniformSpec('f'), - uCDistance: UniformSpec('f'), - - uShadow: UniformSpec('i'), - dSSample: DefineSpec('number'), - uSDistance: UniformSpec('f'), - uSTolerance: UniformSpec('f'), - uSBias: UniformSpec('f'), - - uSoftAO: UniformSpec('i'), - uAorange: UniformSpec('f'), - uDepthTolerance: UniformSpec('f'), - uAoMultiplier: UniformSpec('f'), - uAoCap: UniformSpec('f'), - uAScale: UniformSpec('f'), - uARings: UniformSpec('i'), - uASamples: UniformSpec('i'), - - uLightDirection: UniformSpec('v3[]'), - uLightColor: UniformSpec('v3[]'), - dLightCount: DefineSpec('number'), - dOrthographic: DefineSpec('number'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), @@ -138,36 +167,9 @@ function getSsaoRenderable(ctx: WebGLContext, depthTexture: Texture): SsaoRender uTexSize: ValueCell.create(Vec2.create(ctx.gl.drawingBufferWidth, ctx.gl.drawingBufferHeight)), - uLightDirection: ValueCell.create([]), - uLightColor: ValueCell.create([]), - dLightCount: ValueCell.create(0), - uRadius: ValueCell.create(8.0), uBias: ValueCell.create(0.025), - uCloseAO: ValueCell.create(1), - uCloseBias: ValueCell.create(1.0), - uCloseDistance: ValueCell.create(0.01), - uCDistanceCutoff: ValueCell.create(1.0), - uCCutoffFalloff: ValueCell.create(1.0), - uCIntensity: ValueCell.create(1.0), - uCDistance: ValueCell.create(1.0), - - uShadow: ValueCell.create(1), - dSSample: ValueCell.create(1), - uSDistance: ValueCell.create(3.0), - uSTolerance: ValueCell.create(0.2), - uSBias: ValueCell.create(1.5), - - uSoftAO: ValueCell.create(1), - uAorange: ValueCell.create(1.0), - uDepthTolerance: ValueCell.create(1.0), - uAoMultiplier: ValueCell.create(1.0), - uAoCap: ValueCell.create(1.0), - uAScale: ValueCell.create(1.0), - uARings: ValueCell.create(1), - uASamples: ValueCell.create(1), - dOrthographic: ValueCell.create(0), uNear: ValueCell.create(0.0), uFar: ValueCell.create(10000.0), @@ -271,6 +273,7 @@ const PostprocessingSchema = { tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), + tShadows: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), tOutlines: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'), uTexSize: UniformSpec('v2'), @@ -288,6 +291,8 @@ const PostprocessingSchema = { dOcclusionEnable: DefineSpec('boolean'), uOcclusionOffset: UniformSpec('v2'), + dShadowEnable: DefineSpec('boolean'), + dOutlineEnable: DefineSpec('boolean'), dOutlineScale: DefineSpec('number'), uOutlineThreshold: UniformSpec('f'), @@ -298,13 +303,14 @@ const PostprocessingSchema = { }; type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>> -function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable { +function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, shadowsTexture: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable { const values: Values<typeof PostprocessingSchema> = { ...QuadValues, tSsaoDepth: ValueCell.create(ssaoDepthTexture), tColor: ValueCell.create(colorTexture), tDepthOpaque: ValueCell.create(depthTextureOpaque), tDepthTransparent: ValueCell.create(depthTextureTransparent), + tShadows: ValueCell.create(shadowsTexture), tOutlines: ValueCell.create(outlinesTexture), uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())), @@ -322,6 +328,8 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d dOcclusionEnable: ValueCell.create(true), uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)), + dShadowEnable: ValueCell.create(false), + dOutlineEnable: ValueCell.create(false), dOutlineScale: ValueCell.create(1), uOutlineThreshold: ValueCell.create(0.33), @@ -344,43 +352,20 @@ export const PostprocessingParams = { samples: PD.Numeric(32, { min: 1, max: 256, step: 1 }), radius: PD.Numeric(5, { min: 0, max: 10, step: 0.1 }, { description: 'Final occlusion radius is 2^x' }), bias: PD.Numeric(0.8, { min: 0, max: 3, step: 0.1 }), - shadow: PD.MappedStatic('on', { - on: PD.Group({ - sSamples: PD.Numeric(1, { min: 1, max: 20, step: 1 }), - sbias: PD.Numeric(0.8, { min: 0.0, max: 1.0, step: 0.01 }), - sdistance: PD.Numeric(3.0, { min: 0.0, max: 100.0, step: 1.0 }), - stolerance: PD.Numeric(1.0, { min: 0.0, max: 100.0, step: 1.0 }), - }), - off: PD.Group({}) - }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), - closeAO: PD.MappedStatic('on', { - on: PD.Group({ - cbias: PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }), - cradius: PD.Numeric(0.015, { min: 0.0, max: 0.2, step: 0.001 }), - cdistancecutoff: PD.Numeric(2000.0, { min: 0.0, max: 10000.0, step: 1.0 }), - ccutofffalloff: PD.Numeric(25.0, { min: 0.0, max: 10000.0, step: 0.001 }), - cintensity: PD.Numeric(1.0, { min: 0.0, max: 1.0, step: 0.1 }), - cdistance: PD.Numeric(0.0015, { min: 0.0, max: 0.2, step: 0.001 }), - }), - off: PD.Group({}) - }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), - softAO: PD.MappedStatic('on', { - on: PD.Group({ - uAorange: PD.Numeric(160.0, { min: 0.0, max: 500.0, step: 1.0 }), - uDepthTolerance: PD.Numeric(0.0, { min: 0.0, max: 200.0, step: 0.01 }), - uAoMultiplier: PD.Numeric(100.0, { min: 0.0, max: 2000.0, step: 0.01 }), - uAoCap: PD.Numeric(1.0, { min: 0.0, max: 10.0, step: 0.01 }), - uAScale: PD.Numeric(1.0, { min: 0.0, max: 10.0, step: 0.01 }), - uARings: PD.Numeric(6.0, { min: 0.0, max: 10.0, step: 1 }), - uASamples: PD.Numeric(3.0, { min: 0.0, max: 10.0, step: 1 }), - }), - off: PD.Group({}) - }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), blurKernelSize: PD.Numeric(15, { min: 1, max: 25, step: 2 }), resolutionScale: PD.Numeric(1, { min: 0.1, max: 1, step: 0.05 }, { description: 'Adjust resolution of occlusion calculation' }) }), off: PD.Group({}) }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }), + shadow: PD.MappedStatic('off', { + on: PD.Group({ + steps: PD.Numeric(1, { min: 1, max: 20, step: 1 }), + bias: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }), + maxDistance: PD.Numeric(3.0, { min: 0.0, max: 100.0, step: 1.0 }), + tolerance: PD.Numeric(1.0, { min: 0.0, max: 10.0, step: 0.1 }), + }), + off: PD.Group({}) + }, { cycle: true, description: 'Simplistic shadows' }), outline: PD.MappedStatic('off', { on: PD.Group({ scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }), @@ -413,6 +398,9 @@ export class PostprocessingPass { private readonly outlinesTarget: RenderTarget; private readonly outlinesRenderable: OutlinesRenderable; + private readonly shadowsTarget: RenderTarget; + private readonly shadowsRenderable: ShadowsRenderable; + private readonly ssaoFramebuffer: Framebuffer; private readonly ssaoBlurFirstPassFramebuffer: Framebuffer; private readonly ssaoBlurSecondPassFramebuffer: Framebuffer; @@ -458,6 +446,9 @@ export class PostprocessingPass { this.outlinesTarget = webgl.createRenderTarget(width, height, false); this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent); + this.shadowsTarget = webgl.createRenderTarget(width, height, false); + this.shadowsRenderable = getShadowsRenderable(webgl, depthTextureOpaque); + this.ssaoFramebuffer = webgl.resources.framebuffer(); this.ssaoBlurFirstPassFramebuffer = webgl.resources.framebuffer(); this.ssaoBlurSecondPassFramebuffer = webgl.resources.framebuffer(); @@ -481,7 +472,7 @@ export class PostprocessingPass { this.ssaoRenderable = getSsaoRenderable(webgl, this.downsampleFactor === 1 ? depthTextureOpaque : this.downsampledDepthTarget.texture); this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal'); this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical'); - this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture); + this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.shadowsTarget.texture, this.outlinesTarget.texture, this.ssaoDepthTexture); this.background = new BackgroundPass(webgl, assetManager, width, height); } @@ -497,12 +488,14 @@ export class PostprocessingPass { const sh = Math.floor(height * this.ssaoScale); this.target.setSize(width, height); this.outlinesTarget.setSize(width, height); + this.shadowsTarget.setSize(width, height); this.downsampledDepthTarget.setSize(sw, sh); this.ssaoDepthTexture.define(sw, sh); this.ssaoDepthBlurProxyTexture.define(sw, sh); ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.outlinesRenderable.values.uTexSize, Vec2.set(this.outlinesRenderable.values.uTexSize.ref.value, width, height)); + ValueCell.update(this.shadowsRenderable.values.uTexSize, Vec2.set(this.shadowsRenderable.values.uTexSize.ref.value, width, height)); ValueCell.update(this.downsampleDepthRenderable.values.uTexSize, Vec2.set(this.downsampleDepthRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoRenderable.values.uTexSize, Vec2.set(this.ssaoRenderable.values.uTexSize.ref.value, sw, sh)); ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh)); @@ -513,25 +506,20 @@ export class PostprocessingPass { } private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) { + let needsUpdateShadows = false; let needsUpdateMain = false; let needsUpdateSsao = false; let needsUpdateSsaoBlur = false; const orthographic = camera.state.mode === 'orthographic' ? 1 : 0; const outlinesEnabled = props.outline.name === 'on'; + const shadowsEnabled = props.shadow.name === 'on'; const occlusionEnabled = props.occlusion.name === 'on'; + const invProjection = Mat4.identity(); Mat4.invert(invProjection, camera.projection); if (props.occlusion.name === 'on') { - const shadowocclusionEnabled = props.occlusion.params.shadow.name === 'on' ? 1 : 0; - const closeocclusionEnabled = props.occlusion.params.closeAO.name === 'on' ? 1 : 0; - const softocclusionEnabled = props.occlusion.params.softAO.name === 'on' ? 1 : 0; - - ValueCell.update(this.ssaoRenderable.values.uShadow, shadowocclusionEnabled); - ValueCell.update(this.ssaoRenderable.values.uCloseAO, closeocclusionEnabled); - ValueCell.update(this.ssaoRenderable.values.uSoftAO, softocclusionEnabled); - ValueCell.update(this.ssaoRenderable.values.uProjection, camera.projection); ValueCell.update(this.ssaoRenderable.values.uInvProjection, invProjection); ValueCell.update(this.ssaoRenderable.values.uView, camera.view); @@ -576,54 +564,6 @@ export class PostprocessingPass { ValueCell.updateIfChanged(this.ssaoRenderable.values.uRadius, Math.pow(2, props.occlusion.params.radius)); ValueCell.updateIfChanged(this.ssaoRenderable.values.uBias, props.occlusion.params.bias); - if (props.occlusion.params.shadow.name === 'on') { - ValueCell.update(this.ssaoRenderable.values.dSSample, props.occlusion.params.shadow.params.sSamples); - ValueCell.update(this.ssaoRenderable.values.uSDistance, props.occlusion.params.shadow.params.sdistance); - ValueCell.update(this.ssaoRenderable.values.uSTolerance, props.occlusion.params.shadow.params.stolerance); - - ValueCell.update(this.ssaoRenderable.values.uSBias, props.occlusion.params.shadow.params.sbias); - if (this.ssaoRenderable.values.dSSample.ref.value !== props.occlusion.params.shadow.params.sSamples || - this.ssaoRenderable.values.uSDistance.ref.value !== props.occlusion.params.shadow.params.sdistance || - this.ssaoRenderable.values.uSBias.ref.value !== props.occlusion.params.shadow.params.sbias) { - needsUpdateSsao = true; - } - } - - if (props.occlusion.params.closeAO.name === 'on') { - ValueCell.update(this.ssaoRenderable.values.uCloseBias, props.occlusion.params.closeAO.params.cbias); - ValueCell.update(this.ssaoRenderable.values.uCloseDistance, props.occlusion.params.closeAO.params.cradius); - ValueCell.update(this.ssaoRenderable.values.uCDistanceCutoff, props.occlusion.params.closeAO.params.cdistancecutoff); - ValueCell.update(this.ssaoRenderable.values.uCCutoffFalloff, props.occlusion.params.closeAO.params.ccutofffalloff); - ValueCell.update(this.ssaoRenderable.values.uCIntensity, props.occlusion.params.closeAO.params.cintensity); - ValueCell.update(this.ssaoRenderable.values.uCDistance, props.occlusion.params.closeAO.params.cdistance); - if (this.ssaoRenderable.values.uCloseBias.ref.value !== props.occlusion.params.closeAO.params.cbias || - this.ssaoRenderable.values.uCloseDistance.ref.value !== props.occlusion.params.closeAO.params.cdistance) { - needsUpdateSsao = true; - } - } - - if (props.occlusion.params.softAO.name === 'on') { - ValueCell.update(this.ssaoRenderable.values.uAorange, props.occlusion.params.softAO.params.uAorange); - ValueCell.update(this.ssaoRenderable.values.uDepthTolerance, props.occlusion.params.softAO.params.uDepthTolerance); - ValueCell.update(this.ssaoRenderable.values.uAoMultiplier, props.occlusion.params.softAO.params.uAoMultiplier); - ValueCell.update(this.ssaoRenderable.values.uAoCap, props.occlusion.params.softAO.params.uAoCap); - ValueCell.update(this.ssaoRenderable.values.uAScale, props.occlusion.params.softAO.params.uAScale); - ValueCell.update(this.ssaoRenderable.values.uARings, props.occlusion.params.softAO.params.uARings); - ValueCell.update(this.ssaoRenderable.values.uASamples, props.occlusion.params.softAO.params.uASamples); - - if (this.ssaoRenderable.values.uCloseBias.ref.value !== props.occlusion.params.softAO.params.uASamples || - this.ssaoRenderable.values.uCloseDistance.ref.value !== props.occlusion.params.softAO.params.uARings) { - needsUpdateSsao = true; - } - } - - // console.log(light.direction); - ValueCell.update(this.ssaoRenderable.values.uLightDirection, light.direction); - ValueCell.update(this.ssaoRenderable.values.uLightColor, light.color); - if (this.ssaoRenderable.values.dLightCount.ref.value !== light.count) { - ValueCell.update(this.ssaoRenderable.values.dLightCount, light.count); - needsUpdateSsao = true; - } if (this.blurKernelSize !== props.occlusion.params.blurKernelSize) { needsUpdateSsaoBlur = true; @@ -662,6 +602,30 @@ export class PostprocessingPass { } } + if (props.shadow.name === 'on') { + ValueCell.update(this.shadowsRenderable.values.uProjection, camera.projection); + ValueCell.update(this.shadowsRenderable.values.uInvProjection, invProjection); + + ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far); + ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic); + + ValueCell.updateIfChanged(this.shadowsRenderable.values.uMaxDistance, props.shadow.params.maxDistance); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uTolerance, props.shadow.params.tolerance); + ValueCell.updateIfChanged(this.shadowsRenderable.values.uBias, props.shadow.params.bias); + if (this.shadowsRenderable.values.dSteps.ref.value !== props.shadow.params.steps) { + ValueCell.update(this.shadowsRenderable.values.dSteps, props.shadow.params.steps); + needsUpdateShadows = true; + } + + ValueCell.update(this.shadowsRenderable.values.uLightDirection, light.direction); + ValueCell.update(this.shadowsRenderable.values.uLightColor, light.color); + if (this.shadowsRenderable.values.dLightCount.ref.value !== light.count) { + ValueCell.update(this.shadowsRenderable.values.dLightCount, light.count); + needsUpdateShadows = true; + } + } + if (props.outline.name === 'on') { let { threshold } = props.outline.params; // orthographic needs lower threshold @@ -690,16 +654,16 @@ export class PostprocessingPass { ValueCell.updateIfChanged(this.renderable.values.uTransparentBackground, transparentBackground); if (this.renderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic); + if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled); + if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { needsUpdateMain = true; } + ValueCell.updateIfChanged(this.renderable.values.dShadowEnable, shadowsEnabled); if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; } ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled); - ValueCell.update(this.renderable.values.uLightDirection, light.direction); - ValueCell.update(this.renderable.values.uLightColor, light.color); - if (this.renderable.values.dLightCount.ref.value !== light.count) { - ValueCell.update(this.renderable.values.dLightCount, light.count); - needsUpdateMain = true; + if (needsUpdateShadows) { + this.shadowsRenderable.update(); } if (needsUpdateSsao) { @@ -748,6 +712,11 @@ export class PostprocessingPass { this.outlinesRenderable.render(); } + if (props.shadow.name === 'on') { + this.shadowsTarget.bind(); + this.shadowsRenderable.render(); + } + // don't render occlusion if offset is given, // which will reuse the existing occlusion if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) { diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index a3124581c6fdc0d8ac5d801aa7b8b22974e07b8d..fdfb4b539b53f4732651bfe13d7778b4ab92850d 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -104,13 +104,13 @@ export const RendererParams = { xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }), light: PD.ObjectList({ - inclination: PD.Numeric(180, { min: 0, max: 180, step: 1 }), - azimuth: PD.Numeric(0, { min: 0, max: 360, step: 1 }), + inclination: PD.Numeric(150, { min: 0, max: 180, step: 1 }), + azimuth: PD.Numeric(320, { min: 0, max: 360, step: 1 }), color: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)), intensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }), }, o => Color.toHexString(o.color), { defaultValue: [{ - inclination: 180, - azimuth: 0, + inclination: 150, + azimuth: 320, color: Color.fromNormalizedRgb(1.0, 1.0, 1.0), intensity: 0.6 }] }), diff --git a/src/mol-gl/shader/postprocessing.frag.ts b/src/mol-gl/shader/postprocessing.frag.ts index 0cb8547a2a00a11193b9caf704ca23841582bfc1..720bd65e3a0aa99d5ebcd42423ac30ae99743717 100644 --- a/src/mol-gl/shader/postprocessing.frag.ts +++ b/src/mol-gl/shader/postprocessing.frag.ts @@ -14,6 +14,7 @@ uniform sampler2D tSsaoDepth; uniform sampler2D tColor; uniform sampler2D tDepthOpaque; uniform sampler2D tDepthTransparent; +uniform sampler2D tShadows; uniform sampler2D tOutlines; uniform vec2 uTexSize; @@ -29,18 +30,6 @@ uniform vec2 uOcclusionOffset; uniform float uMaxPossibleViewZDiff; -#if dLightCount != 0 - uniform vec3 uLightDirection[dLightCount]; - uniform vec3 uLightColor[dLightCount]; -#endif - -// #pragma unroll_loop_start -// for (int i = 0; i < dLightCount; ++i) { -// uLightDirection[i]; -// uLightColor[i]; -// } -// #pragma unroll_loop_end - const vec3 occlusionColor = vec3(0.0); #include common @@ -132,7 +121,20 @@ void main(void) { } #endif - // outline needs to be handled after occlusion to keep them clean + #ifdef dShadowEnable + if (!isBackground(opaqueDepth)) { + viewDist = abs(getViewZ(opaqueDepth)); + fogFactor = smoothstep(uFogNear, uFogFar, viewDist); + vec4 shadow = texture2D(tShadows, coords + uOcclusionOffset); + if (!uTransparentBackground) { + color.rgb = mix(mix(vec3(0), uFogColor, fogFactor), color.rgb, shadow.a); + } else { + color.rgb = mix(vec3(0) * (1.0 - fogFactor), color.rgb, shadow.a); + } + } + #endif + + // outline needs to be handled after occlusion and shadow to keep them clean #ifdef dOutlineEnable float closestTexel; float outline = getOutline(coords, opaqueDepth, closestTexel); diff --git a/src/mol-gl/shader/shadows.frag.ts b/src/mol-gl/shader/shadows.frag.ts new file mode 100644 index 0000000000000000000000000000000000000000..1963b2148fcb7a7bf1ce69d453f6b3c733c275a0 --- /dev/null +++ b/src/mol-gl/shader/shadows.frag.ts @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Ludovic Autin <ludovic.autin@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +export const shadows_frag = ` +precision highp float; +precision highp int; +precision highp sampler2D; + +#include common + +uniform sampler2D tDepth; +uniform vec2 uTexSize; + +uniform float uNear; +uniform float uFar; + +#if dLightCount != 0 + uniform vec3 uLightDirection[dLightCount]; + uniform vec3 uLightColor[dLightCount]; +#endif + +uniform mat4 uProjection; +uniform mat4 uInvProjection; + +uniform float uMaxDistance; +uniform float uTolerance; +uniform float uBias; + +bool isBackground(const in float depth) { + return depth == 1.0; +} + +float getViewZ(in float depth) { + #if dOrthographic == 1 + return orthographicDepthToViewZ(depth, uNear, uFar); + #else + return perspectiveDepthToViewZ(depth, uNear, uFar); + #endif +} + +float getDepth(const in vec2 coords) { + #ifdef depthTextureSupport + return texture2D(tDepth, coords).r; + #else + return unpackRGBAToDepth(texture2D(tDepth, coords)); + #endif +} + +// based on https://panoskarabelas.com/posts/screen_space_shadows/ +float screenSpaceShadow(in vec2 coords, in vec3 position, in vec3 lightDirection, in float stepLength) { + // Ray position and direction (in view-space) + vec3 rayPos = position; + vec3 rayDir = -lightDirection; + + // Compute ray step + vec3 rayStep = rayDir * stepLength; + + // Ray march towards the light + float occlusion = 0.0; + vec4 rayCoords = vec4(0.0); + for (int i = 0; i < dSteps; ++i) { + // 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; + float depth = getDepth(rayCoords.xy); + float viewZ = getViewZ(depth); + float zDelta = rayPos.z - viewZ; + + if (zDelta < uTolerance) { + occlusion = 1.0; + 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); +} + +void main(void) { + vec2 invTexSize = 1.0 / uTexSize; + vec2 selfCoords = gl_FragCoord.xy * invTexSize; + + float selfDepth = getDepth(selfCoords); + + if (isBackground(selfDepth)) { + gl_FragColor = vec4(0.0); + return; + } + + vec3 selfViewPos = screenSpaceToViewSpace(vec3(selfCoords, selfDepth), uInvProjection); + float stepLength = uMaxDistance / float(dSteps); + + float o = 1.0; + #if dLightCount != 0 + float sh[dLightCount]; + #pragma unroll_loop_start + for (int i = 0; i < dLightCount; ++i) { + sh[i] = screenSpaceShadow(selfCoords, selfViewPos, uLightDirection[i], stepLength); + o = min(o, sh[i]); + } + #pragma unroll_loop_end + #endif + + gl_FragColor = vec4(o); +} +`; \ No newline at end of file diff --git a/src/mol-gl/shader/ssao.frag.ts b/src/mol-gl/shader/ssao.frag.ts index 5a41821b694545ce67924828f6413a7775c905fe..41850c5ea31f200af46d545731869152bb43baa0 100644 --- a/src/mol-gl/shader/ssao.frag.ts +++ b/src/mol-gl/shader/ssao.frag.ts @@ -16,54 +16,14 @@ uniform sampler2D tDepth; uniform vec2 uTexSize; uniform vec4 uBounds; -uniform float uNear; -uniform float uFar; - -#if dLightCount != 0 - uniform vec3 uLightDirection[dLightCount]; - uniform vec3 uLightColor[dLightCount]; -#endif - uniform vec3 uSamples[dNSamples]; uniform mat4 uProjection; -uniform mat4 uView; uniform mat4 uInvProjection; uniform float uRadius; uniform float uBias; -// shadow uniform -uniform float uSDistance; -uniform float uSTolerance; -uniform float uSBias; -uniform int uShadow; - -//ssao-pro uniform -uniform int uCloseAO; -uniform float uCloseBias; -uniform float uCloseDistance; -uniform float uCDistanceCutoff; -uniform float uCCutoffFalloff; -uniform float uCIntensity; -uniform float uCDistance; - -//ssao-old-blender uniform -uniform int uSoftAO; -uniform float uAorange; -uniform float uDepthTolerance; -uniform float uAoMultiplier; -uniform float uAoCap; -uniform float uAScale; -uniform int uARings; -uniform int uASamples; - -#define PI 3.14159265 -#define SAMPLES_HIGH 1 -#define SAMPLES_ULTRA 0 -#define SAMPLE_NOISE 1 - - float smootherstep(float edge0, float edge1, float x) { x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); @@ -90,14 +50,6 @@ 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(in float depth) { - #if dOrthographic == 1 - return orthographicDepthToViewZ(depth, uNear, uFar); - #else - return perspectiveDepthToViewZ(depth, uNear, uFar); - #endif -} - float getDepth(const in vec2 coords) { if (outsideBounds(coords)) { return 1.0; @@ -120,241 +72,6 @@ vec3 normalFromDepth(const in float depth, const in float depth1, const in float return normalize(normal); } -float readDepth( in vec2 coord ) { - return (2.0 * uNear) / (uFar + uNear - getDepth(coord) * (uFar - uNear)); -} - -float compareDepths( in float d1, in float d2 ){ - float near = uNear; - float far = uFar; - //float aorange = 160.0; //uniform - //float depthTolerance = 0.0;//uniform - //float aoMultiplier = 100.0;//uniform - //float aoCap = 1.0;//uniform - //go linear ? - float depth1 = d1;//getViewZ(d1); - float depth2 = d2;//getViewZ(d2); - //float diff = sqrt(clamp(1.0-(depth1-depth2) / (uAorange),0.0,1.0)); - float diff = sqrt(clamp(1.0-(depth1-depth2) / (uAorange/(far-near)),0.0,1.0)); - float ao = min(uAoCap,max(0.0,depth1-depth2-uDepthTolerance) * uAoMultiplier) * diff; - return ao; -} - -float computeAO(in vec2 scrCoord){ - float depth = readDepth(scrCoord); - vec2 invTexSize = 1.0 / uTexSize; - int do_noise = 0; - - float scale = uAScale; //uniform - float aspect = uTexSize.x/uTexSize.y; - int rings = uARings;//min(6,int(uRadius)); //uniform - int samples = uASamples;//min(6,int(dNSamples)); //uniform - //vec3 randomVec = normalize(vec3(getNoiseVec2(scrCoord), 0.0)); - vec2 noise = getNoiseVec2(scrCoord);//getRandom(srcCoord);// - float w; - float h; - if (do_noise == 1) { - w = invTexSize.x/clamp(depth,0.05,1.0)+(noise.x*(1.0-noise.x))*scale; - h = invTexSize.y/clamp(depth,0.05,1.0)+(noise.y*(1.0-noise.y))*scale; - } - else { - w = invTexSize.x/clamp(depth,0.05,1.0)+0.001*scale;//+(noise.x*(1.0-noise.x)); - h = invTexSize.y/clamp(depth,0.05,1.0)+0.001*scale;//+(noise.y*(1.0-noise.y)); - } - float pw; - float ph; - - float ao; - float s; - - int ringsamples; - for (int i = 1; i <= rings; i += 1){ - ringsamples = i * samples; - for (int j = 0 ; j < ringsamples ; j += 1) { - float step = PI*2.0 / float(ringsamples); - pw = (cos(float(j)*step)*float(i)); - ph = (sin(float(j)*step)*float(i))*aspect; - float v = readDepth( vec2(scrCoord.s+pw*w,scrCoord.t+ph*h) ); - ao += compareDepths(depth, v); - s += 1.0; - } - } - ao /= s; - // ao = 1.0-ao; - return ao; -} - - -float computeOcclusion(in float aradius, in mat3 TBN, in vec3 selfViewPos ){ - float occlusion = 0.0; - for(int i = 0; i < dNSamples; i++){ - vec3 sampleViewPos = TBN * uSamples[i]; - sampleViewPos = selfViewPos + sampleViewPos * aradius; - - vec4 offset = vec4(sampleViewPos, 1.0); - offset = uProjection * offset; - offset.xyz = (offset.xyz / offset.w) * 0.5 + 0.5; - - float sampleViewZ = screenSpaceToViewSpace(vec3(offset.xy, getDepth(offset.xy)), uInvProjection).z; - - occlusion += step(sampleViewPos.z + 0.025, sampleViewZ) * smootherstep(0.0, 1.0, aradius / abs(selfViewPos.z - sampleViewZ)); - } - return occlusion; -} - -float calcAO(in vec2 tcoord, in vec2 uv, in vec3 p, in vec3 cnorm) -{ - float _Bias = uCloseBias; - float _Intensity = uCIntensity; - float _Distance = uCDistance; - vec2 t = tcoord + uv; - float depth = getDepth(t); - vec3 diff = screenSpaceToViewSpace(vec3(t, depth), uInvProjection) - p; - vec3 v = normalize(diff); - float d = length(diff) * _Distance; - // cnorm = normalize(_WorldSpaceCameraPos - p); - return max(0.0, dot(cnorm, v) - _Bias) * (1.0 / (1.0 + d)) * _Intensity; -} - -float invlerp(float from, float to, float value) -{ - return (value - from) / (to - from); -} - -// Gold Noise function -float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio -float PIT = 3.14159265358979323846264 * 00000.1; // PI -float SRT = 1.41421356237309504880169 * 10000.0; // Square Root of Two - -float random_0t1(in vec2 coordinate, in float seed) -{ - return fract(sin(dot(coordinate*seed, vec2(PHI, PIT)))*SRT); -} - -float ssao(in vec2 uv, in vec3 normal) -{ - float _SampleRadius = 5.0; - float _DistanceCutoff = uCDistanceCutoff;//100.0; - float _CutoffFalloff = uCCutoffFalloff;//25.0; - - vec2 CROSS[4] = vec2[4]( vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0) ); - float depth = getDepth(uv); - float eyeDepth = getViewZ(depth); - vec3 position = screenSpaceToViewSpace(vec3(uv, depth), uInvProjection); - float radius = uCloseDistance; // original was max(_SampleRadius / eyeDepth, 0.005); - // clip(_DistanceCutoff - eyeDepth); // Skip out of range pixels - if (_DistanceCutoff - abs(eyeDepth) < 0.0) return 1.0; - #if defined(SAMPLE_NOISE) - float a = random_0t1(uv,depth); - float b = random_0t1(uv,eyeDepth); - vec2 random = normalize(vec2(a,b)); - // original used a texture for noise - // vec2 random = normalize(tex2D(_NoiseTex, _ScreenParams.xy * uv / _NoiseSize).rg * 2.0 - 1.0); - #endif - float ao = 0.0; - // Sampling - for (int j = 0; j < 4; j++) - { - vec2 coord1; - - #if defined(SAMPLE_NOISE) - coord1 = reflect(CROSS[j], random) * radius; - #else - coord1 = CROSS[j] * radius; - #endif - - // #if !SAMPLES_VERY_LOW - vec2 coord2 = coord1 * 0.707; - coord2 = vec2(coord2.x - coord2.y, coord2.x + coord2.y); - // #endif - - #if defined(SAMPLES_ULTRA) // 20 - ao += calcAO(uv, coord1 * 0.20, position, normal); - ao += calcAO(uv, coord2 * 0.40, position, normal); - ao += calcAO(uv, coord1 * 0.60, position, normal); - ao += calcAO(uv, coord2 * 0.80, position, normal); - ao += calcAO(uv, coord1, position, normal); - #elif defined(SAMPLES_HIGH) // 16 - ao += calcAO(uv, coord1 * 0.25, position, normal); - ao += calcAO(uv, coord2 * 0.50, position, normal); - ao += calcAO(uv, coord1 * 0.75, position, normal); - ao += calcAO(uv, coord2, position, normal); - #elif defined(SAMPLES_MEDIUM) // 12 - ao += calcAO(uv, coord1 * 0.30, position, normal); - ao += calcAO(uv, coord2 * 0.60, position, normal); - ao += calcAO(uv, coord1 * 0.90, position, normal); - #elif defined(SAMPLES_LOW ) // 8 - ao += calcAO(uv, coord1 * 0.30, position, normal); - ao += calcAO(uv, coord2 * 0.80, position, normal); - #else // 4 - ao += calcAO(uv, coord1 * 0.50, position, normal); - #endif - } - - #if SAMPLES_ULTRA - ao /= 20.0; - #elif SAMPLES_HIGH - ao /= 16.0; - #elif SAMPLES_MEDIUM - ao /= 12.0; - #elif SAMPLES_LOW - ao /= 8.0; - #else - ao /= 4.0; - #endif - - // Distance cutoff - ao = mix(1.0 - ao, 1.0, saturate(invlerp(_DistanceCutoff - _CutoffFalloff, _DistanceCutoff, eyeDepth))); - - return ao; -} - -float ScreenSpaceShadows(in vec2 uv, in vec3 position, in vec3 light_direction) -{ - // Settings - int g_sss_steps = dSSample; // Quality/performancedNSamples - float g_sss_ray_max_distance = uSDistance; // Max shadow length - float g_sss_tolerance = uSTolerance; // Error in favor of reducing gaps - float g_sss_step_length = g_sss_ray_max_distance / float(g_sss_steps); - float uvdepth = getDepth(uv); - - float eyeDepth = getViewZ(uvdepth); - // Compute ray position and direction (in view-space) - vec3 ray_pos = position; - vec3 ray_dir = -light_direction; //light direction in View space - vec2 uv_pos = uv; - // Compute ray step - vec3 ray_step = ray_dir * g_sss_step_length; - vec2 uv_step = ray_dir.xy * g_sss_step_length; - // Ray march towards the light - float occlusion = 0.0; - - vec4 ray_uv = vec4(0.0,0.0,0.0,0.0); - for (int i = 0; i < g_sss_steps; i++) - { - // Step the ray - uv_pos += uv_step; - ray_pos += ray_step; - // Compute the difference between the ray's and the camera's depth - ray_uv = (uProjection * vec4(ray_pos,1.0)); - ray_uv.xyz = (ray_uv.xyz / ray_uv.w) * 0.5 + 0.5; - float depth = getDepth(ray_uv.xy); - float depth_z = getViewZ(depth); - float depth_delta = ray_pos.z - depth_z; - if (depth_delta < g_sss_tolerance){ - // original test : if (abs(g_sss_tolerance - depth_delta) < g_sss_tolerance){ - occlusion = 1.0; - vec2 fade = max(12.0 * abs(ray_uv.xy - 0.5) - 5.0, vec2(0.0,0.0)); - occlusion *= saturate(1.0 - dot(fade, fade)); - break; - } - } - // Fade out as we approach the edges of the screen - // occlusion *= screen_fade(ray_uv);return 1.0 - occlusion; - occlusion = 1.0 - (uSBias * occlusion); - return occlusion; -} - // StarCraft II Ambient Occlusion by [Filion and McNaughton 2008] void main(void) { vec2 invTexSize = 1.0 / uTexSize; @@ -383,47 +100,23 @@ void main(void) { vec3 bitangent = cross(selfViewNormal, tangent); mat3 TBN = mat3(tangent, bitangent, selfViewNormal); - float occlusion = computeOcclusion(uRadius, TBN, selfViewPos); - occlusion = 1.0 - (uBias * occlusion / float(dNSamples)); - float ao1=0.0; - // alternative ao algo - if (uSoftAO == 1) - { - ao1 = computeAO(selfCoords); - ao1 = clamp(ao1,0.0,1.0); - if ( ao1 > 1.0 ) {ao1 = 1.0 ;} - if ( ao1 < 0.0 ) {ao1 = 0.0 ;} - if (selfDepth > 1.0 ) {ao1 = 1.0 ;} - if (selfDepth < 0.0 ) {ao1 = 0.0 ;} - ao1 = 1.0 - (ao1); - } - - bool isClose = true; - if (abs(selfViewPos.z) > 1200.0) isClose = false; + float occlusion = 0.0; + for(int i = 0; i < dNSamples; i++){ + vec3 sampleViewPos = TBN * uSamples[i]; + sampleViewPos = selfViewPos + sampleViewPos * uRadius; - float ao = 1.0; - if (uCloseAO == 1){ - ao = saturate(ssao(selfCoords, selfViewNormal)); - } - float o = 9999.9; - if (uShadow == 1) { - #if dLightCount != 0 - float sh[dLightCount]; - #pragma unroll_loop_start - for (int i = 0; i < dLightCount; ++i) { - sh[i] = ScreenSpaceShadows(selfCoords, selfViewPos, uLightDirection[i]); - o = min(o,min(min(sh[i],ao),occlusion)); - } - #pragma unroll_loop_end - #endif - } - else{ - o = min(ao,occlusion); - } - if (uSoftAO==1){ - o = min(ao1,o); + vec4 offset = vec4(sampleViewPos, 1.0); + offset = uProjection * offset; + offset.xyz = (offset.xyz / offset.w) * 0.5 + 0.5; + + float sampleViewZ = screenSpaceToViewSpace(vec3(offset.xy, getDepth(offset.xy)), uInvProjection).z; + + occlusion += step(sampleViewPos.z + 0.025, sampleViewZ) * smootherstep(0.0, 1.0, uRadius / abs(selfViewPos.z - sampleViewZ)); } - vec2 packedOcclusion = packUnitIntervalToRG(o); + occlusion = 1.0 - (uBias * occlusion / float(dNSamples)); + + vec2 packedOcclusion = packUnitIntervalToRG(occlusion); + gl_FragColor = vec4(packedOcclusion, selfPackedDepth); } `; \ No newline at end of file diff --git a/src/mol-plugin-ui/structure/quick-styles.tsx b/src/mol-plugin-ui/structure/quick-styles.tsx index 262f10f6b515c70126293e116edd75fbc16b8c0d..182e53760866b9d3f3257fd9c474bcfd505d11de 100644 --- a/src/mol-plugin-ui/structure/quick-styles.tsx +++ b/src/mol-plugin-ui/structure/quick-styles.tsx @@ -60,8 +60,12 @@ export class QuickStyles extends PurePluginUIComponent { }, occlusion: { name: 'on', - params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1, shadow: { name: 'off', params: {} }, softAO: { name: 'off', params: {} }, closeAO: { name: 'off', params: {} } } - } + params: { bias: 0.8, blurKernelSize: 15, radius: 5, samples: 32, resolutionScale: 1 } + }, + shadow: { + name: 'off', + params: { } + }, } }); } diff --git a/src/mol-plugin-ui/viewport/simple-settings.tsx b/src/mol-plugin-ui/viewport/simple-settings.tsx index a3f7eb6d939a26fb0db47839521823779989c94f..ddf7fcf54304c5503f428ec8b31c42e488a832e8 100644 --- a/src/mol-plugin-ui/viewport/simple-settings.tsx +++ b/src/mol-plugin-ui/viewport/simple-settings.tsx @@ -59,6 +59,7 @@ const SimpleSettingsParams = { }, { pivot: 'color' }), lighting: PD.Group({ occlusion: Canvas3DParams.postprocessing.params.occlusion, + shadow: Canvas3DParams.postprocessing.params.shadow, outline: Canvas3DParams.postprocessing.params.outline, fog: Canvas3DParams.cameraFog, }, { isFlat: true }), @@ -114,6 +115,7 @@ const SimpleSettingsMapping = ParamMapping({ }, lighting: { occlusion: canvas.postprocessing.occlusion, + shadow: canvas.postprocessing.shadow, outline: canvas.postprocessing.outline, fog: canvas.cameraFog, }, @@ -129,6 +131,7 @@ const SimpleSettingsMapping = ParamMapping({ canvas.transparentBackground = s.background.transparent; canvas.renderer.backgroundColor = s.background.color; canvas.postprocessing.occlusion = s.lighting.occlusion; + canvas.postprocessing.shadow = s.lighting.shadow; canvas.postprocessing.outline = s.lighting.outline; canvas.postprocessing.background = s.background.style; canvas.cameraFog = s.lighting.fog;