Skip to content
Snippets Groups Projects
Commit 22c45e78 authored by Alexander Rose's avatar Alexander Rose
Browse files

improved renderer and postprocessing params

parent 768ec108
Branches
No related tags found
No related merge requests found
/** /**
* 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 Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -17,6 +17,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; ...@@ -17,6 +17,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { RenderTarget } from '../../mol-gl/webgl/render-target'; import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { DrawPass } from './draw'; import { DrawPass } from './draw';
import { Camera } from '../../mol-canvas3d/camera'; import { Camera } from '../../mol-canvas3d/camera';
import { produce } from 'immer';
import quad_vert from '../../mol-gl/shader/quad.vert' import quad_vert from '../../mol-gl/shader/quad.vert'
import postprocessing_frag from '../../mol-gl/shader/postprocessing.frag' import postprocessing_frag from '../../mol-gl/shader/postprocessing.frag'
...@@ -47,14 +48,21 @@ const PostprocessingSchema = { ...@@ -47,14 +48,21 @@ const PostprocessingSchema = {
} }
export const PostprocessingParams = { export const PostprocessingParams = {
occlusionEnable: PD.Boolean(false), occlusion: PD.MappedStatic('off', {
occlusionKernelSize: PD.Numeric(4, { min: 1, max: 32, step: 1 }), on: PD.Group({
occlusionBias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }), kernelSize: PD.Numeric(4, { min: 1, max: 32, step: 1 }),
occlusionRadius: PD.Numeric(32, { min: 0, max: 256, step: 1 }), bias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
radius: PD.Numeric(64, { min: 0, max: 256, step: 1 }),
outlineEnable: PD.Boolean(false), }),
outlineScale: PD.Numeric(1, { min: 0, max: 10, step: 1 }), off: PD.Group({})
outlineThreshold: PD.Numeric(0.8, { min: 0, max: 1, step: 0.01 }), }, { 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> export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
...@@ -75,14 +83,14 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d ...@@ -75,14 +83,14 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
uFogFar: ValueCell.create(10000), uFogFar: ValueCell.create(10000),
uFogColor: ValueCell.create(Vec3.create(1, 1, 1)), uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
dOcclusionEnable: ValueCell.create(p.occlusionEnable), dOcclusionEnable: ValueCell.create(p.occlusion.name === 'on'),
dOcclusionKernelSize: ValueCell.create(p.occlusionKernelSize), dOcclusionKernelSize: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.kernelSize : 4),
uOcclusionBias: ValueCell.create(p.occlusionBias), uOcclusionBias: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.bias : 0.5),
uOcclusionRadius: ValueCell.create(p.occlusionRadius), uOcclusionRadius: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.radius : 64),
dOutlineEnable: ValueCell.create(p.outlineEnable), dOutlineEnable: ValueCell.create(p.outline.name === 'on'),
uOutlineScale: ValueCell.create(p.outlineScale * ctx.pixelRatio), uOutlineScale: ValueCell.create((p.outline.name === 'on' ? p.outline.params.scale : 1) * ctx.pixelRatio),
uOutlineThreshold: ValueCell.create(p.outlineThreshold), uOutlineThreshold: ValueCell.create(p.outline.name === 'on' ? p.outline.params.threshold : 0.8),
dPackedDepth: ValueCell.create(packedDepth), dPackedDepth: ValueCell.create(packedDepth),
} }
...@@ -108,7 +116,7 @@ export class PostprocessingPass { ...@@ -108,7 +116,7 @@ export class PostprocessingPass {
} }
get enabled() { 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) { setSize(width: number, height: number) {
...@@ -117,35 +125,28 @@ export class PostprocessingPass { ...@@ -117,35 +125,28 @@ export class PostprocessingPass {
} }
setProps(props: Partial<PostprocessingProps>) { setProps(props: Partial<PostprocessingProps>) {
if (props.occlusionEnable !== undefined) { this.props = produce(this.props, p => {
this.props.occlusionEnable = props.occlusionEnable if (props.occlusion !== undefined) {
ValueCell.update(this.renderable.values.dOcclusionEnable, props.occlusionEnable) 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.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) { if (props.outline !== undefined) {
this.props.outlineEnable = props.outlineEnable p.outline.name = props.outline.name
ValueCell.update(this.renderable.values.dOutlineEnable, props.outlineEnable) ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, props.outline.name === 'on')
} if (props.outline.name === 'on') {
if (props.outlineScale !== undefined) { p.outline.params = { ...props.outline.params }
this.props.outlineScale = props.outlineScale ValueCell.updateIfChanged(this.renderable.values.uOutlineScale, props.outline.params.scale)
ValueCell.update(this.renderable.values.uOutlineScale, props.outlineScale * this.webgl.pixelRatio) ValueCell.updateIfChanged(this.renderable.values.uOutlineThreshold, props.outline.params.threshold)
} }
if (props.outlineThreshold !== undefined) {
this.props.outlineThreshold = props.outlineThreshold
ValueCell.update(this.renderable.values.uOutlineThreshold, props.outlineThreshold)
} }
})
this.renderable.update() this.renderable.update()
} }
......
/** /**
* 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> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -55,22 +55,63 @@ export const RendererParams = { ...@@ -55,22 +55,63 @@ export const RendererParams = {
interiorColorFlag: PD.Boolean(true, { label: 'Use Interior Color' }), interiorColorFlag: PD.Boolean(true, { label: 'Use Interior Color' }),
interiorColor: PD.Color(Color.fromNormalizedRgb(0.3, 0.3, 0.3)), interiorColor: PD.Color(Color.fromNormalizedRgb(0.3, 0.3, 0.3)),
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 }), 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 }), 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 }), 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 }), 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 }), reflectivity: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
}, { isExpanded: true }),
highlightColor: PD.Color(Color.fromNormalizedRgb(1.0, 0.4, 0.6)), flat: PD.Group({}),
selectColor: PD.Color(Color.fromNormalizedRgb(0.2, 1.0, 0.1)), 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> 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 { namespace Renderer {
export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer { export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
const { gl, state, stats } = ctx const { gl, state, stats } = ctx
const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props }) const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props })
const style = getStyle(p.style)
const viewport = Viewport() const viewport = Viewport()
const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor) const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor)
...@@ -112,12 +153,12 @@ namespace Renderer { ...@@ -112,12 +153,12 @@ namespace Renderer {
uTransparentBackground: ValueCell.create(0), uTransparentBackground: ValueCell.create(0),
// the following are general 'material' uniforms // the following are general 'material' uniforms
uLightIntensity: ValueCell.create(p.lightIntensity), uLightIntensity: ValueCell.create(style.lightIntensity),
uAmbientIntensity: ValueCell.create(p.ambientIntensity), uAmbientIntensity: ValueCell.create(style.ambientIntensity),
uMetalness: ValueCell.create(p.metalness), uMetalness: ValueCell.create(style.metalness),
uRoughness: ValueCell.create(p.roughness), uRoughness: ValueCell.create(style.roughness),
uReflectivity: ValueCell.create(p.reflectivity), uReflectivity: ValueCell.create(style.reflectivity),
uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold), uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold),
...@@ -276,28 +317,6 @@ namespace Renderer { ...@@ -276,28 +317,6 @@ namespace Renderer {
ValueCell.update(globalUniforms.uInteriorColor, Color.toVec3Normalized(globalUniforms.uInteriorColor.ref.value, p.interiorColor)) 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) { if (props.highlightColor !== undefined && props.highlightColor !== p.highlightColor) {
p.highlightColor = props.highlightColor p.highlightColor = props.highlightColor
ValueCell.update(globalUniforms.uHighlightColor, Color.toVec3Normalized(globalUniforms.uHighlightColor.ref.value, p.highlightColor)) ValueCell.update(globalUniforms.uHighlightColor, Color.toVec3Normalized(globalUniforms.uHighlightColor.ref.value, p.highlightColor))
...@@ -306,6 +325,16 @@ namespace Renderer { ...@@ -306,6 +325,16 @@ namespace Renderer {
p.selectColor = props.selectColor p.selectColor = props.selectColor
ValueCell.update(globalUniforms.uSelectColor, Color.toVec3Normalized(globalUniforms.uSelectColor.ref.value, p.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) => { setViewport: (x: number, y: number, width: number, height: number) => {
gl.viewport(x, y, width, height) gl.viewport(x, y, width, height)
......
/** /**
* 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 Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
...@@ -38,9 +38,9 @@ const SimpleSettingsParams = { ...@@ -38,9 +38,9 @@ const SimpleSettingsParams = {
'transparent': PD.EmptyGroup(), 'transparent': PD.EmptyGroup(),
'opaque': PD.Group({ color: PD.Color(Color(0xFCFBF9), { description: 'Custom background color' }) }, { isFlat: true }) 'opaque': PD.Group({ color: PD.Color(Color(0xFCFBF9), { description: 'Custom background color' }) }, { isFlat: true })
}, { description: 'Background of the 3D canvas' }), }, { 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' }), renderStyle: Canvas3DParams.renderer.params.style,
occlusion: PD.Boolean(false, { description: 'Darken occluded crevices with the ambient occlusion effect' }), occlusion: Canvas3DParams.postprocessing.params.occlusion,
outline: PD.Boolean(false, { description: 'Draw outline around 3D objects' }), outline: Canvas3DParams.postprocessing.params.outline,
fog: PD.Boolean(false, { description: 'Show fog in the distance' }), fog: PD.Boolean(false, { description: 'Show fog in the distance' }),
clipFar: PD.Boolean(true, { description: 'Clip scene in the distance' }), clipFar: PD.Boolean(true, { description: 'Clip scene in the distance' }),
}; };
...@@ -60,21 +60,6 @@ const SimpleSettingsMapping = ParamMapping({ ...@@ -60,21 +60,6 @@ const SimpleSettingsMapping = ParamMapping({
const { canvas } = props; const { canvas } = props;
const renderer = canvas.renderer; 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 { return {
layout: props.layout, layout: props.layout,
spin: !!canvas.trackball.spin, spin: !!canvas.trackball.spin,
...@@ -82,9 +67,9 @@ const SimpleSettingsMapping = ParamMapping({ ...@@ -82,9 +67,9 @@ const SimpleSettingsMapping = ParamMapping({
background: (renderer.backgroundColor === ColorNames.white && canvas.transparentBackground) background: (renderer.backgroundColor === ColorNames.white && canvas.transparentBackground)
? { name: 'transparent', params: { } } ? { name: 'transparent', params: { } }
: { name: 'opaque', params: { color: renderer.backgroundColor } }, : { name: 'opaque', params: { color: renderer.backgroundColor } },
renderStyle, renderStyle: renderer.style,
occlusion: canvas.postprocessing.occlusionEnable, occlusion: canvas.postprocessing.occlusion,
outline: canvas.postprocessing.outlineEnable, outline: canvas.postprocessing.outline,
fog: ctx.canvas3d ? canvas.cameraFog > 1 : false, fog: ctx.canvas3d ? canvas.cameraFog > 1 : false,
clipFar: canvas.cameraClipFar clipFar: canvas.cameraClipFar
}; };
...@@ -95,18 +80,9 @@ const SimpleSettingsMapping = ParamMapping({ ...@@ -95,18 +80,9 @@ const SimpleSettingsMapping = ParamMapping({
canvas.cameraMode = s.camera; canvas.cameraMode = s.camera;
canvas.transparentBackground = s.background.name === 'transparent'; canvas.transparentBackground = s.background.name === 'transparent';
canvas.renderer.backgroundColor = s.background.name === 'transparent' ? ColorNames.white : s.background.params.color; canvas.renderer.backgroundColor = s.background.name === 'transparent' ? ColorNames.white : s.background.params.color;
switch (s.renderStyle) { canvas.renderer.style = s.renderStyle
case 'flat': Object.assign(canvas.renderer, { lightIntensity: 0, ambientIntensity: 1, roughness: 0.4, metalness: 0 }); break; canvas.postprocessing.occlusion = s.occlusion;
case 'matte': Object.assign(canvas.renderer, { lightIntensity: 0.6, ambientIntensity: 0.4, roughness: 1, metalness: 0 }); break; canvas.postprocessing.outline = s.outline;
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.cameraFog = s.fog ? 50 : 0; canvas.cameraFog = s.fog ? 50 : 0;
canvas.cameraClipFar = s.clipFar; canvas.cameraClipFar = s.clipFar;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment