diff --git a/packages/viewer-sandbox/src/Sandbox.ts b/packages/viewer-sandbox/src/Sandbox.ts index 9322f4652..b82df51e5 100644 --- a/packages/viewer-sandbox/src/Sandbox.ts +++ b/packages/viewer-sandbox/src/Sandbox.ts @@ -30,6 +30,21 @@ export default class Sandbox { tonemapping: 4 //'ACESFilmicToneMapping' } + public static postParams = { + saoEnabled: true, + saoParams: { + saoBias: 0, + saoIntensity: 1.5, + saoScale: 434, + saoKernelRadius: 6.52, + saoMinResolution: 0, + saoBlur: true, + saoBlurRadius: 2, + saoBlurStdDev: 4, + saoBlurDepthCutoff: 0.00007 + } + } + public static lightParams: SunLightConfiguration = { enabled: true, castShadow: true, @@ -321,6 +336,88 @@ export default class Sandbox { this.viewer.getRenderer().renderer.toneMapping = Sandbox.sceneParams.tonemapping 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: 2000 + }) + .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, 'saoBlur', {}) + .on('change', () => { + this.viewer.getRenderer().pipelineOptions = Sandbox.postParams + this.viewer.requestRender() + }) + + postFolder + .addInput(Sandbox.postParams.saoParams, 'saoBlurRadius', { min: 0, max: 100 }) + .on('change', () => { + this.viewer.getRenderer().pipelineOptions = Sandbox.postParams + this.viewer.requestRender() + }) + + postFolder + .addInput(Sandbox.postParams.saoParams, 'saoBlurStdDev', { + min: 0, + max: 150 + }) + .on('change', () => { + this.viewer.getRenderer().pipelineOptions = Sandbox.postParams + this.viewer.requestRender() + }) + + postFolder + .addInput(Sandbox.postParams.saoParams, 'saoBlurDepthCutoff', { + min: 0, + max: 10 + }) + .on('change', () => { + this.viewer.getRenderer().pipelineOptions = Sandbox.postParams + this.viewer.requestRender() + }) const lightsFolder = this.tabs.pages[1].addFolder({ title: 'Lights', diff --git a/packages/viewer-sandbox/src/main.ts b/packages/viewer-sandbox/src/main.ts index b77b509b9..9a85d9d0f 100644 --- a/packages/viewer-sandbox/src/main.ts +++ b/packages/viewer-sandbox/src/main.ts @@ -82,7 +82,7 @@ sandbox.makeFilteringUI() await sandbox.loadUrl( // 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8?c=%5B-7.66134,10.82932,6.41935,-0.07739,-13.88552,1.8697,0,1%5D' // Revit sample house (good for bim-like stuff with many display meshes) - 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8' + // 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8' // 'Super' heavy revit shit // 'https://speckle.xyz/streams/e6f9156405/commits/0694d53bb5' // Same sample revit house, local to dim's computer @@ -99,4 +99,6 @@ await sandbox.loadUrl( // 'https://latest.speckle.dev/streams/92b620fb17/commits/af6098915b?c=%5B0.02144,-0.0377,0.05554,0.00566,0.00236,0,0,1%5D' // AutoCAD // 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce' + //Blizzard world + 'https://latest.speckle.dev/streams/0c6ad366c4/commits/aa1c393aec' ) diff --git a/packages/viewer/src/modules/Pipeline.ts b/packages/viewer/src/modules/Pipeline.ts new file mode 100644 index 000000000..d30d4016e --- /dev/null +++ b/packages/viewer/src/modules/Pipeline.ts @@ -0,0 +1,44 @@ +import { Camera, Scene, WebGLRenderer } from 'three' +import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js' +import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js' +import { SAOPass, SAOPassParams } from 'three/examples/jsm/postprocessing/SAOPass.js' + +export interface PipelineOptions { + saoEnabled?: boolean + saoParams: Partial +} + +export class Pipeline { + private _renderer: WebGLRenderer = null + private _pipelineOptions: PipelineOptions = null + private composer: EffectComposer = null + private renderPass: RenderPass = null + private saoPass: SAOPass = null + + public set pipelineOptions(options: PipelineOptions) { + this._pipelineOptions = options + if (this.saoPass) { + Object.assign(this.saoPass.params, options.saoParams) + } + } + + public constructor(renderer: WebGLRenderer) { + this._renderer = renderer + this.composer = new EffectComposer(renderer) + } + + public configure(scene: Scene, camera: Camera) { + this.renderPass = new RenderPass(scene, camera) + this.composer.addPass(this.renderPass) + this.saoPass = new SAOPass(scene, camera, false, true) + this.composer.addPass(this.saoPass) + } + + public render(scene: Scene, camera: Camera) { + this.renderPass.scene = scene + this.renderPass.camera = camera + this.saoPass.scene = scene + this.saoPass.camera = camera + this.composer.render() + } +} diff --git a/packages/viewer/src/modules/SpeckleRenderer.ts b/packages/viewer/src/modules/SpeckleRenderer.ts index 9a3bb8295..2a00612bd 100644 --- a/packages/viewer/src/modules/SpeckleRenderer.ts +++ b/packages/viewer/src/modules/SpeckleRenderer.ts @@ -45,6 +45,7 @@ import { SunLightConfiguration, ViewerEvent } from '../IViewer' +import { Pipeline, PipelineOptions } from './Pipeline' export default class SpeckleRenderer { private readonly SHOW_HELPERS = false @@ -59,6 +60,7 @@ export default class SpeckleRenderer { private sunConfiguration: SunLightConfiguration = DefaultLightConfiguration public viewer: Viewer // TEMPORARY private filterBatchRecording: string[] + private pipeline: Pipeline public get renderer(): WebGLRenderer { return this._renderer @@ -106,6 +108,10 @@ export default class SpeckleRenderer { return this.sun } + public set pipelineOptions(value: PipelineOptions) { + this.pipeline.pipelineOptions = value + } + public constructor(viewer: Viewer /** TEMPORARY */) { this.scene = new Scene() this.rootGroup = new Group() @@ -137,6 +143,9 @@ export default class SpeckleRenderer { this._renderer.setSize(container.offsetWidth, container.offsetHeight) container.appendChild(this._renderer.domElement) + this.pipeline = new Pipeline(this._renderer) + this.pipeline.configure(this.scene, this.viewer.cameraHandler.activeCam.camera) + this.input = new Input(this._renderer.domElement, InputOptionsDefault) this.input.on(ViewerEvent.ObjectClicked, this.onObjectClick.bind(this)) this.input.on('object-clicked-debug', this.onObjectClickDebug.bind(this)) @@ -232,11 +241,37 @@ export default class SpeckleRenderer { } } } + + const v = new Vector3() + const box = this.sceneBox + const camPos = new Vector3().copy( + this.viewer.cameraHandler.activeCam.camera.position + ) + let d = 0 + v.set(box.min.x, box.min.y, box.min.z) // 000 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.min.x, box.min.y, box.max.z) // 001 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.min.x, box.max.y, box.min.z) // 010 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.min.x, box.max.y, box.max.z) // 011 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.max.x, box.min.y, box.min.z) // 100 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.max.x, box.min.y, box.max.z) // 101 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.max.x, box.max.y, box.min.z) // 110 + d = Math.max(camPos.distanceTo(v), d) + v.set(box.max.x, box.max.y, box.max.z) // 111 + d = Math.max(camPos.distanceTo(v), d) + this.viewer.cameraHandler.activeCam.camera.far = d + this.viewer.cameraHandler.activeCam.camera.updateProjectionMatrix() + this.pipeline.pipelineOptions = { saoParams: { saoScale: d } } } public render(camera: Camera) { this.batcher.render(this.renderer) - this.renderer.render(this.scene, camera) + this.pipeline.render(this.scene, camera) } public addRenderTree(subtreeId: string) { @@ -490,7 +525,6 @@ export default class SpeckleRenderer { selectionCenter: result.point, // Ideally we'd get the selection center here multiple: multiSelect } as SelectionEvent - this.viewer.emit(ViewerEvent.ObjectClicked, selectionInfo) } diff --git a/packages/viewer/src/modules/Viewer.ts b/packages/viewer/src/modules/Viewer.ts index f8a5f2aec..469ff22f9 100644 --- a/packages/viewer/src/modules/Viewer.ts +++ b/packages/viewer/src/modules/Viewer.ts @@ -82,6 +82,8 @@ export class Viewer extends EventEmitter implements IViewer { this.clock = new THREE.Clock() this.inProgressOperations = 0 + this.cameraHandler = new CameraHandler(this) + this.speckleRenderer = new SpeckleRenderer(this) this.speckleRenderer.create(this.container) window.addEventListener('resize', this.resize.bind(this), false) @@ -92,7 +94,6 @@ export class Viewer extends EventEmitter implements IViewer { // eslint-disable-next-line @typescript-eslint/no-explicit-any ;(window as any)._V = this // For debugging! - this.cameraHandler = new CameraHandler(this) this.sectionBox = new SectionBox(this) this.sectionBox.off() this.sectionBox.controls.addEventListener('change', () => { diff --git a/packages/viewer/src/modules/context/CameraHanlder.js b/packages/viewer/src/modules/context/CameraHanlder.js index 5985a653e..40729c57f 100644 --- a/packages/viewer/src/modules/context/CameraHanlder.js +++ b/packages/viewer/src/modules/context/CameraHanlder.js @@ -30,10 +30,7 @@ export default class CameraHandler { this.orthoCamera.updateProjectionMatrix() CameraControls.install({ THREE }) - this.controls = new CameraControls( - this.camera, - this.viewer.speckleRenderer.renderer.domElement - ) + this.controls = new CameraControls(this.camera, this.viewer.container) this.controls.maxPolarAngle = Math.PI / 2 this.setupWASDControls()