A lot of changes. Pipeline rework is more or less complete. Added individual output for some pipeline passes that we might want to inspect inside the sandbox.

This commit is contained in:
AlexandruPopovici
2022-10-14 00:36:33 +03:00
parent 75a2a6ca93
commit b5cfe00c04
13 changed files with 583 additions and 257 deletions
+139 -122
View File
@@ -30,26 +30,20 @@ export default class Sandbox {
tonemapping: 4 //'ACESFilmicToneMapping'
}
public static postParams = {
saoEnabled: true,
saoParams: {
saoBias: 0.15,
saoIntensity: 1.25,
saoScale: 434,
saoKernelRadius: 15,
saoMinResolution: 0,
saoBlur: true,
saoBlurRadius: 4,
saoBlurStdDev: 4,
saoBlurDepthCutoff: 0.0007
},
saoScaleOffset: 0,
saoNormalsRendering: 2,
minDistance: 0.0,
maxDistance: 0.008,
ssaoKernelRadius: 0.5,
progressiveAO: 0,
progressive: true
public static pipelineParams = {
pipelineOutput: 8,
dynamicAoEnabled: true,
dynamicAoParams: {
intensity: 1.25,
scale: 0,
kernelRadius: 10,
bias: 0.15,
normalsType: 2,
blurEnabled: true,
blurRadius: 4,
blurStdDev: 4,
blurDepthCutoff: 0.0007
}
}
public static lightParams: SunLightConfiguration = {
@@ -343,33 +337,88 @@ export default class Sandbox {
this.viewer.getRenderer().renderer.toneMapping = Sandbox.sceneParams.tonemapping
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams, 'saoEnabled', { label: 'SAO-ENABLED' })
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams.saoParams, 'saoBias', {
min: -1,
max: 1
const pipelineFolder = this.tabs.pages[1].addFolder({
title: 'Pipeline',
expanded: true
})
pipelineFolder
.addInput(Sandbox.pipelineParams, 'pipelineOutput', {
options: {
DEPTH_RGBA: 0,
DEPTH: 1,
COLOR: 2,
GEOMETRY_NORMALS: 3,
RECONSTRUCTED_NORMALS: 4,
DYNAMIC_AO: 5,
DYNAMIC_AO_BLURED: 6,
PROGRESSIVE_AO: 7,
FINAL: 8
}
})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams.saoParams, 'saoIntensity', {
min: 0,
max: 5
})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
this.viewer.requestRender()
})
// postFolder
// .addInput(Sandbox.postParams, 'saoEnabled', { label: 'SAO-ENABLED' })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoBias', {
// min: -1,
// max: 1
// })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoIntensity', {
// min: 0,
// max: 5
// })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// // postFolder
// // .addInput(Sandbox.postParams.saoParams, 'saoScale', {
// // min: 0,
// // max: 100
// // })
// // .on('change', () => {
// // this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// // this.viewer.requestRender()
// // })
// postFolder
// .addInput(Sandbox.postParams, 'saoScaleOffset', {
// min: -100,
// max: 100
// })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoScale', {
// .addInput(Sandbox.postParams, 'saoNormalsRendering', {
// options: {
// DEFAULT: 0,
// ADVANCED: 1,
// ACCURATE: 2
// }
// })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoKernelRadius', {
// min: 0,
// max: 100
// })
@@ -377,97 +426,65 @@ export default class Sandbox {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
postFolder
.addInput(Sandbox.postParams, 'saoScaleOffset', {
min: -100,
max: 100
})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams, 'saoNormalsRendering', {
options: {
DEFAULT: 0,
ADVANCED: 1,
ACCURATE: 2
}
})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams.saoParams, 'saoKernelRadius', {
min: 0,
max: 100
})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
// // postFolder
// // .addInput(Sandbox.postParams.saoParams, 'saoMinResolution', {
// // min: 0,
// // max: 1
// // })
// // .on('change', () => {
// // this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// // this.viewer.requestRender()
// // })
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoMinResolution', {
// min: 0,
// max: 1
// })
// .addInput(Sandbox.postParams.saoParams, 'saoBlur', {})
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
postFolder
.addInput(Sandbox.postParams.saoParams, 'saoBlur', {})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoBlurRadius', { min: 0, max: 10 })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
postFolder
.addInput(Sandbox.postParams.saoParams, 'saoBlurRadius', { min: 0, max: 10 })
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
// postFolder
// .addInput(Sandbox.postParams, 'minDistance', { min: 0, max: 100, step: 0.000001 })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
postFolder
.addInput(Sandbox.postParams, 'minDistance', { min: 0, max: 100, step: 0.000001 })
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams, 'maxDistance', { min: 0, max: 100, step: 0.000001 })
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams, 'ssaoKernelRadius', { min: 0, max: 100 })
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder.addInput(Sandbox.postParams, 'progressive', {}).on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
postFolder
.addInput(Sandbox.postParams, 'progressiveAO', {
options: {
SAO: 0,
SSAO: 1
}
})
.on('change', () => {
this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
this.viewer.requestRender()
})
// postFolder
// .addInput(Sandbox.postParams, 'maxDistance', { min: 0, max: 100, step: 0.000001 })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams, 'ssaoKernelRadius', { min: 0, max: 100 })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder.addInput(Sandbox.postParams, 'progressive', {}).on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams, 'progressiveAO', {
// options: {
// SAO: 0,
// SSAO: 1
// }
// })
// .on('change', () => {
// this.viewer.getRenderer().pipelineOptions = Sandbox.postParams
// this.viewer.requestRender()
// })
// postFolder
// .addInput(Sandbox.postParams.saoParams, 'saoBlurStdDev', {
+30 -25
View File
@@ -50,7 +50,7 @@ import { DefaultPipelineOptions, Pipeline, PipelineOptions } from './pipeline/Pi
export default class SpeckleRenderer {
private readonly SHOW_HELPERS = false
private _renderer: WebGLRenderer
public scene: Scene
public _scene: Scene
private rootGroup: Group
private batcher: Batcher
private intersections: Intersections
@@ -62,19 +62,12 @@ export default class SpeckleRenderer {
private filterBatchRecording: string[]
private pipeline: Pipeline
private lastAzimuth: number
private lastPolar: number
private lastDistance: number
private lastTarget: Vector3 = new Vector3()
private lasMaxCameraMotion: number
private readonly CAMERA_MOTION_EPSILON: number = 0.0001
public get renderer(): WebGLRenderer {
return this._renderer
}
public set indirectIBL(texture: Texture) {
this.scene.environment = texture
this._scene.environment = texture
}
public set indirectIBLIntensity(value: number) {
@@ -92,11 +85,11 @@ export default class SpeckleRenderer {
/** TEMPORARY for backwards compatibility */
public get allObjects() {
return this.scene.getObjectByName('ContentGroup')
return this._scene.getObjectByName('ContentGroup')
}
public subtree(subtreeId: string) {
return this.scene.getObjectByName(subtreeId)
return this._scene.getObjectByName(subtreeId)
}
public get sceneBox() {
@@ -115,15 +108,23 @@ export default class SpeckleRenderer {
return this.sun
}
public get camera() {
return this.viewer.cameraHandler.activeCam.camera
}
public get scene() {
return this._scene
}
public set pipelineOptions(value: PipelineOptions) {
this.pipeline.pipelineOptions = value
}
public constructor(viewer: Viewer /** TEMPORARY */) {
this.scene = new Scene()
this._scene = new Scene()
this.rootGroup = new Group()
this.rootGroup.name = 'ContentGroup'
this.scene.add(this.rootGroup)
this._scene.add(this.rootGroup)
this.batcher = new Batcher()
this.intersections = new Intersections()
@@ -151,7 +152,7 @@ export default class SpeckleRenderer {
container.appendChild(this._renderer.domElement)
this.pipeline = new Pipeline(this._renderer, this.batcher)
this.pipeline.configure(this.scene, this.viewer.cameraHandler.activeCam.camera)
this.pipeline.configure(this._scene, this.viewer.cameraHandler.activeCam.camera)
this.pipeline.pipelineOptions = DefaultPipelineOptions
this.input = new Input(this._renderer.domElement, InputOptionsDefault)
@@ -163,7 +164,7 @@ export default class SpeckleRenderer {
if (this.SHOW_HELPERS) {
const helpers = new Group()
helpers.name = 'Helpers'
this.scene.add(helpers)
this._scene.add(helpers)
const sceneBoxHelper = new Box3Helper(this.sceneBox, new Color(0x0000ff))
sceneBoxHelper.name = 'SceneBoxHelper'
@@ -287,7 +288,8 @@ export default class SpeckleRenderer {
this.viewer.cameraHandler.activeCam.camera.far = d
this.viewer.cameraHandler.activeCam.camera.updateProjectionMatrix()
this.viewer.cameraHandler.camera.updateProjectionMatrix()
this.pipeline.pipelineOptions = { saoParams: { saoScale: d } }
this.pipeline.update(this)
// const currentAzimuth = this.viewer.cameraHandler.controls.azimuthAngle
// const currentPolar = this.viewer.cameraHandler.controls.polarAngle
@@ -321,8 +323,9 @@ export default class SpeckleRenderer {
}
public render(camera: Camera): boolean {
camera
this.batcher.render(this.renderer)
const needsRender = this.pipeline.render(this.scene, camera)
const needsRender = this.pipeline.render()
return needsRender
// this.renderer.render(this.scene, camera)
}
@@ -431,7 +434,7 @@ export default class SpeckleRenderer {
private addDirectLights() {
this.sun = new DirectionalLight(0xffffff, 5)
this.sun.name = 'sun'
this.scene.add(this.sun)
this._scene.add(this.sun)
this.sun.castShadow = true
@@ -450,7 +453,7 @@ export default class SpeckleRenderer {
this.sun.shadow.radius = 2
this.sunTarget = new Object3D()
this.scene.add(this.sunTarget)
this._scene.add(this.sunTarget)
this.sunTarget.position.copy(this.sceneCenter)
this.sun.target = this.sunTarget
}
@@ -529,12 +532,14 @@ export default class SpeckleRenderer {
public updateHelpers() {
if (this.SHOW_HELPERS) {
;(this.scene.getObjectByName('CamHelper') as CameraHelper).update()
;(this._scene.getObjectByName('CamHelper') as CameraHelper).update()
// Thank you prettier, this looks so much better
;(this.scene.getObjectByName('SceneBoxHelper') as Box3Helper).box.copy(
;(this._scene.getObjectByName('SceneBoxHelper') as Box3Helper).box.copy(
this.sceneBox
)
;(this.scene.getObjectByName('DirLightHelper') as DirectionalLightHelper).update()
;(
this._scene.getObjectByName('DirLightHelper') as DirectionalLightHelper
).update()
}
}
@@ -575,7 +580,7 @@ export default class SpeckleRenderer {
private onObjectClick(e) {
const results: Array<Intersection> = this.intersections.intersect(
this.scene,
this._scene,
this.viewer.cameraHandler.activeCam.camera,
e,
true,
@@ -614,7 +619,7 @@ export default class SpeckleRenderer {
private onObjectDoubleClick(e) {
const results: Array<Intersection> = this.intersections.intersect(
this.scene,
this._scene,
this.viewer.cameraHandler.activeCam.camera,
e,
true,
@@ -899,7 +904,7 @@ export default class SpeckleRenderer {
/** DEBUG */
public onObjectClickDebug(e) {
const results: Array<Intersection> = this.intersections.intersect(
this.scene,
this._scene,
this.viewer.cameraHandler.activeCam.camera,
e,
true,
+3 -1
View File
@@ -135,7 +135,9 @@ export class Viewer extends EventEmitter implements IViewer {
}
public resize() {
this.speckleRenderer.resize(this.container.offsetWidth, this.container.offsetHeight)
const width = this.container.offsetWidth
const height = this.container.offsetHeight
this.speckleRenderer.resize(width, height)
this.needsRender = true
}
@@ -0,0 +1,30 @@
export const speckleCopyOutputFrag = `
uniform float opacity;
uniform sampler2D tDiffuse;
varying vec2 vUv;
const float UnpackDownscale = 255. / 256.;
const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );
const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );
float unpackRGBAToDepth( const in vec4 v ) {
return dot( v, UnpackFactors );
}
vec3 unpackRGBToNormal( const in vec3 rgb ) {
return 2.0 * rgb.xyz - 1.0;
}
void main() {
vec4 inSample = texture2D( tDiffuse, vUv );
vec3 outSample = inSample.rgb;
#if OUTPUT_TYPE == 1
outSample.rgb = vec3(unpackRGBAToDepth(inSample));
#endif
#if OUTPUT_TYPE == 3
outSample.rgb = unpackRGBToNormal(inSample.rgb);
#endif
gl_FragColor.rgb = outSample;
gl_FragColor.a = 1.;
}`
@@ -0,0 +1,6 @@
export const speckleCopyOutputVert = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`
@@ -209,6 +209,21 @@ export const speckleSaoFrag = /* glsl */ `
}
float centerViewZ = getViewZ( centerDepth );
vec3 viewPosition = getViewPosition( vUv, centerDepth, centerViewZ );
#ifdef OUTPUT_RECONSTRUCTED_NORMALS
vec3 normal;
#if IMPROVED_NORMAL_RECONSTRUCTION == 1
normal = viewNormalImproved(vUv, viewPosition);
#elif ACCURATE_NORMAL_RECONSTRUCTION == 1
normal = viewNormalAccurate(vUv, viewPosition, centerDepth);
#else
normal = normalize( cross( dFdx( viewPosition ), dFdy( viewPosition ) ) );
#endif
gl_FragColor.rgb = packNormalToRGB(viewNormalImproved(vUv, viewPosition));
gl_FragColor.a = 1.;
return;
#endif
float ambientOcclusion = getAmbientOcclusion( viewPosition, centerDepth );
gl_FragColor = getDefaultColor( vUv );
gl_FragColor.xyz *= 1. - ambientOcclusion;
@@ -11,8 +11,9 @@ import {
} from 'three'
import { FullScreenQuad, Pass } from 'three/examples/jsm/postprocessing/Pass'
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js'
import { InputColorTextureUniform, SpecklePass } from './SpecklePass'
export class ApplySAOPass extends Pass {
export class ApplySAOPass extends Pass implements SpecklePass {
private fsQuad: FullScreenQuad
public materialCopy: ShaderMaterial
@@ -35,26 +36,34 @@ export class ApplySAOPass extends Pass {
this.materialCopy.blendDstAlpha = ZeroFactor
this.materialCopy.blendEquationAlpha = AddEquation
// this.materialCopy.blending = CustomBlending
// this.materialCopy.blendSrc = OneFactor
// this.materialCopy.blendDst = OneFactor
// this.materialCopy.blendEquation = ReverseSubtractEquation
// this.materialCopy.blendSrcAlpha = OneFactor
// this.materialCopy.blendDstAlpha = OneFactor
// this.materialCopy.blendEquationAlpha = AddEquation
this.materialCopy.needsUpdate = true
this.fsQuad = new FullScreenQuad(this.materialCopy)
}
public setAoTexture(texture: Texture) {
this.materialCopy.uniforms['tDiffuse'].value = texture
public setTexture(uName: InputColorTextureUniform, texture: Texture) {
this.materialCopy.uniforms[uName].value = texture
this.materialCopy.needsUpdate = true
}
get displayName(): string {
return 'APPLYSAO'
}
get outputTexture(): Texture {
return null
}
setParams(params: unknown) {
params
}
render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive*/) {
writeBuffer
readBuffer
renderer.setRenderTarget(null)
const rendereAutoClear = renderer.autoClear
renderer.autoClear = false
this.fsQuad.render(renderer)
renderer.autoClear = rendereAutoClear
}
}
@@ -0,0 +1,56 @@
import { NoBlending, ShaderMaterial, Texture, UniformsUtils } from 'three'
import { FullScreenQuad, Pass } from 'three/examples/jsm/postprocessing/Pass'
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js'
import { speckleCopyOutputFrag } from '../materials/shaders/speckle-copy-output-frag'
import { speckleCopyOutputVert } from '../materials/shaders/speckle-copy-output-vert'
import { PipelineOutputType } from './Pipeline'
import { InputColorTextureUniform, SpecklePass } from './SpecklePass'
export class CopyOutputPass extends Pass implements SpecklePass {
private fsQuad: FullScreenQuad
public materialCopy: ShaderMaterial
constructor() {
super()
this.materialCopy = new ShaderMaterial({
defines: {
INPUT_TYPE: 0
},
uniforms: UniformsUtils.clone(CopyShader.uniforms),
vertexShader: speckleCopyOutputVert,
fragmentShader: speckleCopyOutputFrag,
blending: NoBlending
})
this.materialCopy.needsUpdate = true
this.fsQuad = new FullScreenQuad(this.materialCopy)
}
public setOutputType(type: PipelineOutputType) {
this.materialCopy.defines['OUTPUT_TYPE'] = type
this.materialCopy.needsUpdate = true
}
public setTexture(uName: InputColorTextureUniform, texture: Texture) {
this.materialCopy.uniforms[uName].value = texture
this.materialCopy.needsUpdate = true
}
get displayName(): string {
return 'COPY-OUTPUT'
}
get outputTexture(): Texture {
return null
}
render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive*/) {
writeBuffer
readBuffer
renderer.setRenderTarget(null)
const rendereAutoClear = renderer.autoClear
renderer.autoClear = false
this.fsQuad.render(renderer)
renderer.autoClear = rendereAutoClear
}
}
@@ -3,6 +3,7 @@ import {
Color,
DoubleSide,
NoBlending,
Plane,
RGBADepthPacking,
Scene,
Texture,
@@ -10,7 +11,7 @@ import {
} from 'three'
import { Pass } from 'three/examples/jsm/postprocessing/Pass'
import SpeckleDepthMaterial from '../materials/SpeckleDepthMaterial'
import { SpecklePass } from './Pipeline'
import { SpecklePass } from './SpecklePass'
export class DepthPass extends Pass implements SpecklePass {
private renderTarget: WebGLRenderTarget
@@ -20,6 +21,9 @@ export class DepthPass extends Pass implements SpecklePass {
private colorBuffer: Color = new Color()
public onBeforeRender: () => void = null
public onAfterRender: () => void = null
get displayName(): string {
return 'DEPTH'
}
@@ -49,7 +53,11 @@ export class DepthPass extends Pass implements SpecklePass {
this.depthMaterial.side = DoubleSide
}
public update(camera: Camera, scene: Scene) {
public setClippingPlanes(planes: Plane[]) {
this.depthMaterial.clippingPlanes = planes
}
public update(scene: Scene, camera: Camera) {
this.camera = camera
this.scene = scene
}
@@ -58,6 +66,7 @@ export class DepthPass extends Pass implements SpecklePass {
writeBuffer
readBuffer
this.onBeforeRender()
renderer.getClearColor(this.colorBuffer)
const originalClearAlpha = renderer.getClearAlpha()
const originalAutoClear = renderer.autoClear
@@ -83,6 +92,7 @@ export class DepthPass extends Pass implements SpecklePass {
renderer.autoClear = originalAutoClear
renderer.setClearColor(this.colorBuffer)
renderer.setClearAlpha(originalClearAlpha)
this.onAfterRender()
}
public setSize(width: number, height: number) {
@@ -17,7 +17,7 @@ import { speckleSaoVert } from '../materials/shaders/speckle-sao-vert'
import { SAOShader } from 'three/examples/jsm/shaders/SAOShader.js'
import { DepthLimitedBlurShader } from 'three/examples/jsm/shaders/DepthLimitedBlurShader.js'
import { BlurShaderUtils } from 'three/examples/jsm/shaders/DepthLimitedBlurShader.js'
import { SpecklePass } from './Pipeline'
import { InputDepthTextureUniform, SpecklePass } from './SpecklePass'
export enum NormalsType {
DEFAULT = 0,
@@ -49,12 +49,8 @@ export const DefaultSpeckleDynamicSAOPassParams = {
blurDepthCutoff: 0.0007
}
/**
* SAO implementation inspired from bhouston previous SAO work
*/
export class SpeckleDynamicSAOPass extends Pass implements SpecklePass {
private params: SpeckleDynamicSAOPassParams
export class DynamicSAOPass extends Pass implements SpecklePass {
private params: SpeckleDynamicSAOPassParams = DefaultSpeckleDynamicSAOPassParams
private colorBuffer: Color = new Color()
private saoMaterial: ShaderMaterial = null
private vBlurMaterial: ShaderMaterial = null
@@ -66,32 +62,22 @@ export class SpeckleDynamicSAOPass extends Pass implements SpecklePass {
private prevStdDev: number
private prevNumSamples: number
get displayName(): string {
public get displayName(): string {
return 'SAO'
}
get outputTexture(): Texture {
public get outputTexture(): Texture {
return this.saoRenderTarget.texture
}
public setDepthTexture(texture: Texture) {
this.saoMaterial.uniforms['tDepth'].value = texture
this.vBlurMaterial.uniforms['tDepth'].value = texture
this.hBlurMaterial.uniforms['tDepth'].value = texture
this.saoMaterial.needsUpdate = true
this.vBlurMaterial.needsUpdate = true
this.hBlurMaterial.needsUpdate = true
public set outputReconstructedNormals(value: boolean) {
if (value) this.saoMaterial.defines['OUTPUT_RECONSTRUCTED_NORMALS'] = ''
else delete this.saoMaterial.defines['OUTPUT_RECONSTRUCTED_NORMALS']
}
constructor() {
super()
// this.normalRenderTarget.depthBuffer = true
// this.normalRenderTarget.stencilBuffer = true
// this.normalMaterial = new SpeckleNormalMaterial({}, ['USE_RTE'])
// this.normalMaterial.blending = NoBlending
// this.normalMaterial.side = DoubleSide
this.saoRenderTarget = new WebGLRenderTarget(256, 256)
this.blurIntermediateRenderTarget = new WebGLRenderTarget(256, 256)
this.saoMaterial = new ShaderMaterial({
@@ -145,7 +131,21 @@ export class SpeckleDynamicSAOPass extends Pass implements SpecklePass {
this.fsQuad = new FullScreenQuad(this.saoMaterial)
}
public setParams(params: unknown) {
Object.assign(this.params, params)
}
public setTexture(uName: InputDepthTextureUniform, texture: Texture) {
this.saoMaterial.uniforms['tDepth'].value = texture
this.vBlurMaterial.uniforms['tDepth'].value = texture
this.hBlurMaterial.uniforms['tDepth'].value = texture
this.saoMaterial.needsUpdate = true
this.vBlurMaterial.needsUpdate = true
this.hBlurMaterial.needsUpdate = true
}
public update(scene: Scene, camera: Camera) {
this.params.scale = (camera as PerspectiveCamera | OrthographicCamera).far
/** SAO DEFINES */
this.saoMaterial.defines['PERSPECTIVE_CAMERA'] = (camera as PerspectiveCamera)
.isPerspectiveCamera
@@ -235,15 +235,9 @@ export class SpeckleDynamicSAOPass extends Pass implements SpecklePass {
this.hBlurMaterial.needsUpdate = true
}
public render(renderer, writeBuffer, readBuffer) {
writeBuffer
readBuffer
// const restoreVisibility = this.batcher.saveVisiblity()
// const opaque = this.batcher.getOpaque()
// this.batcher.applyVisibility(opaque)
// this.batcher.applyVisibility(restoreVisibility)
public render(renderer) {
const outputNormals =
this.saoMaterial.defines['OUTPUT_RECONSTRUCTED_NORMALS'] !== undefined
// Rendering SAO texture
renderer.getClearColor(this.colorBuffer)
const originalClearAlpha = renderer.getClearAlpha()
@@ -259,7 +253,7 @@ export class SpeckleDynamicSAOPass extends Pass implements SpecklePass {
this.fsQuad.material = this.saoMaterial
this.fsQuad.render(renderer)
if (this.params.blurEnabled) {
if (this.params.blurEnabled && !outputNormals) {
renderer.setRenderTarget(this.blurIntermediateRenderTarget)
renderer.setClearColor(0xffffff)
renderer.setClearAlpha(1.0)
@@ -0,0 +1,95 @@
import {
Camera,
Color,
DoubleSide,
NoBlending,
Plane,
Scene,
Texture,
WebGLRenderTarget
} from 'three'
import { Pass } from 'three/examples/jsm/postprocessing/Pass'
import SpeckleNormalMaterial from '../materials/SpeckleNormalMaterial'
import { SpecklePass } from './SpecklePass'
export class NormalsPass extends Pass implements SpecklePass {
private renderTarget: WebGLRenderTarget
private normalsMaterial: SpeckleNormalMaterial = null
private scene: Scene
private camera: Camera
private colorBuffer: Color = new Color()
public onBeforeRender: () => void = null
public onAfterRender: () => void = null
get displayName(): string {
return 'GEOMETRY-NORMALS'
}
get outputTexture(): Texture {
return this.renderTarget.texture
}
constructor() {
super()
this.renderTarget = new WebGLRenderTarget(256, 256)
/** On Chromium, on MacOS the 16 bit depth render buffer appears broken.
* We're not really using a stencil buffer at all, we're just forcing
* three.js to use a 24 bit depth render buffer
*/
this.renderTarget.depthBuffer = true
this.renderTarget.stencilBuffer = true
this.normalsMaterial = new SpeckleNormalMaterial({}, ['USE_RTE'])
this.normalsMaterial.blending = NoBlending
this.normalsMaterial.side = DoubleSide
}
public setClippingPlanes(planes: Plane[]) {
this.normalsMaterial.clippingPlanes = planes
}
public update(scene: Scene, camera: Camera) {
this.camera = camera
this.scene = scene
}
public render(renderer, writeBuffer, readBuffer) {
writeBuffer
readBuffer
this.onBeforeRender()
renderer.getClearColor(this.colorBuffer)
const originalClearAlpha = renderer.getClearAlpha()
const originalAutoClear = renderer.autoClear
renderer.setRenderTarget(this.renderTarget)
renderer.autoClear = false
renderer.setClearColor(0x000000)
renderer.setClearAlpha(1.0)
renderer.clear()
const shadowmapEnabled = renderer.shadowMap.enabled
const shadowmapNeedsUpdate = renderer.shadowMap.needsUpdate
this.scene.overrideMaterial = this.normalsMaterial
renderer.shadowMap.enabled = false
renderer.shadowMap.needsUpdate = false
renderer.render(this.scene, this.camera)
renderer.shadowMap.enabled = shadowmapEnabled
renderer.shadowMap.needsUpdate = shadowmapNeedsUpdate
this.scene.overrideMaterial = null
// restore original state
renderer.autoClear = originalAutoClear
renderer.setClearColor(this.colorBuffer)
renderer.setClearAlpha(originalClearAlpha)
this.onAfterRender()
}
public setSize(width: number, height: number) {
this.renderTarget.setSize(width, height)
}
}
+135 -65
View File
@@ -1,31 +1,40 @@
import { Camera, Plane, Scene, Texture, Vector2, WebGLRenderer } from 'three'
import { Camera, Plane, Scene, Vector2, WebGLRenderer } from 'three'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js'
import Batcher from '../batching/Batcher'
import SpeckleRenderer from '../SpeckleRenderer'
import { ApplySAOPass } from './ApplySAOPass'
import { CopyOutputPass } from './CopyOutputPass'
import { DepthPass } from './DepthPass'
import { NormalsPass } from './NormalsPass'
import {
DefaultSpeckleDynamicSAOPassParams,
NormalsType,
SpeckleDynamicSAOPass,
DynamicSAOPass,
SpeckleDynamicSAOPassParams
} from './SpeckleDynamicSAOPass'
import { SpeckleStaticAOGeneratePass } from './SpeckleStaticAOGeneratePass'
} from './DynamicSAOPass'
// import { SpecklePass } from './SpecklePass'
// import { SpeckleStaticAOGeneratePass } from './SpeckleStaticAOGeneratePass'
enum RenderType {
NORMAL,
ACCUMULATION
}
export interface SpecklePass {
get displayName(): string
get outputTexture(): Texture
export enum PipelineOutputType {
DEPTH_RGBA = 0,
DEPTH = 1,
COLOR = 2,
GEOMETRY_NORMALS = 3,
RECONSTRUCTED_NORMALS = 4,
DYNAMIC_AO = 5,
DYNAMIC_AO_BLURED = 6,
PROGRESSIVE_AO = 7,
FINAL = 8
}
export interface PipelineOptions {
pipelineOutput: PipelineOutputType
dynamicAoEnabled: boolean
dynamicAoParams: SpeckleDynamicSAOPassParams
}
export const DefaultPipelineOptions: PipelineOptions = {
pipelineOutput: PipelineOutputType.FINAL,
dynamicAoEnabled: true,
dynamicAoParams: DefaultSpeckleDynamicSAOPassParams
// saoScaleOffset: 0,
@@ -43,23 +52,79 @@ export class Pipeline {
private _pipelineOptions: PipelineOptions = Object.assign({}, DefaultPipelineOptions)
private composer: EffectComposer = null
private depthPass: DepthPass = null
private normalsPass: NormalsPass = null
private renderPass: RenderPass = null
private dynamicAoPass: SpeckleDynamicSAOPass = null
private dynamicAoPass: DynamicSAOPass = null
private applySaoPass: ApplySAOPass = null
private staticAOGenerationPass: SpeckleStaticAOGeneratePass = null
private copyOutputPass: CopyOutputPass = null
private drawingSize: Vector2 = new Vector2()
private _renderType: RenderType = RenderType.NORMAL
private accumulationFrame = 0
private readonly NUM_ACCUMULATION_FRAMES = 16
private enableProgressive = true
public set pipelineOptions(options: Partial<PipelineOptions>) {
Object.assign(this._pipelineOptions, options)
this.pipelineOutput = options.pipelineOutput
this.dynamicAoPass.setParams(options.dynamicAoParams)
}
private set renderType(value: RenderType) {
this._renderType = value
public set pipelineOutput(outputType: PipelineOutputType) {
switch (outputType) {
case PipelineOutputType.DEPTH_RGBA:
this.dynamicAoPass.enabled = false
this.renderPass.enabled = false
this.applySaoPass.enabled = false
this.normalsPass.enabled = false
this.depthPass.enabled = true
this.copyOutputPass.enabled = true
this.copyOutputPass.setTexture('tDiffuse', this.depthPass.outputTexture)
this.copyOutputPass.setOutputType(PipelineOutputType.DEPTH_RGBA)
break
case PipelineOutputType.DEPTH:
this.dynamicAoPass.enabled = false
this.renderPass.enabled = false
this.applySaoPass.enabled = false
this.depthPass.enabled = true
this.normalsPass.enabled = false
this.copyOutputPass.enabled = true
this.copyOutputPass.setTexture('tDiffuse', this.depthPass.outputTexture)
this.copyOutputPass.setOutputType(PipelineOutputType.DEPTH)
break
case PipelineOutputType.COLOR:
this.depthPass.enabled = false
this.dynamicAoPass.enabled = false
this.applySaoPass.enabled = false
this.copyOutputPass.enabled = false
this.normalsPass.enabled = false
this.renderPass.enabled = true
break
case PipelineOutputType.GEOMETRY_NORMALS:
this.depthPass.enabled = false
this.dynamicAoPass.enabled = false
this.applySaoPass.enabled = false
this.renderPass.enabled = false
this.normalsPass.enabled = true
this.copyOutputPass.enabled = true
this.copyOutputPass.setTexture('tDiffuse', this.normalsPass.outputTexture)
this.copyOutputPass.setOutputType(PipelineOutputType.GEOMETRY_NORMALS)
break
case PipelineOutputType.RECONSTRUCTED_NORMALS:
this.depthPass.enabled = true
this.dynamicAoPass.enabled = true
this.applySaoPass.enabled = false
this.renderPass.enabled = false
this.normalsPass.enabled = false
this.copyOutputPass.enabled = true
this.copyOutputPass.setTexture('tDiffuse', this.dynamicAoPass.outputTexture)
this.copyOutputPass.setOutputType(PipelineOutputType.GEOMETRY_NORMALS)
this.dynamicAoPass.outputReconstructedNormals = true
break
default:
break
}
}
public constructor(renderer: WebGLRenderer, batcher: Batcher) {
@@ -71,59 +136,64 @@ export class Pipeline {
}
public configure(scene: Scene, camera: Camera) {
this.dynamicAoPass = new SpeckleDynamicSAOPass(
scene,
camera,
this._batcher,
false,
NormalsType.IMPROVED
)
this.staticAOGenerationPass = new SpeckleStaticAOGeneratePass(this._batcher)
this.staticAOGenerationPass.depthTexture =
this.dynamicAoPass.depthRenderTarget.texture
this.composer.addPass(this.dynamicAoPass)
this.depthPass = new DepthPass()
this.normalsPass = new NormalsPass()
this.normalsPass.enabled = false
this.dynamicAoPass = new DynamicSAOPass()
this.renderPass = new RenderPass(scene, camera)
this.renderPass.renderToScreen = true
// this.renderPass.enabled = false
this.composer.addPass(this.renderPass)
this.composer.addPass(this.staticAOGenerationPass)
this.applySaoPass = new ApplySAOPass()
this.applySaoPass.setAoTexture(this.dynamicAoPass.saoRenderTarget.texture)
this.applySaoPass.renderToScreen = true
this.copyOutputPass = new CopyOutputPass()
this.copyOutputPass.renderToScreen = true
this.copyOutputPass.enabled = false
this.composer.addPass(this.depthPass)
this.composer.addPass(this.normalsPass)
this.composer.addPass(this.dynamicAoPass)
this.composer.addPass(this.renderPass)
this.composer.addPass(this.applySaoPass)
this.composer.addPass(this.copyOutputPass)
this.dynamicAoPass.setTexture('tDepth', this.depthPass.outputTexture)
this.applySaoPass.setTexture('tDiffuse', this.dynamicAoPass.outputTexture)
let restoreVisibility
this.depthPass.onBeforeRender = () => {
restoreVisibility = this._batcher.saveVisiblity()
const opaque = this._batcher.getOpaque()
this._batcher.applyVisibility(opaque)
}
this.depthPass.onAfterRender = () => {
this._batcher.applyVisibility(restoreVisibility)
}
this.normalsPass.onBeforeRender = () => {
restoreVisibility = this._batcher.saveVisiblity()
const opaque = this._batcher.getOpaque()
this._batcher.applyVisibility(opaque)
}
this.normalsPass.onAfterRender = () => {
this._batcher.applyVisibility(restoreVisibility)
}
}
public updateClippingPlanes(planes: Plane[]) {
this.dynamicAoPass.depthMaterial.clippingPlanes = planes
this.dynamicAoPass.normalMaterial.clippingPlanes = planes
this.depthPass.setClippingPlanes(planes)
}
public render(scene: Scene, camera: Camera): boolean {
public update(renderer: SpeckleRenderer) {
this.depthPass.update(renderer.scene, renderer.camera)
this.dynamicAoPass.update(renderer.scene, renderer.camera)
this.normalsPass.update(renderer.scene, renderer.camera)
}
public render(): boolean {
this._renderer.getDrawingBufferSize(this.drawingSize)
if (this.drawingSize.length() === 0) return
if (this._renderType === RenderType.NORMAL) {
this._renderer.clear(true)
this.applySaoPass.setAoTexture(this.dynamicAoPass.saoRenderTarget.texture)
this.renderPass.scene = scene
this.renderPass.camera = camera
this.dynamicAoPass.scene = scene
this.dynamicAoPass.camera = camera
this.composer.render()
return true
} else if (this.enableProgressive) {
this._renderer.clear(true)
this.applySaoPass.setAoTexture(this.staticAOGenerationPass.outputTexture.texture)
this.renderPass.scene = scene
this.renderPass.camera = camera
this.dynamicAoPass.scene = scene
this.dynamicAoPass.camera = camera
this.staticAOGenerationPass.update(camera, this.accumulationFrame)
this.composer.render()
this.accumulationFrame++
console.warn('rendering stationary frame => ', this.accumulationFrame)
return this.accumulationFrame < this.NUM_ACCUMULATION_FRAMES ? true : false
}
this._renderer.clear(true)
this.composer.render()
return true
}
public resize(width: number, height: number) {
@@ -131,15 +201,15 @@ export class Pipeline {
}
public onStationaryBegin() {
this.renderType = RenderType.ACCUMULATION
this.staticAOGenerationPass.enabled = true
this.accumulationFrame = 0
// this.renderType = RenderType.ACCUMULATION
// this.staticAOGenerationPass.enabled = true
// this.accumulationFrame = 0
console.warn('Starting stationary')
}
public onStationaryEnd() {
this.renderType = RenderType.NORMAL
this.staticAOGenerationPass.enabled = false
// this.renderType = RenderType.NORMAL
// this.staticAOGenerationPass.enabled = false
console.warn('Ending stationary')
}
}
@@ -0,0 +1,17 @@
import { Camera, Plane, Scene, Texture } from 'three'
export type InputColorTextureUniform = 'tDiffuse'
export type InputDepthTextureUniform = 'tDepth'
export interface SpecklePass {
onBeforeRender?: () => void
onAferRender?: () => void
get displayName(): string
get outputTexture(): Texture
update?(scene: Scene, camera: Camera)
setTexture?(uName: string, texture: Texture)
setParams?(params: unknown)
setClippingPlanes?(planes: Plane[])
}