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

temporal msaa

parent 147897cc
No related branches found
No related tags found
No related merge requests found
...@@ -42,7 +42,8 @@ export const Canvas3DParams = { ...@@ -42,7 +42,8 @@ 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 }),
sampleLevel: PD.Numeric(0, { min: 0, max: 5, step: 1 }), multiSample: PD.Select('off', [['off', 'Off'], ['on', 'On'], ['temporal', 'Temporal']]),
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),
...@@ -135,6 +136,7 @@ namespace Canvas3D { ...@@ -135,6 +136,7 @@ namespace Canvas3D {
const postprocessing = getPostprocessingRenderable(webgl, drawTarget.texture, depthTexture, p.postprocessing) const postprocessing = getPostprocessingRenderable(webgl, drawTarget.texture, depthTexture, p.postprocessing)
const composeTarget = createRenderTarget(webgl, canvas.width, canvas.height) const composeTarget = createRenderTarget(webgl, canvas.width, canvas.height)
const holdTarget = createRenderTarget(webgl, canvas.width, canvas.height)
const compose = getComposeRenderable(webgl, drawTarget.texture) const compose = getComposeRenderable(webgl, drawTarget.texture)
const pickBaseScale = 0.25 const pickBaseScale = 0.25
...@@ -150,6 +152,9 @@ namespace Canvas3D { ...@@ -150,6 +152,9 @@ 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);
...@@ -233,11 +238,112 @@ namespace Canvas3D { ...@@ -233,11 +238,112 @@ namespace Canvas3D {
postprocessing.render() postprocessing.render()
} }
function renderTemporalMultiSample(postprocessingEnabled: boolean) {
// 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 (postprocessingEnabled) {
postprocessingTarget.bind()
renderPostprocessing()
}
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, postprocessingEnabled ? postprocessingTarget.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, postprocessingEnabled ? postprocessingTarget.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 (postprocessingEnabled) {
postprocessingTarget.bind()
renderPostprocessing()
}
// 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, canvas.width, canvas.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, canvas.width, canvas.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(postprocessingEnabled: boolean) { function renderMultiSample(postprocessingEnabled: boolean) {
// based on the Multisample Anti-Aliasing Render Pass // based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/ // contributed to three.js by bhouston / http://clara.io/
// //
// This manual approach to MSAA re-renders the scene ones for // This manual approach to MSAA re-renders the scene once for
// each sample with camera jitter and accumulates the results. // each sample with camera jitter and accumulates the results.
const offsetList = JitterVectors[ Math.max(0, Math.min(p.sampleLevel, 5)) ] const offsetList = JitterVectors[ Math.max(0, Math.min(p.sampleLevel, 5)) ]
...@@ -272,7 +378,7 @@ namespace Canvas3D { ...@@ -272,7 +378,7 @@ namespace Canvas3D {
renderPostprocessing() renderPostprocessing()
} }
// compose rendered scene with hold target // compose rendered scene with compose target
composeTarget.bind() composeTarget.bind()
gl.viewport(0, 0, canvas.width, canvas.height) gl.viewport(0, 0, canvas.width, canvas.height)
state.enable(gl.BLEND) state.enable(gl.BLEND)
...@@ -309,9 +415,22 @@ namespace Canvas3D { ...@@ -309,9 +415,22 @@ 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()
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
}
const postprocessingEnabled = p.postprocessing.occlusionEnable || p.postprocessing.outlineEnable const postprocessingEnabled = p.postprocessing.occlusionEnable || p.postprocessing.outlineEnable
if (force || cameraChanged) { if (force || cameraChanged || multiSample) {
switch (variant) { switch (variant) {
case 'pick': case 'pick':
renderer.setViewport(0, 0, pickWidth, pickHeight); renderer.setViewport(0, 0, pickWidth, pickHeight);
...@@ -324,8 +443,12 @@ namespace Canvas3D { ...@@ -324,8 +443,12 @@ namespace Canvas3D {
break; break;
case 'draw': case 'draw':
renderer.setViewport(0, 0, canvas.width, canvas.height); renderer.setViewport(0, 0, canvas.width, canvas.height);
if (p.sampleLevel > 0) { if (multiSample) {
renderMultiSample(postprocessingEnabled) if (p.multiSample === 'temporal') {
renderTemporalMultiSample(postprocessingEnabled)
} else {
renderMultiSample(postprocessingEnabled)
}
} else { } else {
if (postprocessingEnabled) drawTarget.bind() if (postprocessingEnabled) drawTarget.bind()
else webgl.unbindFramebuffer() else webgl.unbindFramebuffer()
...@@ -346,6 +469,7 @@ namespace Canvas3D { ...@@ -346,6 +469,7 @@ 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)) {
...@@ -508,6 +632,7 @@ namespace Canvas3D { ...@@ -508,6 +632,7 @@ 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.sampleLevel !== undefined) p.sampleLevel = props.sampleLevel
if (props.postprocessing) { if (props.postprocessing) {
...@@ -557,6 +682,7 @@ namespace Canvas3D { ...@@ -557,6 +682,7 @@ namespace Canvas3D {
clip: p.clip, clip: p.clip,
fog: p.fog, fog: p.fog,
multiSample: p.multiSample,
sampleLevel: p.sampleLevel, sampleLevel: p.sampleLevel,
postprocessing: { ...p.postprocessing }, postprocessing: { ...p.postprocessing },
...@@ -594,6 +720,7 @@ namespace Canvas3D { ...@@ -594,6 +720,7 @@ namespace Canvas3D {
drawTarget.setSize(canvas.width, canvas.height) drawTarget.setSize(canvas.width, canvas.height)
postprocessingTarget.setSize(canvas.width, canvas.height) postprocessingTarget.setSize(canvas.width, canvas.height)
composeTarget.setSize(canvas.width, canvas.height) composeTarget.setSize(canvas.width, canvas.height)
holdTarget.setSize(canvas.width, canvas.height)
depthTexture.define(canvas.width, canvas.height) depthTexture.define(canvas.width, canvas.height)
ValueCell.update(postprocessing.values.uTexSize, Vec2.set(postprocessing.values.uTexSize.ref.value, canvas.width, canvas.height)) ValueCell.update(postprocessing.values.uTexSize, Vec2.set(postprocessing.values.uTexSize.ref.value, canvas.width, canvas.height))
ValueCell.update(compose.values.uTexSize, Vec2.set(compose.values.uTexSize.ref.value, canvas.width, canvas.height)) ValueCell.update(compose.values.uTexSize, Vec2.set(compose.values.uTexSize.ref.value, canvas.width, canvas.height))
......
...@@ -70,7 +70,7 @@ export const JitterVectors = [ ...@@ -70,7 +70,7 @@ export const JitterVectors = [
[ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ]
] ]
] ]
JitterVectors.forEach(offsetList => { JitterVectors.forEach(offsetList => {
offsetList.forEach(offset => { offsetList.forEach(offset => {
// 0.0625 = 1 / 16 // 0.0625 = 1 / 16
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment