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

wip, ssao

parent 50c2bfbe
No related branches found
No related tags found
No related merge requests found
/** /**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2018-2019 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>
*/ */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import { BehaviorSubject, Subscription } from 'rxjs'; import { BehaviorSubject, Subscription } from 'rxjs';
import { now } from 'mol-util/now'; import { now } from 'mol-util/now';
import { Vec3 } from 'mol-math/linear-algebra' import { Vec3, Vec2 } from 'mol-math/linear-algebra'
import InputObserver, { ModifiersKeys, ButtonsType } from 'mol-util/input/input-observer' import InputObserver, { ModifiersKeys, ButtonsType } from 'mol-util/input/input-observer'
import Renderer, { RendererStats, RendererParams } from 'mol-gl/renderer' import Renderer, { RendererStats, RendererParams } from 'mol-gl/renderer'
import { GraphicsRenderObject } from 'mol-gl/render-object' import { GraphicsRenderObject } from 'mol-gl/render-object'
...@@ -29,6 +29,9 @@ import { BoundingSphereHelper, DebugHelperParams } from './helper/bounding-spher ...@@ -29,6 +29,9 @@ import { BoundingSphereHelper, DebugHelperParams } from './helper/bounding-spher
import { decodeFloatRGB } from 'mol-util/float-packing'; import { decodeFloatRGB } from 'mol-util/float-packing';
import { SetUtils } from 'mol-util/set'; import { SetUtils } from 'mol-util/set';
import { Canvas3dInteractionHelper } from './helper/interaction-events'; import { Canvas3dInteractionHelper } from './helper/interaction-events';
import { createTexture } from 'mol-gl/webgl/texture';
import { ValueCell } from 'mol-util';
import { getSSAOPassRenderable, SSAOPassParams } from './passes/ssao-pass';
export const Canvas3DParams = { export const Canvas3DParams = {
// TODO: FPS cap? // TODO: FPS cap?
...@@ -37,6 +40,8 @@ export const Canvas3DParams = { ...@@ -37,6 +40,8 @@ export const Canvas3DParams = {
cameraClipDistance: PD.Numeric(0, { min: 0.0, max: 50.0, step: 0.1 }, { description: 'The distance between camera and scene at which to clip regardless of near clipping plane.' }), cameraClipDistance: PD.Numeric(0, { min: 0.0, max: 50.0, step: 0.1 }, { description: 'The distance between camera and scene at which to clip regardless of near clipping plane.' }),
clip: PD.Interval([1, 100], { min: 1, max: 100, step: 1 }), clip: PD.Interval([1, 100], { min: 1, max: 100, step: 1 }),
fog: PD.Interval([50, 100], { min: 1, max: 100, step: 1 }), fog: PD.Interval([50, 100], { min: 1, max: 100, step: 1 }),
ambientOcclusion: PD.Group(SSAOPassParams),
renderer: PD.Group(RendererParams), renderer: PD.Group(RendererParams),
trackball: PD.Group(TrackballControlsParams), trackball: PD.Group(TrackballControlsParams),
debug: PD.Group(DebugHelperParams) debug: PD.Group(DebugHelperParams)
...@@ -117,6 +122,12 @@ namespace Canvas3D { ...@@ -117,6 +122,12 @@ namespace Canvas3D {
const controls = TrackballControls.create(input, camera, p.trackball) const controls = TrackballControls.create(input, camera, p.trackball)
const renderer = Renderer.create(webgl, camera, p.renderer) const renderer = Renderer.create(webgl, camera, p.renderer)
const drawTarget = createRenderTarget(webgl, canvas.width, canvas.height)
const depthTexture = createTexture(webgl, 'image-depth', 'depth', 'ushort', 'nearest')
depthTexture.define(canvas.width, canvas.height)
depthTexture.attachFramebuffer(drawTarget.framebuffer, 'depth')
const ssaoPass = getSSAOPassRenderable(webgl, drawTarget.texture, depthTexture, p.ambientOcclusion)
let pickScale = 0.25 / webgl.pixelRatio let pickScale = 0.25 / webgl.pixelRatio
let pickWidth = Math.round(canvas.width * pickScale) let pickWidth = Math.round(canvas.width * pickScale)
let pickHeight = Math.round(canvas.height * pickScale) let pickHeight = Math.round(canvas.height * pickScale)
...@@ -215,13 +226,18 @@ namespace Canvas3D { ...@@ -215,13 +226,18 @@ namespace Canvas3D {
renderer.render(scene, 'pickGroup'); renderer.render(scene, 'pickGroup');
break; break;
case 'draw': case 'draw':
webgl.unbindFramebuffer();
renderer.setViewport(0, 0, canvas.width, canvas.height); renderer.setViewport(0, 0, canvas.width, canvas.height);
renderer.render(scene, variant); drawTarget.bind()
renderer.render(scene, 'draw');
if (debugHelper.isEnabled) { if (debugHelper.isEnabled) {
debugHelper.syncVisibility() debugHelper.syncVisibility()
renderer.render(debugHelper.scene, 'draw') renderer.render(debugHelper.scene, 'draw')
} }
webgl.unbindFramebuffer();
webgl.state.disable(webgl.gl.SCISSOR_TEST)
webgl.state.disable(webgl.gl.BLEND)
webgl.state.disable(webgl.gl.DEPTH_TEST)
ssaoPass.render()
pickDirty = true pickDirty = true
break; break;
} }
...@@ -395,6 +411,25 @@ namespace Canvas3D { ...@@ -395,6 +411,25 @@ namespace Canvas3D {
if (props.clip !== undefined) p.clip = [props.clip[0], props.clip[1]] if (props.clip !== undefined) p.clip = [props.clip[0], props.clip[1]]
if (props.fog !== undefined) p.fog = [props.fog[0], props.fog[1]] if (props.fog !== undefined) p.fog = [props.fog[0], props.fog[1]]
if (props.ambientOcclusion) {
if (props.ambientOcclusion.enable !== undefined) {
p.ambientOcclusion.enable = props.ambientOcclusion.enable
ValueCell.update(ssaoPass.values.uEnable, props.ambientOcclusion.enable ? 1 : 0)
}
if (props.ambientOcclusion.kernelSize !== undefined) {
p.ambientOcclusion.kernelSize = props.ambientOcclusion.kernelSize
ValueCell.update(ssaoPass.values.uKernelSize, props.ambientOcclusion.kernelSize)
}
if (props.ambientOcclusion.bias !== undefined) {
p.ambientOcclusion.bias = props.ambientOcclusion.bias
ValueCell.update(ssaoPass.values.uBias, props.ambientOcclusion.bias)
}
if (props.ambientOcclusion.radius !== undefined) {
p.ambientOcclusion.radius = props.ambientOcclusion.radius
ValueCell.update(ssaoPass.values.uRadius, props.ambientOcclusion.radius)
}
}
if (props.renderer) renderer.setProps(props.renderer) if (props.renderer) renderer.setProps(props.renderer)
if (props.trackball) controls.setProps(props.trackball) if (props.trackball) controls.setProps(props.trackball)
if (props.debug) debugHelper.setProps(props.debug) if (props.debug) debugHelper.setProps(props.debug)
...@@ -407,6 +442,8 @@ namespace Canvas3D { ...@@ -407,6 +442,8 @@ namespace Canvas3D {
cameraClipDistance: p.cameraClipDistance, cameraClipDistance: p.cameraClipDistance,
clip: p.clip, clip: p.clip,
fog: p.fog, fog: p.fog,
ambientOcclusion: { ...p.ambientOcclusion },
renderer: { ...renderer.props }, renderer: { ...renderer.props },
trackball: { ...controls.props }, trackball: { ...controls.props },
debug: { ...debugHelper.props } debug: { ...debugHelper.props }
...@@ -438,6 +475,10 @@ namespace Canvas3D { ...@@ -438,6 +475,10 @@ namespace Canvas3D {
Viewport.set(camera.viewport, 0, 0, canvas.width, canvas.height) Viewport.set(camera.viewport, 0, 0, canvas.width, canvas.height)
Viewport.set(controls.viewport, 0, 0, canvas.width, canvas.height) Viewport.set(controls.viewport, 0, 0, canvas.width, canvas.height)
drawTarget.setSize(canvas.width, canvas.height)
depthTexture.define(canvas.width, canvas.height)
ValueCell.update(ssaoPass.values.uTexSize, Vec2.set(ssaoPass.values.uTexSize.ref.value, canvas.width, canvas.height))
pickScale = 0.25 / webgl.pixelRatio pickScale = 0.25 / webgl.pixelRatio
pickWidth = Math.round(canvas.width * pickScale) pickWidth = Math.round(canvas.width * pickScale)
pickHeight = Math.round(canvas.height * pickScale) pickHeight = Math.round(canvas.height * pickScale)
......
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { QuadSchema, QuadValues } from 'mol-gl/compute/util';
import { TextureSpec, Values, UniformSpec } from 'mol-gl/renderable/schema';
import { ShaderCode } from 'mol-gl/shader-code';
import { WebGLContext } from 'mol-gl/webgl/context';
import { Texture } from 'mol-gl/webgl/texture';
import { ValueCell } from 'mol-util';
import { createComputeRenderItem } from 'mol-gl/webgl/render-item';
import { createComputeRenderable } from 'mol-gl/renderable';
import { Vec2 } from 'mol-math/linear-algebra';
import { ParamDefinition as PD } from 'mol-util/param-definition';
const SSAOPassSchema = {
...QuadSchema,
tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
uTexSize: UniformSpec('v2'),
uEnable: UniformSpec('i'),
uKernelSize: UniformSpec('i'),
uBias: UniformSpec('f'),
uRadius: UniformSpec('f'),
}
export const SSAOPassParams = {
enable: PD.Boolean(true),
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 }),
}
export type SSAOPassProps = PD.Values<typeof SSAOPassParams>
export function getSSAOPassRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture, props: Partial<SSAOPassProps>) {
const p = { ...PD.getDefaultValues(SSAOPassParams), props }
const values: Values<typeof SSAOPassSchema> = {
...QuadValues,
tColor: ValueCell.create(colorTexture),
tDepth: ValueCell.create(depthTexture),
uTexSize: ValueCell.create(Vec2.create(colorTexture.width, colorTexture.height)),
uEnable: ValueCell.create(p.enable ? 1 : 0),
uKernelSize: ValueCell.create(p.kernelSize),
uBias: ValueCell.create(p.bias),
uRadius: ValueCell.create(p.radius),
}
const schema = { ...SSAOPassSchema }
const shaderCode = ShaderCode(
require('mol-gl/shader/quad.vert').default,
require('mol-gl/shader/passes/ssao.frag').default
)
const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values)
return createComputeRenderable(renderItem, values)
}
\ No newline at end of file
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D tColor;
uniform sampler2D tDepth;
uniform vec2 uTexSize;
uniform int uEnable;
uniform int uKernelSize;
uniform float uBias;
uniform float uRadius;
const float noiseAmount = 0.0002;
float noise(vec2 coords) {
float a = 12.9898;
float b = 78.233;
float c = 43758.5453;
float dt = dot(coords, vec2(a,b));
float sn = mod(dt, 3.14159);
return fract(sin(sn) * c);
}
float calcSSAO(in vec2 coords, in float depth) {
float occlusionFactor = 0.0;
for (int i = -uKernelSize; i <= uKernelSize; i++) {
for (int j = -uKernelSize; j <= uKernelSize; j++) {
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;
}
}
return occlusionFactor / float((2 * uKernelSize + 1) * (2 * uKernelSize + 1));
}
void main(void) {
vec2 coords = gl_FragCoord.xy / uTexSize;
vec4 color = texture(tColor, coords);
float depth = texture(tDepth, coords).r;
// calculate screen-space ambient occlusion
if ((uEnable != 0) && (depth != 1.0)) {
float occlusionFactor = calcSSAO(coords, depth);
color = mix(color, vec4(0.0, 0.0, 0.0, 1.0), uBias * occlusionFactor);
}
gl_FragColor = color;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment