diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts
index b98072d9c77a3f9ee31927fe5fd091eaf05dc87a..5cae262fa056c1e7efa3f1a0fd2ce2fc0ebc678e 100644
--- a/src/mol-canvas3d/passes/postprocessing.ts
+++ b/src/mol-canvas3d/passes/postprocessing.ts
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -17,6 +17,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { DrawPass } from './draw';
import { Camera } from '../../mol-canvas3d/camera';
+import { produce } from 'immer';
import quad_vert from '../../mol-gl/shader/quad.vert'
import postprocessing_frag from '../../mol-gl/shader/postprocessing.frag'
@@ -47,14 +48,21 @@ const PostprocessingSchema = {
}
export const PostprocessingParams = {
- occlusionEnable: PD.Boolean(false),
- occlusionKernelSize: PD.Numeric(4, { min: 1, max: 32, step: 1 }),
- occlusionBias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
- occlusionRadius: PD.Numeric(32, { min: 0, max: 256, step: 1 }),
-
- outlineEnable: PD.Boolean(false),
- outlineScale: PD.Numeric(1, { min: 0, max: 10, step: 1 }),
- outlineThreshold: PD.Numeric(0.8, { min: 0, max: 1, step: 0.01 }),
+ occlusion: PD.MappedStatic('off', {
+ on: PD.Group({
+ kernelSize: PD.Numeric(4, { min: 1, max: 32, step: 1 }),
+ bias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
+ radius: PD.Numeric(64, { min: 0, max: 256, step: 1 }),
+ }),
+ off: PD.Group({})
+ }, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
+ outline: PD.MappedStatic('off', {
+ on: PD.Group({
+ scale: PD.Numeric(1, { min: 0, max: 10, step: 1 }),
+ threshold: PD.Numeric(0.8, { min: 0, max: 1, step: 0.01 }),
+ }),
+ off: PD.Group({})
+ }, { cycle: true, description: 'Draw outline around 3D objects' })
}
export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
@@ -75,14 +83,14 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
uFogFar: ValueCell.create(10000),
uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
- dOcclusionEnable: ValueCell.create(p.occlusionEnable),
- dOcclusionKernelSize: ValueCell.create(p.occlusionKernelSize),
- uOcclusionBias: ValueCell.create(p.occlusionBias),
- uOcclusionRadius: ValueCell.create(p.occlusionRadius),
+ dOcclusionEnable: ValueCell.create(p.occlusion.name === 'on'),
+ dOcclusionKernelSize: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.kernelSize : 4),
+ uOcclusionBias: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.bias : 0.5),
+ uOcclusionRadius: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.radius : 64),
- dOutlineEnable: ValueCell.create(p.outlineEnable),
- uOutlineScale: ValueCell.create(p.outlineScale * ctx.pixelRatio),
- uOutlineThreshold: ValueCell.create(p.outlineThreshold),
+ dOutlineEnable: ValueCell.create(p.outline.name === 'on'),
+ uOutlineScale: ValueCell.create((p.outline.name === 'on' ? p.outline.params.scale : 1) * ctx.pixelRatio),
+ uOutlineThreshold: ValueCell.create(p.outline.name === 'on' ? p.outline.params.threshold : 0.8),
dPackedDepth: ValueCell.create(packedDepth),
}
@@ -108,7 +116,7 @@ export class PostprocessingPass {
}
get enabled() {
- return this.props.occlusionEnable || this.props.outlineEnable
+ return this.props.occlusion.name === 'on' || this.props.outline.name === 'on'
}
setSize(width: number, height: number) {
@@ -117,35 +125,28 @@ export class PostprocessingPass {
}
setProps(props: Partial<PostprocessingProps>) {
- if (props.occlusionEnable !== undefined) {
- this.props.occlusionEnable = props.occlusionEnable
- ValueCell.update(this.renderable.values.dOcclusionEnable, props.occlusionEnable)
- }
- if (props.occlusionKernelSize !== undefined) {
- this.props.occlusionKernelSize = props.occlusionKernelSize
- ValueCell.update(this.renderable.values.dOcclusionKernelSize, props.occlusionKernelSize)
- }
- if (props.occlusionBias !== undefined) {
- this.props.occlusionBias = props.occlusionBias
- ValueCell.update(this.renderable.values.uOcclusionBias, props.occlusionBias)
- }
- if (props.occlusionRadius !== undefined) {
- this.props.occlusionRadius = props.occlusionRadius
- ValueCell.update(this.renderable.values.uOcclusionRadius, props.occlusionRadius)
- }
-
- if (props.outlineEnable !== undefined) {
- this.props.outlineEnable = props.outlineEnable
- ValueCell.update(this.renderable.values.dOutlineEnable, props.outlineEnable)
- }
- if (props.outlineScale !== undefined) {
- this.props.outlineScale = props.outlineScale
- ValueCell.update(this.renderable.values.uOutlineScale, props.outlineScale * this.webgl.pixelRatio)
- }
- if (props.outlineThreshold !== undefined) {
- this.props.outlineThreshold = props.outlineThreshold
- ValueCell.update(this.renderable.values.uOutlineThreshold, props.outlineThreshold)
- }
+ this.props = produce(this.props, p => {
+ if (props.occlusion !== undefined) {
+ p.occlusion.name = props.occlusion.name
+ ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, props.occlusion.name === 'on')
+ if (props.occlusion.name === 'on') {
+ p.occlusion.params = { ...props.occlusion.params }
+ ValueCell.updateIfChanged(this.renderable.values.dOcclusionKernelSize, props.occlusion.params.kernelSize)
+ ValueCell.updateIfChanged(this.renderable.values.uOcclusionBias, props.occlusion.params.bias)
+ ValueCell.updateIfChanged(this.renderable.values.uOcclusionRadius, props.occlusion.params.radius)
+ }
+ }
+
+ if (props.outline !== undefined) {
+ p.outline.name = props.outline.name
+ ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, props.outline.name === 'on')
+ if (props.outline.name === 'on') {
+ p.outline.params = { ...props.outline.params }
+ ValueCell.updateIfChanged(this.renderable.values.uOutlineScale, props.outline.params.scale)
+ ValueCell.updateIfChanged(this.renderable.values.uOutlineThreshold, props.outline.params.threshold)
+ }
+ }
+ })
this.renderable.update()
}
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
index 6262d5452b47b4e2245d37f14b08df6f109e519d..57975f47c9d89dde14fb6fc64a0a58dce5b04f8a 100644
--- a/src/mol-gl/renderer.ts
+++ b/src/mol-gl/renderer.ts
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -55,22 +55,63 @@ export const RendererParams = {
interiorColorFlag: PD.Boolean(true, { label: 'Use Interior Color' }),
interiorColor: PD.Color(Color.fromNormalizedRgb(0.3, 0.3, 0.3)),
- lightIntensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
- ambientIntensity: PD.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }),
-
- metalness: PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }),
- roughness: PD.Numeric(1.0, { min: 0.0, max: 1.0, step: 0.01 }),
- reflectivity: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
-
highlightColor: PD.Color(Color.fromNormalizedRgb(1.0, 0.4, 0.6)),
selectColor: PD.Color(Color.fromNormalizedRgb(0.2, 1.0, 0.1)),
+
+ style: PD.MappedStatic('matte', {
+ custom: PD.Group({
+ lightIntensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
+ ambientIntensity: PD.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }),
+ metalness: PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }),
+ roughness: PD.Numeric(1.0, { min: 0.0, max: 1.0, step: 0.01 }),
+ reflectivity: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
+ }, { isExpanded: true }),
+ flat: PD.Group({}),
+ matte: PD.Group({}),
+ glossy: PD.Group({}),
+ metallic: PD.Group({}),
+ plastic: PD.Group({}),
+ }, { label: 'Render Style', description: 'Style in which the 3D scene is rendered' }),
}
export type RendererProps = PD.Values<typeof RendererParams>
+function getStyle(props: RendererProps['style']) {
+ switch (props.name) {
+ case 'custom':
+ return props.params
+ case 'flat':
+ return {
+ lightIntensity: 0, ambientIntensity: 1,
+ metalness: 0, roughness: 0.4, reflectivity: 0.5
+ }
+ case 'matte':
+ return {
+ lightIntensity: 0.6, ambientIntensity: 0.4,
+ metalness: 0, roughness: 1, reflectivity: 0.5
+ }
+ case 'glossy':
+ return {
+ lightIntensity: 0.6, ambientIntensity: 0.4,
+ metalness: 0, roughness: 0.4, reflectivity: 0.5
+ }
+ case 'metallic':
+ return {
+ lightIntensity: 0.6, ambientIntensity: 0.4,
+ metalness: 0.4, roughness: 0.6, reflectivity: 0.5
+ }
+ case 'plastic':
+ return {
+ lightIntensity: 0.6, ambientIntensity: 0.4,
+ metalness: 0, roughness: 0.2, reflectivity: 0.5
+ }
+ }
+}
+
namespace Renderer {
export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
const { gl, state, stats } = ctx
const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props })
+ const style = getStyle(p.style)
const viewport = Viewport()
const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor)
@@ -112,12 +153,12 @@ namespace Renderer {
uTransparentBackground: ValueCell.create(0),
// the following are general 'material' uniforms
- uLightIntensity: ValueCell.create(p.lightIntensity),
- uAmbientIntensity: ValueCell.create(p.ambientIntensity),
+ uLightIntensity: ValueCell.create(style.lightIntensity),
+ uAmbientIntensity: ValueCell.create(style.ambientIntensity),
- uMetalness: ValueCell.create(p.metalness),
- uRoughness: ValueCell.create(p.roughness),
- uReflectivity: ValueCell.create(p.reflectivity),
+ uMetalness: ValueCell.create(style.metalness),
+ uRoughness: ValueCell.create(style.roughness),
+ uReflectivity: ValueCell.create(style.reflectivity),
uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold),
@@ -276,28 +317,6 @@ namespace Renderer {
ValueCell.update(globalUniforms.uInteriorColor, Color.toVec3Normalized(globalUniforms.uInteriorColor.ref.value, p.interiorColor))
}
- if (props.lightIntensity !== undefined && props.lightIntensity !== p.lightIntensity) {
- p.lightIntensity = props.lightIntensity
- ValueCell.update(globalUniforms.uLightIntensity, p.lightIntensity)
- }
- if (props.ambientIntensity !== undefined && props.ambientIntensity !== p.ambientIntensity) {
- p.ambientIntensity = props.ambientIntensity
- ValueCell.update(globalUniforms.uAmbientIntensity, p.ambientIntensity)
- }
-
- if (props.metalness !== undefined && props.metalness !== p.metalness) {
- p.metalness = props.metalness
- ValueCell.update(globalUniforms.uMetalness, p.metalness)
- }
- if (props.roughness !== undefined && props.roughness !== p.roughness) {
- p.roughness = props.roughness
- ValueCell.update(globalUniforms.uRoughness, p.roughness)
- }
- if (props.reflectivity !== undefined && props.reflectivity !== p.reflectivity) {
- p.reflectivity = props.reflectivity
- ValueCell.update(globalUniforms.uReflectivity, p.reflectivity)
- }
-
if (props.highlightColor !== undefined && props.highlightColor !== p.highlightColor) {
p.highlightColor = props.highlightColor
ValueCell.update(globalUniforms.uHighlightColor, Color.toVec3Normalized(globalUniforms.uHighlightColor.ref.value, p.highlightColor))
@@ -306,6 +325,16 @@ namespace Renderer {
p.selectColor = props.selectColor
ValueCell.update(globalUniforms.uSelectColor, Color.toVec3Normalized(globalUniforms.uSelectColor.ref.value, p.selectColor))
}
+
+ if (props.style !== undefined) {
+ p.style = props.style
+ Object.assign(style, getStyle(props.style))
+ ValueCell.updateIfChanged(globalUniforms.uLightIntensity, style.lightIntensity)
+ ValueCell.updateIfChanged(globalUniforms.uAmbientIntensity, style.ambientIntensity)
+ ValueCell.updateIfChanged(globalUniforms.uMetalness, style.metalness)
+ ValueCell.updateIfChanged(globalUniforms.uRoughness, style.roughness)
+ ValueCell.updateIfChanged(globalUniforms.uReflectivity, style.reflectivity)
+ }
},
setViewport: (x: number, y: number, width: number, height: number) => {
gl.viewport(x, y, width, height)
diff --git a/src/mol-plugin-ui/viewport/simple-settings.tsx b/src/mol-plugin-ui/viewport/simple-settings.tsx
index 2cdc23609517c83da8be25d86b6363cdbec67944..200fd91e65acd1e6f94d1b7477325bc1209eb6d6 100644
--- a/src/mol-plugin-ui/viewport/simple-settings.tsx
+++ b/src/mol-plugin-ui/viewport/simple-settings.tsx
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -38,9 +38,9 @@ const SimpleSettingsParams = {
'transparent': PD.EmptyGroup(),
'opaque': PD.Group({ color: PD.Color(Color(0xFCFBF9), { description: 'Custom background color' }) }, { isFlat: true })
}, { description: 'Background of the 3D canvas' }),
- renderStyle: PD.Select('glossy', PD.arrayToOptions(['flat', 'matte', 'glossy', 'metallic']), { description: 'Style in which the 3D scene is rendered' }),
- occlusion: PD.Boolean(false, { description: 'Darken occluded crevices with the ambient occlusion effect' }),
- outline: PD.Boolean(false, { description: 'Draw outline around 3D objects' }),
+ renderStyle: Canvas3DParams.renderer.params.style,
+ occlusion: Canvas3DParams.postprocessing.params.occlusion,
+ outline: Canvas3DParams.postprocessing.params.outline,
fog: PD.Boolean(false, { description: 'Show fog in the distance' }),
clipFar: PD.Boolean(true, { description: 'Clip scene in the distance' }),
};
@@ -48,43 +48,28 @@ const SimpleSettingsParams = {
type SimpleSettingsParams = typeof SimpleSettingsParams
const SimpleSettingsMapping = ParamMapping({
params: SimpleSettingsParams,
- target(ctx: PluginContext) {
+ target(ctx: PluginContext) {
const layout: SimpleSettingsParams['layout']['defaultValue'] = [];
if (ctx.layout.state.regionState.top !== 'hidden') layout.push('sequence');
if (ctx.layout.state.regionState.bottom !== 'hidden') layout.push('log');
if (ctx.layout.state.regionState.left !== 'hidden') layout.push('left');
return { canvas: ctx.canvas3d?.props!, layout };
}
-})({
+})({
values(props, ctx) {
const { canvas } = props;
const renderer = canvas.renderer;
- let renderStyle: SimpleSettingsParams['renderStyle']['defaultValue'] = 'custom' as any;
- if (renderer) {
- if (renderer.lightIntensity === 0 && renderer.ambientIntensity === 1 && renderer.roughness === 0.4 && renderer.metalness === 0) {
- renderStyle = 'flat'
- } else if (renderer.lightIntensity === 0.6 && renderer.ambientIntensity === 0.4) {
- if (renderer.roughness === 1 && renderer.metalness === 0) {
- renderStyle = 'matte'
- } else if (renderer.roughness === 0.4 && renderer.metalness === 0) {
- renderStyle = 'glossy'
- } else if (renderer.roughness === 0.6 && renderer.metalness === 0.4) {
- renderStyle = 'metallic'
- }
- }
- }
-
return {
layout: props.layout,
spin: !!canvas.trackball.spin,
camera: canvas.cameraMode,
- background: (renderer.backgroundColor === ColorNames.white && canvas.transparentBackground)
+ background: (renderer.backgroundColor === ColorNames.white && canvas.transparentBackground)
? { name: 'transparent', params: { } }
: { name: 'opaque', params: { color: renderer.backgroundColor } },
- renderStyle,
- occlusion: canvas.postprocessing.occlusionEnable,
- outline: canvas.postprocessing.outlineEnable,
+ renderStyle: renderer.style,
+ occlusion: canvas.postprocessing.occlusion,
+ outline: canvas.postprocessing.outline,
fog: ctx.canvas3d ? canvas.cameraFog > 1 : false,
clipFar: canvas.cameraClipFar
};
@@ -95,18 +80,9 @@ const SimpleSettingsMapping = ParamMapping({
canvas.cameraMode = s.camera;
canvas.transparentBackground = s.background.name === 'transparent';
canvas.renderer.backgroundColor = s.background.name === 'transparent' ? ColorNames.white : s.background.params.color;
- switch (s.renderStyle) {
- case 'flat': Object.assign(canvas.renderer, { lightIntensity: 0, ambientIntensity: 1, roughness: 0.4, metalness: 0 }); break;
- case 'matte': Object.assign(canvas.renderer, { lightIntensity: 0.6, ambientIntensity: 0.4, roughness: 1, metalness: 0 }); break;
- case 'glossy': Object.assign(canvas.renderer, { lightIntensity: 0.6, ambientIntensity: 0.4, roughness: 0.4, metalness: 0 }); break;
- case 'metallic': Object.assign(canvas.renderer, { lightIntensity: 0.6, ambientIntensity: 0.4, roughness: 0.6, metalness: 0.4 }); break;
- }
- canvas.postprocessing.occlusionEnable = s.occlusion;
- if (s.occlusion) {
- canvas.postprocessing.occlusionBias = 0.5;
- canvas.postprocessing.occlusionRadius = 64;
- }
- canvas.postprocessing.outlineEnable = s.outline;
+ canvas.renderer.style = s.renderStyle
+ canvas.postprocessing.occlusion = s.occlusion;
+ canvas.postprocessing.outline = s.outline;
canvas.cameraFog = s.fog ? 50 : 0;
canvas.cameraClipFar = s.clipFar;
@@ -122,7 +98,7 @@ const SimpleSettingsMapping = ParamMapping({
s.regionState.left = hideLeft ? 'hidden' : ctx.behaviors.layout.leftPanelTabName.value === 'none' ? 'collapsed' : 'full';
});
await PluginCommands.Layout.Update(ctx, { state });
-
+
if (hideLeft) {
PluginCommands.State.SetCurrentObject(ctx, { state: ctx.state.dataState, ref: StateTransform.RootRef });
}