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

refactored multi-sample pass

parent 320144b3
No related branches found
No related tags found
No related merge requests found
...@@ -30,8 +30,10 @@ const gl = createContext(width, height, { ...@@ -30,8 +30,10 @@ const gl = createContext(width, height, {
const input = InputObserver.create() const input = InputObserver.create()
const canvas3d = Canvas3D.create(gl, input, { const canvas3d = Canvas3D.create(gl, input, {
multiSample: 'on', multiSample: {
sampleLevel: 3, mode: 'on',
sampleLevel: 3
},
renderer: { renderer: {
...Canvas3DParams.renderer.defaultValue, ...Canvas3DParams.renderer.defaultValue,
lightIntensity: 0, lightIntensity: 0,
......
...@@ -6,12 +6,10 @@ ...@@ -6,12 +6,10 @@
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'
import { TrackballControls, TrackballControlsParams } from './controls/trackball' import { TrackballControls, TrackballControlsParams } from './controls/trackball'
import { Viewport } from './camera/util' import { Viewport } from './camera/util'
import { createContext, WebGLContext, getGLContext } from 'mol-gl/webgl/context'; import { createContext, WebGLContext, getGLContext } from 'mol-gl/webgl/context';
...@@ -29,9 +27,8 @@ import { decodeFloatRGB } from 'mol-util/float-packing'; ...@@ -29,9 +27,8 @@ 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 { createTexture } from 'mol-gl/webgl/texture';
import { ValueCell } from 'mol-util';
import { PostprocessingParams, PostprocessingPass } from './helper/postprocessing'; import { PostprocessingParams, PostprocessingPass } from './helper/postprocessing';
import { JitterVectors, getComposeRenderable } from './helper/multi-sample'; import { MultiSampleParams, MultiSamplePass } from './helper/multi-sample';
import { GLRenderingContext } from 'mol-gl/webgl/compat'; import { GLRenderingContext } from 'mol-gl/webgl/compat';
import { PixelData } from 'mol-util/image'; import { PixelData } from 'mol-util/image';
import { readTexture } from 'mol-gl/compute/util'; import { readTexture } from 'mol-gl/compute/util';
...@@ -44,9 +41,7 @@ export const Canvas3DParams = { ...@@ -44,9 +41,7 @@ export const Canvas3DParams = {
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 }),
multiSample: PD.Select('off', [['off', 'Off'], ['on', 'On'], ['temporal', 'Temporal']]), multiSample: PD.Group(MultiSampleParams),
sampleLevel: PD.Numeric(2, { min: 0, max: 5, step: 1 }),
postprocessing: PD.Group(PostprocessingParams), postprocessing: PD.Group(PostprocessingParams),
renderer: PD.Group(RendererParams), renderer: PD.Group(RendererParams),
trackball: PD.Group(TrackballControlsParams), trackball: PD.Group(TrackballControlsParams),
...@@ -127,7 +122,6 @@ namespace Canvas3D { ...@@ -127,7 +122,6 @@ namespace Canvas3D {
}) })
const webgl = createContext(gl) const webgl = createContext(gl)
const { state } = webgl
let width = gl.drawingBufferWidth let width = gl.drawingBufferWidth
let height = gl.drawingBufferHeight let height = gl.drawingBufferHeight
...@@ -145,10 +139,7 @@ namespace Canvas3D { ...@@ -145,10 +139,7 @@ namespace Canvas3D {
} }
const postprocessing = new PostprocessingPass(webgl, drawTarget.texture, depthTexture, !!depthTarget, p.postprocessing) const postprocessing = new PostprocessingPass(webgl, drawTarget.texture, depthTexture, !!depthTarget, p.postprocessing)
const multiSample = new MultiSamplePass(webgl, camera, drawTarget, postprocessing, renderDraw, p.multiSample)
const composeTarget = createRenderTarget(webgl, width, height)
const holdTarget = createRenderTarget(webgl, width, height)
const compose = getComposeRenderable(webgl, drawTarget.texture)
const pickBaseScale = 0.5 const pickBaseScale = 0.5
let pickScale = pickBaseScale / webgl.pixelRatio let pickScale = pickBaseScale / webgl.pixelRatio
...@@ -163,9 +154,6 @@ namespace Canvas3D { ...@@ -163,9 +154,6 @@ namespace Canvas3D {
let isUpdating = false let isUpdating = false
let drawPending = false let drawPending = false
let multiSampleIndex = -1
let multiSample = false
const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug); const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug);
const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input); const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input);
...@@ -249,166 +237,6 @@ namespace Canvas3D { ...@@ -249,166 +237,6 @@ namespace Canvas3D {
} }
} }
function renderTemporalMultiSample() {
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
//
// This manual approach to MSAA re-renders the scene once for
// each sample with camera jitter and accumulates the results.
const offsetList = JitterVectors[ Math.max(0, Math.min(p.sampleLevel, 5)) ]
if (multiSampleIndex === -1) return
if (multiSampleIndex >= offsetList.length) {
multiSampleIndex = -1
return
}
const i = multiSampleIndex
if (i === 0) {
drawTarget.bind()
renderDraw()
if (postprocessing.enabled) postprocessing.render(false)
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawTarget.texture)
compose.update()
holdTarget.bind()
state.disable(gl.BLEND)
compose.render()
}
const sampleWeight = 1.0 / offsetList.length
camera.viewOffset.enabled = true
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawTarget.texture)
ValueCell.update(compose.values.uWeight, sampleWeight)
compose.update()
const { width, height } = drawTarget
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
const numSamplesPerFrame = Math.pow(2, p.sampleLevel)
for (let i = 0; i < numSamplesPerFrame; ++i) {
const offset = offsetList[multiSampleIndex]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
// render scene and optionally postprocess
drawTarget.bind()
renderDraw()
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
composeTarget.bind()
state.enable(gl.BLEND)
state.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)
state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)
state.disable(gl.DEPTH_TEST)
state.disable(gl.SCISSOR_TEST)
state.depthMask(false)
if (multiSampleIndex === 0) {
webgl.state.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)
}
compose.render()
multiSampleIndex += 1
if (multiSampleIndex >= offsetList.length ) break
}
const accumulationWeight = multiSampleIndex * sampleWeight
if (accumulationWeight > 0) {
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
}
if (accumulationWeight < 1.0) {
ValueCell.update(compose.values.uWeight, 1.0 - accumulationWeight)
ValueCell.update(compose.values.tColor, holdTarget.texture)
compose.update()
webgl.unbindFramebuffer()
gl.viewport(0, 0, width, height)
if (accumulationWeight === 0) state.disable(gl.BLEND)
else state.enable(gl.BLEND)
compose.render()
}
camera.viewOffset.enabled = false
camera.updateMatrices()
if (multiSampleIndex >= offsetList.length) multiSampleIndex = -1
}
function renderMultiSample() {
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
//
// This manual approach to MSAA re-renders the scene once for
// each sample with camera jitter and accumulates the results.
const offsetList = JitterVectors[ Math.max(0, Math.min(p.sampleLevel, 5)) ]
const baseSampleWeight = 1.0 / offsetList.length
const roundingRange = 1 / 32
camera.viewOffset.enabled = true
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawTarget.texture)
compose.update()
const { width, height } = drawTarget
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
for (let i = 0; i < offsetList.length; ++i) {
const offset = offsetList[i]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
// the theory is that equal weights for each sample lead to an accumulation of rounding
// errors. The following equation varies the sampleWeight per sample so that it is uniformly
// distributed across a range of values whose rounding errors cancel each other out.
const uniformCenteredDistribution = -0.5 + (i + 0.5) / offsetList.length
const sampleWeight = baseSampleWeight + roundingRange * uniformCenteredDistribution
ValueCell.update(compose.values.uWeight, sampleWeight)
// render scene and optionally postprocess
drawTarget.bind()
renderDraw()
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
composeTarget.bind()
gl.viewport(0, 0, width, height)
state.enable(gl.BLEND)
state.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)
state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)
state.disable(gl.DEPTH_TEST)
state.disable(gl.SCISSOR_TEST)
state.depthMask(false)
if (i === 0) {
webgl.state.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)
}
compose.render()
}
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
camera.viewOffset.enabled = false
camera.updateMatrices()
}
function render(variant: 'pick' | 'draw', force: boolean) { function render(variant: 'pick' | 'draw', force: boolean) {
if (isIdentifying || isUpdating) return false if (isIdentifying || isUpdating) return false
...@@ -417,21 +245,9 @@ namespace Canvas3D { ...@@ -417,21 +245,9 @@ namespace Canvas3D {
// TODO: is this a good fix? Also, setClipping does not work if the user has manually set a clipping plane. // TODO: is this a good fix? Also, setClipping does not work if the user has manually set a clipping plane.
if (!camera.transition.inTransition) setClipping(); if (!camera.transition.inTransition) setClipping();
const cameraChanged = camera.updateMatrices(); const cameraChanged = camera.updateMatrices();
if (force || cameraChanged) lastRenderTime = now() multiSample.update(force || cameraChanged, currentTime)
if (p.multiSample === 'temporal') {
if (currentTime - lastRenderTime > 200) {
multiSample = multiSampleIndex !== -1
} else {
multiSampleIndex = 0
multiSample = false
}
} else if (p.multiSample === 'on') {
multiSample = true
} else {
multiSample = false
}
if (force || cameraChanged || multiSample) { if (force || cameraChanged || multiSample.enabled) {
switch (variant) { switch (variant) {
case 'pick': case 'pick':
renderer.setViewport(0, 0, pickWidth, pickHeight); renderer.setViewport(0, 0, pickWidth, pickHeight);
...@@ -444,12 +260,8 @@ namespace Canvas3D { ...@@ -444,12 +260,8 @@ namespace Canvas3D {
break; break;
case 'draw': case 'draw':
renderer.setViewport(0, 0, width, height); renderer.setViewport(0, 0, width, height);
if (multiSample) { if (multiSample.enabled) {
if (p.multiSample === 'temporal') { multiSample.render()
renderTemporalMultiSample()
} else {
renderMultiSample()
}
} else { } else {
if (postprocessing.enabled) drawTarget.bind() if (postprocessing.enabled) drawTarget.bind()
else webgl.unbindFramebuffer() else webgl.unbindFramebuffer()
...@@ -467,7 +279,6 @@ namespace Canvas3D { ...@@ -467,7 +279,6 @@ namespace Canvas3D {
let forceNextDraw = false; let forceNextDraw = false;
let currentTime = 0; let currentTime = 0;
let lastRenderTime = 0;
function draw(force?: boolean) { function draw(force?: boolean) {
if (render('draw', !!force || forceNextDraw)) { if (render('draw', !!force || forceNextDraw)) {
...@@ -636,11 +447,8 @@ namespace Canvas3D { ...@@ -636,11 +447,8 @@ 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.multiSample !== undefined) p.multiSample = props.multiSample
if (props.sampleLevel !== undefined) p.sampleLevel = props.sampleLevel
if (props.postprocessing) postprocessing.setProps(props.postprocessing) if (props.postprocessing) postprocessing.setProps(props.postprocessing)
if (props.multiSample) multiSample.setProps(props.multiSample)
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)
...@@ -654,10 +462,8 @@ namespace Canvas3D { ...@@ -654,10 +462,8 @@ namespace Canvas3D {
clip: p.clip, clip: p.clip,
fog: p.fog, fog: p.fog,
multiSample: p.multiSample,
sampleLevel: p.sampleLevel,
postprocessing: { ...postprocessing.props }, postprocessing: { ...postprocessing.props },
multiSample: { ...multiSample.props },
renderer: { ...renderer.props }, renderer: { ...renderer.props },
trackball: { ...controls.props }, trackball: { ...controls.props },
debug: { ...debugHelper.props } debug: { ...debugHelper.props }
...@@ -693,14 +499,13 @@ namespace Canvas3D { ...@@ -693,14 +499,13 @@ namespace Canvas3D {
drawTarget.setSize(width, height) drawTarget.setSize(width, height)
postprocessing.setSize(width, height) postprocessing.setSize(width, height)
composeTarget.setSize(width, height) multiSample.setSize(width, height)
holdTarget.setSize(width, height)
if (depthTarget) { if (depthTarget) {
depthTarget.setSize(width, height) depthTarget.setSize(width, height)
} else { } else {
depthTexture.define(width, height) depthTexture.define(width, height)
} }
ValueCell.update(compose.values.uTexSize, Vec2.set(compose.values.uTexSize.ref.value, width, height))
pickScale = pickBaseScale / webgl.pixelRatio pickScale = pickBaseScale / webgl.pixelRatio
pickWidth = Math.round(width * pickScale) pickWidth = Math.round(width * pickScale)
......
...@@ -12,7 +12,11 @@ import { ValueCell } from 'mol-util'; ...@@ -12,7 +12,11 @@ import { ValueCell } from 'mol-util';
import { Vec2 } from 'mol-math/linear-algebra'; import { Vec2 } from 'mol-math/linear-algebra';
import { ShaderCode } from 'mol-gl/shader-code'; import { ShaderCode } from 'mol-gl/shader-code';
import { createComputeRenderItem } from 'mol-gl/webgl/render-item'; import { createComputeRenderItem } from 'mol-gl/webgl/render-item';
import { createComputeRenderable } from 'mol-gl/renderable'; import { createComputeRenderable, ComputeRenderable } from 'mol-gl/renderable';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { RenderTarget, createRenderTarget } from 'mol-gl/webgl/render-target';
import { Camera } from 'mol-canvas3d/camera';
import { PostprocessingPass } from './postprocessing';
const ComposeSchema = { const ComposeSchema = {
...QuadSchema, ...QuadSchema,
...@@ -21,7 +25,9 @@ const ComposeSchema = { ...@@ -21,7 +25,9 @@ const ComposeSchema = {
uWeight: UniformSpec('f'), uWeight: UniformSpec('f'),
} }
export function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture) { type ComposeRenderable = ComputeRenderable<Values<typeof ComposeSchema>>
function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture): ComposeRenderable {
const values: Values<typeof ComposeSchema> = { const values: Values<typeof ComposeSchema> = {
...QuadValues, ...QuadValues,
tColor: ValueCell.create(colorTexture), tColor: ValueCell.create(colorTexture),
...@@ -39,7 +45,238 @@ export function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture) { ...@@ -39,7 +45,238 @@ export function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture) {
return createComputeRenderable(renderItem, values) return createComputeRenderable(renderItem, values)
} }
export const JitterVectors = [ export const MultiSampleParams = {
mode: PD.Select('off', [['off', 'Off'], ['on', 'On'], ['temporal', 'Temporal']]),
sampleLevel: PD.Numeric(2, { min: 0, max: 5, step: 1 }),
}
export type MultiSampleProps = PD.Values<typeof MultiSampleParams>
export class MultiSamplePass {
props: MultiSampleProps
private composeTarget: RenderTarget
private holdTarget: RenderTarget
private compose: ComposeRenderable
private sampleIndex = -1
private currentTime = 0
private lastRenderTime = 0
constructor(private webgl: WebGLContext, private camera: Camera, private drawTarget: RenderTarget, private postprocessing: PostprocessingPass, private renderDraw: () => void, props: Partial<MultiSampleProps>) {
const { gl } = webgl
this.composeTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.holdTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.compose = getComposeRenderable(webgl, drawTarget.texture)
this.props = { ...PD.getDefaultValues(MultiSampleParams), ...props }
}
get enabled() {
if (this.props.mode === 'temporal') {
if (this.currentTime - this.lastRenderTime > 200) {
return this.sampleIndex !== -1
} else {
this.sampleIndex = 0
return false
}
} else if (this.props.mode === 'on') {
return true
} else {
return false
}
}
update(changed: boolean, currentTime: number) {
if (changed) this.lastRenderTime = currentTime
this.currentTime = currentTime
}
setSize(width: number, height: number) {
this.composeTarget.setSize(width, height)
this.holdTarget.setSize(width, height)
ValueCell.update(this.compose.values.uTexSize, Vec2.set(this.compose.values.uTexSize.ref.value, width, height))
}
setProps(props: Partial<MultiSampleProps>) {
if (props.mode !== undefined) this.props.mode = props.mode
if (props.sampleLevel !== undefined) this.props.sampleLevel = props.sampleLevel
}
render() {
if (this.props.mode === 'temporal') {
this.renderTemporalMultiSample()
} else {
this.renderMultiSample()
}
}
private renderMultiSample() {
const { camera, compose, drawTarget, composeTarget, postprocessing, renderDraw, webgl } = this
const { gl, state } = webgl
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
//
// This manual approach to MSAA re-renders the scene once for
// each sample with camera jitter and accumulates the results.
const offsetList = JitterVectors[ Math.max(0, Math.min(this.props.sampleLevel, 5)) ]
const baseSampleWeight = 1.0 / offsetList.length
const roundingRange = 1 / 32
camera.viewOffset.enabled = true
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawTarget.texture)
compose.update()
const { width, height } = drawTarget
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
for (let i = 0; i < offsetList.length; ++i) {
const offset = offsetList[i]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
// the theory is that equal weights for each sample lead to an accumulation of rounding
// errors. The following equation varies the sampleWeight per sample so that it is uniformly
// distributed across a range of values whose rounding errors cancel each other out.
const uniformCenteredDistribution = -0.5 + (i + 0.5) / offsetList.length
const sampleWeight = baseSampleWeight + roundingRange * uniformCenteredDistribution
ValueCell.update(compose.values.uWeight, sampleWeight)
// render scene and optionally postprocess
drawTarget.bind()
renderDraw()
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
composeTarget.bind()
gl.viewport(0, 0, width, height)
state.enable(gl.BLEND)
state.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)
state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)
state.disable(gl.DEPTH_TEST)
state.disable(gl.SCISSOR_TEST)
state.depthMask(false)
if (i === 0) {
state.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)
}
compose.render()
}
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
camera.viewOffset.enabled = false
camera.updateMatrices()
}
private renderTemporalMultiSample() {
const { camera, compose, drawTarget, composeTarget, holdTarget, postprocessing, renderDraw, webgl } = this
const { gl, state } = webgl
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
//
// This manual approach to MSAA re-renders the scene once for
// each sample with camera jitter and accumulates the results.
const offsetList = JitterVectors[ Math.max(0, Math.min(this.props.sampleLevel, 5)) ]
if (this.sampleIndex === -1) return
if (this.sampleIndex >= offsetList.length) {
this.sampleIndex = -1
return
}
const i = this.sampleIndex
if (i === 0) {
drawTarget.bind()
renderDraw()
if (postprocessing.enabled) postprocessing.render(false)
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawTarget.texture)
compose.update()
holdTarget.bind()
state.disable(gl.BLEND)
compose.render()
}
const sampleWeight = 1.0 / offsetList.length
camera.viewOffset.enabled = true
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawTarget.texture)
ValueCell.update(compose.values.uWeight, sampleWeight)
compose.update()
const { width, height } = drawTarget
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
const numSamplesPerFrame = Math.pow(2, this.props.sampleLevel)
for (let i = 0; i < numSamplesPerFrame; ++i) {
const offset = offsetList[this.sampleIndex]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
// render scene and optionally postprocess
drawTarget.bind()
renderDraw()
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
composeTarget.bind()
state.enable(gl.BLEND)
state.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)
state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)
state.disable(gl.DEPTH_TEST)
state.disable(gl.SCISSOR_TEST)
state.depthMask(false)
if (this.sampleIndex === 0) {
state.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)
}
compose.render()
this.sampleIndex += 1
if (this.sampleIndex >= offsetList.length ) break
}
const accumulationWeight = this.sampleIndex * sampleWeight
if (accumulationWeight > 0) {
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
}
if (accumulationWeight < 1.0) {
ValueCell.update(compose.values.uWeight, 1.0 - accumulationWeight)
ValueCell.update(compose.values.tColor, holdTarget.texture)
compose.update()
webgl.unbindFramebuffer()
gl.viewport(0, 0, width, height)
if (accumulationWeight === 0) state.disable(gl.BLEND)
else state.enable(gl.BLEND)
compose.render()
}
camera.viewOffset.enabled = false
camera.updateMatrices()
if (this.sampleIndex >= offsetList.length) this.sampleIndex = -1
}
}
const JitterVectors = [
[ [
[ 0, 0 ] [ 0, 0 ]
], ],
......
...@@ -48,7 +48,7 @@ export type PostprocessingProps = PD.Values<typeof PostprocessingParams> ...@@ -48,7 +48,7 @@ export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>> type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
export function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture, packedDepth: boolean, props: Partial<PostprocessingProps>): PostprocessingRenderable { function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTexture: Texture, packedDepth: boolean, props: Partial<PostprocessingProps>): PostprocessingRenderable {
const p = { ...PD.getDefaultValues(PostprocessingParams), ...props } const p = { ...PD.getDefaultValues(PostprocessingParams), ...props }
const values: Values<typeof PostprocessingSchema> = { const values: Values<typeof PostprocessingSchema> = {
...QuadValues, ...QuadValues,
......
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