diff --git a/packages/viewer-sandbox/src/Sandbox.ts b/packages/viewer-sandbox/src/Sandbox.ts index f49cd8ea2..4d84de649 100644 --- a/packages/viewer-sandbox/src/Sandbox.ts +++ b/packages/viewer-sandbox/src/Sandbox.ts @@ -44,7 +44,7 @@ export default class Sandbox { saoBlurDepthCutoff: 0.0007 }, saoScaleOffset: 0, - saoNormalsRendering: 1 + saoNormalsRendering: 2 } public static lightParams: SunLightConfiguration = { @@ -386,7 +386,8 @@ export default class Sandbox { .addInput(Sandbox.postParams, 'saoNormalsRendering', { options: { DEFAULT: 0, - ADVANCED: 1 + ADVANCED: 1, + ACCURATE: 2 } }) .on('change', () => { diff --git a/packages/viewer-sandbox/src/main.ts b/packages/viewer-sandbox/src/main.ts index 067770572..2384b49f2 100644 --- a/packages/viewer-sandbox/src/main.ts +++ b/packages/viewer-sandbox/src/main.ts @@ -82,14 +82,14 @@ 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 // 'http://localhost:3000/streams/6960695d7b/commits/da0a2343fa' // 'http://100.66.180.109:3000/streams/6960695d7b/commits/417526751d' // IFC building (good for a tree based structure) - // 'https://latest.speckle.dev/streams/92b620fb17/commits/2ebd336223' + 'https://latest.speckle.dev/streams/92b620fb17/commits/2ebd336223' // IFC story, a subtree of the above // 'https://latest.speckle.dev/streams/92b620fb17/objects/8247bbc53865b0e0cb5ee4e252e66216' // Small scale lines diff --git a/packages/viewer/src/modules/SpeckleRenderer.ts b/packages/viewer/src/modules/SpeckleRenderer.ts index c22812ed0..fda25f9b0 100644 --- a/packages/viewer/src/modules/SpeckleRenderer.ts +++ b/packages/viewer/src/modules/SpeckleRenderer.ts @@ -265,8 +265,10 @@ export default class SpeckleRenderer { 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.camera.far = d this.viewer.cameraHandler.activeCam.camera.far = d this.viewer.cameraHandler.activeCam.camera.updateProjectionMatrix() + this.viewer.cameraHandler.camera.updateProjectionMatrix() this.pipeline.pipelineOptions = { saoParams: { saoScale: d } } // console.log(d) } @@ -674,9 +676,9 @@ export default class SpeckleRenderer { this.viewer.cameraHandler.controls.minDistance = distance / 100 this.viewer.cameraHandler.controls.maxDistance = distance * 100 - this.viewer.cameraHandler.camera.near = distance / 100 - this.viewer.cameraHandler.camera.far = distance * 100 - this.viewer.cameraHandler.camera.updateProjectionMatrix() + // this.viewer.cameraHandler.camera.near = distance / 100 + // this.viewer.cameraHandler.camera.far = distance * 100 + // this.viewer.cameraHandler.camera.updateProjectionMatrix() if (this.viewer.cameraHandler.activeCam.name === 'ortho') { this.viewer.cameraHandler.orthoCamera.far = distance * 100 diff --git a/packages/viewer/src/modules/materials/shaders/speckle-sao-frag.ts b/packages/viewer/src/modules/materials/shaders/speckle-sao-frag.ts index cdb16d1b3..b7c283856 100644 --- a/packages/viewer/src/modules/materials/shaders/speckle-sao-frag.ts +++ b/packages/viewer/src/modules/materials/shaders/speckle-sao-frag.ts @@ -50,7 +50,7 @@ export const speckleSaoFrag = /* glsl */ ` } //https://wickedengine.net/2019/09/22/improved-normal-reconstruction-from-depth/ - vec3 depth_cross(in vec2 uv, in vec3 origin) + vec3 viewNormalImproved(in vec2 uv, in vec3 origin) { highp vec2 dd = abs(vec2(1./size.x, 1./size.y)); highp vec2 ddx = vec2(dd.x, 0.); @@ -74,44 +74,91 @@ export const speckleSaoFrag = /* glsl */ ` sampleViewZ = getViewZ( sampleDepth ); highp vec3 right = getViewPosition( uv + ddx, sampleDepth, sampleViewZ ); - highp float dx0 = abs(right.z - center.z); - highp float dx1 = abs(left.z - center.z); - highp float dy0 = abs(bottom.z - center.z); - highp float dy1 = abs(top.z - center.z); - - int best_Z_horizontal = dx0 < dx1 ? 1 : 2; - int best_Z_vertical = dy0 < dy1 ? 3 : 4; + // get the difference between the current and each offset position + vec3 l = center - left; + vec3 r = right - center; + vec3 d = center - top; + vec3 u = bottom - center; - vec3 P1, P2; - if (best_Z_horizontal == 1 && best_Z_vertical == 4) - { - P1 = right; - P2 = top; - } - else if (best_Z_horizontal == 1 && best_Z_vertical == 3) - { - P1 = bottom; - P2 = right; - } - else if (best_Z_horizontal == 2 && best_Z_vertical == 4) - { - P1 = top; - P2 = left; - } - else if (best_Z_horizontal == 2 && best_Z_vertical == 3) - { - P1 = left; - P2 = bottom; - } + // pick horizontal and vertical diff with the smallest z difference + vec3 hDeriv = abs(l.z) < abs(r.z) ? l : r; + vec3 vDeriv = abs(d.z) < abs(u.z) ? d : u; - return normalize(cross(P2 - center, P1 - center)); + // get view space normal from the cross product of the two smallest offsets + vec3 viewNormal = normalize(cross(hDeriv, vDeriv)); + + return viewNormal; } - vec3 getViewNormal( const in vec3 viewPosition, const in vec2 screenPosition ) { + vec3 viewNormalAccurate(in vec2 uv, in vec3 origin, in float centerDepth) { + highp vec2 dd = abs(vec2(1./size.x, 1./size.y)); + highp vec2 ddx = vec2(dd.x, 0.); + highp vec2 ddy = vec2(0., dd.y); + + float sampleDepth = getDepth( uv - ddy ); + float sampleViewZ = getViewZ( sampleDepth ); + highp vec3 top = getViewPosition( uv - ddy, sampleDepth, sampleViewZ ); + + sampleDepth = getDepth( uv + ddy ); + sampleViewZ = getViewZ( sampleDepth ); + highp vec3 bottom = getViewPosition( uv + ddy, sampleDepth, sampleViewZ ); + + highp vec3 center = origin; + + sampleDepth = getDepth( uv - ddx ); + sampleViewZ = getViewZ( sampleDepth ); + highp vec3 left = getViewPosition( uv - ddx, sampleDepth, sampleViewZ ); + + sampleDepth = getDepth( uv + ddx ); + sampleViewZ = getViewZ( sampleDepth ); + highp vec3 right = getViewPosition( uv + ddx, sampleDepth, sampleViewZ ); + + // get the difference between the current and each offset position + vec3 l = center - left; + vec3 r = right - center; + vec3 d = center - top; + vec3 u = bottom - center; + + // get depth values at 1 & 2 pixels offsets from current along the horizontal axis + vec4 H = vec4( + getDepth(uv - ddx), + getDepth(uv + ddx), + getDepth(uv - 2. * ddx), + getDepth(uv + 2. * ddx) + ); + + // get depth values at 1 & 2 pixels offsets from current along the vertical axis + vec4 V = vec4( + getDepth(uv - ddy), + getDepth(uv + ddy), + getDepth(uv - 2. * ddy), + getDepth(uv + 2. * ddy) + ); + + // current pixel's depth difference from slope of offset depth samples + // differs from original article because we're using non-linear depth values + // see article's comments + vec2 he = abs((2. * H.xy - H.zw) - centerDepth); + vec2 ve = abs((2. * V.xy - V.zw) - centerDepth); + + // pick horizontal and vertical diff with the smallest depth difference from slopes + vec3 hDeriv = he.x < he.y ? l : r; + vec3 vDeriv = ve.x < ve.y ? d : u; + + // get view space normal from the cross product of the best derivatives + vec3 viewNormal = normalize(cross(hDeriv, vDeriv)); + + return viewNormal; + + } + + vec3 getViewNormal( const in vec3 viewPosition, const in vec2 screenPosition, in float centerDepth ) { #if NORMAL_TEXTURE == 1 return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz ); #elif IMPROVED_NORMAL_RECONSTRUCTION == 1 - return depth_cross(screenPosition, viewPosition); + return viewNormalImproved(screenPosition, viewPosition); + #elif ACCURATE_NORMAL_RECONSTRUCTION == 1 + return viewNormalAccurate(screenPosition, viewPosition, centerDepth); #else return normalize( cross( dFdx( viewPosition ), dFdy( viewPosition ) ) ); #endif @@ -128,11 +175,11 @@ export const speckleSaoFrag = /* glsl */ ` // moving costly divides into consts const float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES ); const float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES ); - float getAmbientOcclusion( const in vec3 centerViewPosition ) { + float getAmbientOcclusion( const in vec3 centerViewPosition, in float centerDepth ) { // precompute some variables require in getOcclusion. scaleDividedByCameraFar = scale / cameraFar; minResolutionMultipliedByCameraFar = minResolution * cameraFar; - vec3 centerViewNormal = getViewNormal( centerViewPosition, vUv ); + vec3 centerViewNormal = getViewNormal( centerViewPosition, vUv, centerDepth ); // jsfiddle that shows sample pattern: https://jsfiddle.net/a16ff1p7/ float angle = rand( vUv + randomSeed ) * PI2; vec2 radius = vec2( kernelRadius * INV_NUM_SAMPLES ) / size; @@ -162,7 +209,7 @@ export const speckleSaoFrag = /* glsl */ ` } float centerViewZ = getViewZ( centerDepth ); vec3 viewPosition = getViewPosition( vUv, centerDepth, centerViewZ ); - float ambientOcclusion = getAmbientOcclusion( viewPosition ); + float ambientOcclusion = getAmbientOcclusion( viewPosition, centerDepth ); gl_FragColor = getDefaultColor( vUv ); gl_FragColor.xyz *= 1.0 - ambientOcclusion; // gl_FragColor.xyz = depth_cross(vUv, viewPosition) * 0.5 + 0.5; diff --git a/packages/viewer/src/modules/pipeline/Pipeline.ts b/packages/viewer/src/modules/pipeline/Pipeline.ts index 1c6bcdfbc..e6991a1b4 100644 --- a/packages/viewer/src/modules/pipeline/Pipeline.ts +++ b/packages/viewer/src/modules/pipeline/Pipeline.ts @@ -27,7 +27,7 @@ export const DefaultPipelineOptions: PipelineOptions = { saoBlurDepthCutoff: 0.0007 }, saoScaleOffset: 0, - saoNormalsRendering: NormalsType.IMPROVED + saoNormalsRendering: NormalsType.ACCURATE } export class Pipeline { diff --git a/packages/viewer/src/modules/pipeline/SpeckleSAOPass.ts b/packages/viewer/src/modules/pipeline/SpeckleSAOPass.ts index d543bbdcb..4158efec9 100644 --- a/packages/viewer/src/modules/pipeline/SpeckleSAOPass.ts +++ b/packages/viewer/src/modules/pipeline/SpeckleSAOPass.ts @@ -22,7 +22,8 @@ import SpeckleNormalMaterial from '../materials/SpeckleNormalMaterial' export enum NormalsType { DEFAULT = 0, - IMPROVED = 1 + IMPROVED = 1, + ACCURATE = 2 } /** @@ -42,6 +43,8 @@ export class SpeckleSAOPass extends SAOPass { this.normalsType === NormalsType.DEFAULT ? 1 : 0 this.saoMaterial.defines['IMPROVED_NORMAL_RECONSTRUCTION'] = this.normalsType === NormalsType.IMPROVED ? 1 : 0 + this.saoMaterial.defines['ACCURATE_NORMAL_RECONSTRUCTION'] = + this.normalsType === NormalsType.ACCURATE ? 1 : 0 this.saoMaterial.needsUpdate = true }