From 65679de91b1c08dab2f3519d05e44af32855f57d Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 10 Aug 2020 15:15:32 +0800 Subject: [PATCH 001/103] SSRPass init --- examples/jsm/postprocessing/SSRPass.js | 61 +++++++++++ examples/jsm/shaders/SSRShader.js | 58 +++++++++++ examples/webgl_postprocessing_ssr.html | 135 +++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 examples/jsm/postprocessing/SSRPass.js create mode 100644 examples/jsm/shaders/SSRShader.js create mode 100644 examples/webgl_postprocessing_ssr.html diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js new file mode 100644 index 00000000000000..96514a9ce28ee0 --- /dev/null +++ b/examples/jsm/postprocessing/SSRPass.js @@ -0,0 +1,61 @@ +import { + ShaderMaterial, + UniformsUtils +} from "../../../build/three.module.js"; +import { Pass } from "../postprocessing/Pass.js"; +import { SSRShader } from "../shaders/SSRShader.js"; + +var SSRPass = function(center, angle, scale) { + + Pass.call(this); + + if (SSRShader === undefined) + console.error("SSRPass relies on SSRShader"); + + var shader = SSRShader; + + this.uniforms = UniformsUtils.clone(shader.uniforms); + + if (center !== undefined) this.uniforms["center"].value.copy(center); + if (angle !== undefined) this.uniforms["angle"].value = angle; + if (scale !== undefined) this.uniforms["scale"].value = scale; + + this.material = new ShaderMaterial({ + + uniforms: this.uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + + }); + + this.fsQuad = new Pass.FullScreenQuad(this.material); + +}; + +SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { + + constructor: SSRPass, + + render: function(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) { + + this.uniforms["tDiffuse"].value = readBuffer.texture; + this.uniforms["tSize"].value.set(readBuffer.width, readBuffer.height); + + if (this.renderToScreen) { + + renderer.setRenderTarget(null); + this.fsQuad.render(renderer); + + } else { + + renderer.setRenderTarget(writeBuffer); + if (this.clear) renderer.clear(); + this.fsQuad.render(renderer); + + } + + } + +}); + +export { SSRPass }; diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js new file mode 100644 index 00000000000000..506d6fa0a6df4c --- /dev/null +++ b/examples/jsm/shaders/SSRShader.js @@ -0,0 +1,58 @@ +import { + Vector2 +} from "../../../build/three.module.js"; +/** + * Dot screen shader + * based on glfx.js sepia shader + * https://github.com/evanw/glfx.js + */ + +var SSRShader = { + + uniforms: { + + "tDiffuse": { value: null }, + "tSize": { value: new Vector2(256, 256) }, + "center": { value: new Vector2(0.5, 0.5) }, + "angle": { value: 1.57 }, + "scale": { value: 1.0 } + + }, + + vertexShader: [ + + "varying vec2 vUv;", + + "void main() {", + + " vUv = uv;", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join("\n"), + + fragmentShader: ` + uniform vec2 center; + uniform float angle; + uniform float scale; + uniform vec2 tSize; + uniform sampler2D tDiffuse; + varying vec2 vUv; + float pattern() { + float s = sin( angle ), c = cos( angle ); + vec2 tex = vUv * tSize - center; + vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale; + return ( sin( point.x ) * sin( point.y ) ) * 4.0; + } + void main() { + vec4 color = texture2D( tDiffuse, vUv ); + float average = ( color.r + color.g + color.b ) / 3.0; + gl_FragColor = texture2D(tDiffuse,vUv); + // gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a ); + } + ` + +}; + +export { SSRShader }; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html new file mode 100644 index 00000000000000..c3699b467b27b3 --- /dev/null +++ b/examples/webgl_postprocessing_ssr.html @@ -0,0 +1,135 @@ + + + + three.js webgl - postprocessing - afterimage + + + + + + + + + From 4b41a967654e2f2c90640d8c8ebe88eaa164dcb6 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 10 Aug 2020 19:10:09 +0800 Subject: [PATCH 002/103] a --- examples/jsm/postprocessing/SSRPass.js | 438 +++++++++++++++++++++++-- examples/jsm/shaders/SSRShader.js | 321 +++++++++++++++--- examples/webgl_postprocessing_ssr.html | 108 +++--- 3 files changed, 746 insertions(+), 121 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 96514a9ce28ee0..9aef5e519fa7e9 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -1,61 +1,431 @@ import { - ShaderMaterial, - UniformsUtils + AddEquation, + Color, + CustomBlending, + DataTexture, + DepthTexture, + DstAlphaFactor, + DstColorFactor, + FloatType, + LinearFilter, + MathUtils, + MeshNormalMaterial, + NearestFilter, + NoBlending, + RGBAFormat, + RepeatWrapping, + ShaderMaterial, + UniformsUtils, + UnsignedShortType, + Vector3, + WebGLRenderTarget, + ZeroFactor } from "../../../build/three.module.js"; import { Pass } from "../postprocessing/Pass.js"; -import { SSRShader } from "../shaders/SSRShader.js"; +import { SimplexNoise } from "../math/SimplexNoise.js"; +import { SSAOShader } from "../shaders/SSAOShader.js"; +import { SSAOBlurShader } from "../shaders/SSAOShader.js"; +import { SSAODepthShader } from "../shaders/SSAOShader.js"; +import { CopyShader } from "../shaders/CopyShader.js"; -var SSRPass = function(center, angle, scale) { +var SSAOPass = function ( scene, camera, width, height ) { - Pass.call(this); + Pass.call( this ); - if (SSRShader === undefined) - console.error("SSRPass relies on SSRShader"); + this.width = ( width !== undefined ) ? width : 512; + this.height = ( height !== undefined ) ? height : 512; - var shader = SSRShader; + this.clear = true; - this.uniforms = UniformsUtils.clone(shader.uniforms); + this.camera = camera; + this.scene = scene; - if (center !== undefined) this.uniforms["center"].value.copy(center); - if (angle !== undefined) this.uniforms["angle"].value = angle; - if (scale !== undefined) this.uniforms["scale"].value = scale; + this.kernelRadius = 8; + this.kernelSize = 32; + this.kernel = []; + this.noiseTexture = null; + this.output = 0; - this.material = new ShaderMaterial({ + this.minDistance = 0.005; + this.maxDistance = 0.1; - uniforms: this.uniforms, - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader + // - }); + this.generateSampleKernel(); + this.generateRandomKernelRotations(); - this.fsQuad = new Pass.FullScreenQuad(this.material); + // beauty render target with depth buffer + + var depthTexture = new DepthTexture(); + depthTexture.type = UnsignedShortType; + depthTexture.minFilter = NearestFilter; + depthTexture.maxFilter = NearestFilter; + + this.beautyRenderTarget = new WebGLRenderTarget( this.width, this.height, { + minFilter: LinearFilter, + magFilter: LinearFilter, + format: RGBAFormat, + depthTexture: depthTexture, + depthBuffer: true + } ); + + // normal render target + + this.normalRenderTarget = new WebGLRenderTarget( this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + format: RGBAFormat + } ); + + // ssao render target + + this.ssaoRenderTarget = new WebGLRenderTarget( this.width, this.height, { + minFilter: LinearFilter, + magFilter: LinearFilter, + format: RGBAFormat + } ); + + this.blurRenderTarget = this.ssaoRenderTarget.clone(); + + // ssao material + + if ( SSAOShader === undefined ) { + + console.error( 'THREE.SSAOPass: The pass relies on SSAOShader.' ); + + } + + this.ssaoMaterial = new ShaderMaterial( { + defines: Object.assign( {}, SSAOShader.defines ), + uniforms: UniformsUtils.clone( SSAOShader.uniforms ), + vertexShader: SSAOShader.vertexShader, + fragmentShader: SSAOShader.fragmentShader, + blending: NoBlending + } ); + + this.ssaoMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; + this.ssaoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture; + this.ssaoMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture; + this.ssaoMaterial.uniforms[ 'tNoise' ].value = this.noiseTexture; + this.ssaoMaterial.uniforms[ 'kernel' ].value = this.kernel; + this.ssaoMaterial.uniforms[ 'cameraNear' ].value = this.camera.near; + this.ssaoMaterial.uniforms[ 'cameraFar' ].value = this.camera.far; + this.ssaoMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height ); + this.ssaoMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix ); + this.ssaoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.getInverse( this.camera.projectionMatrix ); + + // normal material + + this.normalMaterial = new MeshNormalMaterial(); + this.normalMaterial.blending = NoBlending; + + // blur material + + this.blurMaterial = new ShaderMaterial( { + defines: Object.assign( {}, SSAOBlurShader.defines ), + uniforms: UniformsUtils.clone( SSAOBlurShader.uniforms ), + vertexShader: SSAOBlurShader.vertexShader, + fragmentShader: SSAOBlurShader.fragmentShader + } ); + this.blurMaterial.uniforms[ 'tDiffuse' ].value = this.ssaoRenderTarget.texture; + this.blurMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height ); + + // material for rendering the depth + + this.depthRenderMaterial = new ShaderMaterial( { + defines: Object.assign( {}, SSAODepthShader.defines ), + uniforms: UniformsUtils.clone( SSAODepthShader.uniforms ), + vertexShader: SSAODepthShader.vertexShader, + fragmentShader: SSAODepthShader.fragmentShader, + blending: NoBlending + } ); + this.depthRenderMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture; + this.depthRenderMaterial.uniforms[ 'cameraNear' ].value = this.camera.near; + this.depthRenderMaterial.uniforms[ 'cameraFar' ].value = this.camera.far; + + // material for rendering the content of a render target + + this.copyMaterial = new ShaderMaterial( { + uniforms: UniformsUtils.clone( CopyShader.uniforms ), + vertexShader: CopyShader.vertexShader, + fragmentShader: CopyShader.fragmentShader, + transparent: true, + depthTest: false, + depthWrite: false, + blendSrc: DstColorFactor, + blendDst: ZeroFactor, + blendEquation: AddEquation, + blendSrcAlpha: DstAlphaFactor, + blendDstAlpha: ZeroFactor, + blendEquationAlpha: AddEquation + } ); + + this.fsQuad = new Pass.FullScreenQuad( null ); + + this.originalClearColor = new Color(); }; -SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { +SSAOPass.prototype = Object.assign( Object.create( Pass.prototype ), { + + constructor: SSAOPass, + + dispose: function () { + + // dispose render targets + + this.beautyRenderTarget.dispose(); + this.normalRenderTarget.dispose(); + this.ssaoRenderTarget.dispose(); + this.blurRenderTarget.dispose(); + + // dispose materials + + this.normalMaterial.dispose(); + this.blurMaterial.dispose(); + this.copyMaterial.dispose(); + this.depthRenderMaterial.dispose(); + + // dipsose full screen quad + + this.fsQuad.dispose(); + + }, + + render: function ( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) { + + // render beauty and depth + + renderer.setRenderTarget( this.beautyRenderTarget ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + + // render normals + + this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 ); + + // render SSAO + + this.ssaoMaterial.uniforms[ 'kernelRadius' ].value = this.kernelRadius; + this.ssaoMaterial.uniforms[ 'minDistance' ].value = this.minDistance; + this.ssaoMaterial.uniforms[ 'maxDistance' ].value = this.maxDistance; + this.renderPass( renderer, this.ssaoMaterial, this.ssaoRenderTarget ); + + // render blur + + this.renderPass( renderer, this.blurMaterial, this.blurRenderTarget ); + + // output result to screen + + switch ( this.output ) { + + case SSAOPass.OUTPUT.SSAO: + + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssaoRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + + break; + + case SSAOPass.OUTPUT.Blur: + + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + + break; + + case SSAOPass.OUTPUT.Beauty: + + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + + break; + + case SSAOPass.OUTPUT.Depth: + + this.renderPass( renderer, this.depthRenderMaterial, this.renderToScreen ? null : writeBuffer ); - constructor: SSRPass, + break; - render: function(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) { + case SSAOPass.OUTPUT.Normal: - this.uniforms["tDiffuse"].value = readBuffer.texture; - this.uniforms["tSize"].value.set(readBuffer.width, readBuffer.height); + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); - if (this.renderToScreen) { + break; - renderer.setRenderTarget(null); - this.fsQuad.render(renderer); + case SSAOPass.OUTPUT.Default: - } else { + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); - renderer.setRenderTarget(writeBuffer); - if (this.clear) renderer.clear(); - this.fsQuad.render(renderer); + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture; + this.copyMaterial.blending = CustomBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); - } + break; - } + default: + console.warn( 'THREE.SSAOPass: Unknown output type.' ); -}); + } + + }, + + renderPass: function ( renderer, passMaterial, renderTarget, clearColor, clearAlpha ) { + + // save original state + this.originalClearColor.copy( renderer.getClearColor() ); + var originalClearAlpha = renderer.getClearAlpha(); + var originalAutoClear = renderer.autoClear; + + renderer.setRenderTarget( renderTarget ); + + // setup pass state + renderer.autoClear = false; + if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) { + + renderer.setClearColor( clearColor ); + renderer.setClearAlpha( clearAlpha || 0.0 ); + renderer.clear(); + + } + + this.fsQuad.material = passMaterial; + this.fsQuad.render( renderer ); + + // restore original state + renderer.autoClear = originalAutoClear; + renderer.setClearColor( this.originalClearColor ); + renderer.setClearAlpha( originalClearAlpha ); + + }, + + renderOverride: function ( renderer, overrideMaterial, renderTarget, clearColor, clearAlpha ) { + + this.originalClearColor.copy( renderer.getClearColor() ); + var originalClearAlpha = renderer.getClearAlpha(); + var originalAutoClear = renderer.autoClear; + + renderer.setRenderTarget( renderTarget ); + renderer.autoClear = false; + + clearColor = overrideMaterial.clearColor || clearColor; + clearAlpha = overrideMaterial.clearAlpha || clearAlpha; + + if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) { + + renderer.setClearColor( clearColor ); + renderer.setClearAlpha( clearAlpha || 0.0 ); + renderer.clear(); + + } + + this.scene.overrideMaterial = overrideMaterial; + renderer.render( this.scene, this.camera ); + this.scene.overrideMaterial = null; + + // restore original state + + renderer.autoClear = originalAutoClear; + renderer.setClearColor( this.originalClearColor ); + renderer.setClearAlpha( originalClearAlpha ); + + }, + + setSize: function ( width, height ) { + + this.width = width; + this.height = height; + + this.beautyRenderTarget.setSize( width, height ); + this.ssaoRenderTarget.setSize( width, height ); + this.normalRenderTarget.setSize( width, height ); + this.blurRenderTarget.setSize( width, height ); + + this.ssaoMaterial.uniforms[ 'resolution' ].value.set( width, height ); + this.ssaoMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix ); + this.ssaoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.getInverse( this.camera.projectionMatrix ); + + this.blurMaterial.uniforms[ 'resolution' ].value.set( width, height ); + + }, + + generateSampleKernel: function () { + + var kernelSize = this.kernelSize; + var kernel = this.kernel; + + for ( var i = 0; i < kernelSize; i ++ ) { + + var sample = new Vector3(); + sample.x = ( Math.random() * 2 ) - 1; + sample.y = ( Math.random() * 2 ) - 1; + sample.z = Math.random(); + + sample.normalize(); + + var scale = i / kernelSize; + scale = MathUtils.lerp( 0.1, 1, scale * scale ); + sample.multiplyScalar( scale ); + + kernel.push( sample ); + + } + + }, + + generateRandomKernelRotations: function () { + + var width = 4, height = 4; + + if ( SimplexNoise === undefined ) { + + console.error( 'THREE.SSAOPass: The pass relies on SimplexNoise.' ); + + } + + var simplex = new SimplexNoise(); + + var size = width * height; + var data = new Float32Array( size * 4 ); + + for ( var i = 0; i < size; i ++ ) { + + var stride = i * 4; + + var x = ( Math.random() * 2 ) - 1; + var y = ( Math.random() * 2 ) - 1; + var z = 0; + + var noise = simplex.noise3d( x, y, z ); + + data[ stride ] = noise; + data[ stride + 1 ] = noise; + data[ stride + 2 ] = noise; + data[ stride + 3 ] = 1; + + } + + this.noiseTexture = new DataTexture( data, width, height, RGBAFormat, FloatType ); + this.noiseTexture.wrapS = RepeatWrapping; + this.noiseTexture.wrapT = RepeatWrapping; + + } + +} ); + +SSAOPass.OUTPUT = { + 'Default': 0, + 'SSAO': 1, + 'Blur': 2, + 'Beauty': 3, + 'Depth': 4, + 'Normal': 5 +}; -export { SSRPass }; +export { SSAOPass }; diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 506d6fa0a6df4c..87631b25d3a1f0 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -1,58 +1,299 @@ import { - Vector2 + Matrix4, + Vector2 } from "../../../build/three.module.js"; /** - * Dot screen shader - * based on glfx.js sepia shader - * https://github.com/evanw/glfx.js + * References: + * http://john-chapman-graphics.blogspot.com/2013/01/ssao-tutorial.html + * https://learnopengl.com/Advanced-Lighting/SSAO + * https://github.com/McNopper/OpenGL/blob/master/Example28/shader/ssao.frag.glsl */ -var SSRShader = { +var SSAOShader = { - uniforms: { + defines: { + "PERSPECTIVE_CAMERA": 1, + "KERNEL_SIZE": 32 + }, - "tDiffuse": { value: null }, - "tSize": { value: new Vector2(256, 256) }, - "center": { value: new Vector2(0.5, 0.5) }, - "angle": { value: 1.57 }, - "scale": { value: 1.0 } + uniforms: { - }, + "tDiffuse": { value: null }, + "tNormal": { value: null }, + "tDepth": { value: null }, + "tNoise": { value: null }, + "kernel": { value: null }, + "cameraNear": { value: null }, + "cameraFar": { value: null }, + "resolution": { value: new Vector2() }, + "cameraProjectionMatrix": { value: new Matrix4() }, + "cameraInverseProjectionMatrix": { value: new Matrix4() }, + "kernelRadius": { value: 8 }, + "minDistance": { value: 0.005 }, + "maxDistance": { value: 0.05 }, - vertexShader: [ + }, - "varying vec2 vUv;", + vertexShader: [ - "void main() {", + "varying vec2 vUv;", - " vUv = uv;", - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + "void main() {", - "}" + " vUv = uv;", - ].join("\n"), + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - fragmentShader: ` - uniform vec2 center; - uniform float angle; - uniform float scale; - uniform vec2 tSize; - uniform sampler2D tDiffuse; - varying vec2 vUv; - float pattern() { - float s = sin( angle ), c = cos( angle ); - vec2 tex = vUv * tSize - center; - vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale; - return ( sin( point.x ) * sin( point.y ) ) * 4.0; - } - void main() { - vec4 color = texture2D( tDiffuse, vUv ); - float average = ( color.r + color.g + color.b ) / 3.0; - gl_FragColor = texture2D(tDiffuse,vUv); - // gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a ); - } - ` + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform sampler2D tDiffuse;", + "uniform sampler2D tNormal;", + "uniform sampler2D tDepth;", + "uniform sampler2D tNoise;", + + "uniform vec3 kernel[ KERNEL_SIZE ];", + + "uniform vec2 resolution;", + + "uniform float cameraNear;", + "uniform float cameraFar;", + "uniform mat4 cameraProjectionMatrix;", + "uniform mat4 cameraInverseProjectionMatrix;", + + "uniform float kernelRadius;", + "uniform float minDistance;", // avoid artifacts caused by neighbour fragments with minimal depth difference + "uniform float maxDistance;", // avoid the influence of fragments which are too far away + + "varying vec2 vUv;", + + "#include ", + + "float getDepth( const in vec2 screenPosition ) {", + + " return texture2D( tDepth, screenPosition ).x;", + + "}", + + "float getLinearDepth( const in vec2 screenPosition ) {", + + " #if PERSPECTIVE_CAMERA == 1", + + " float fragCoordZ = texture2D( tDepth, screenPosition ).x;", + " float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );", + " return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );", + + " #else", + + " return texture2D( depthSampler, coord ).x;", + + " #endif", + + "}", + + "float getViewZ( const in float depth ) {", + + " #if PERSPECTIVE_CAMERA == 1", + + " return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );", + + " #else", + + " return orthographicDepthToViewZ( depth, cameraNear, cameraFar );", + + " #endif", + + "}", + + "vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) {", + + " float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3];", + + " vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 );", + + " clipPosition *= clipW; // unprojection.", + + " return ( cameraInverseProjectionMatrix * clipPosition ).xyz;", + + "}", + + "vec3 getViewNormal( const in vec2 screenPosition ) {", + + " return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );", + + "}", + + "void main() {", + + " float depth = getDepth( vUv );", + " float viewZ = getViewZ( depth );", + + " vec3 viewPosition = getViewPosition( vUv, depth, viewZ );", + " vec3 viewNormal = getViewNormal( vUv );", + + " vec2 noiseScale = vec2( resolution.x / 4.0, resolution.y / 4.0 );", + " vec3 random = texture2D( tNoise, vUv * noiseScale ).xyz;", + + // compute matrix used to reorient a kernel vector + + " vec3 tangent = normalize( random - viewNormal * dot( random, viewNormal ) );", + " vec3 bitangent = cross( viewNormal, tangent );", + " mat3 kernelMatrix = mat3( tangent, bitangent, viewNormal );", + + " float occlusion = 0.0;", + + " for ( int i = 0; i < KERNEL_SIZE; i ++ ) {", + + " vec3 sampleVector = kernelMatrix * kernel[ i ];", // reorient sample vector in view space + " vec3 samplePoint = viewPosition + ( sampleVector * kernelRadius );", // calculate sample point + + " vec4 samplePointNDC = cameraProjectionMatrix * vec4( samplePoint, 1.0 );", // project point and calculate NDC + " samplePointNDC /= samplePointNDC.w;", + + " vec2 samplePointUv = samplePointNDC.xy * 0.5 + 0.5;", // compute uv coordinates + + " float realDepth = getLinearDepth( samplePointUv );", // get linear depth from depth texture + " float sampleDepth = viewZToOrthographicDepth( samplePoint.z, cameraNear, cameraFar );", // compute linear depth of the sample view Z value + " float delta = sampleDepth - realDepth;", + + " if ( delta > minDistance && delta < maxDistance ) {", // if fragment is before sample point, increase occlusion + + " occlusion += 1.0;", + + " }", + + " }", + + " occlusion = clamp( occlusion / float( KERNEL_SIZE ), 0.0, 1.0 );", + + " gl_FragColor = vec4( vec3( 1.0 - occlusion ), 1.0 );", + + "}" + + ].join( "\n" ) + +}; + +var SSAODepthShader = { + + defines: { + "PERSPECTIVE_CAMERA": 1 + }, + + uniforms: { + + "tDepth": { value: null }, + "cameraNear": { value: null }, + "cameraFar": { value: null }, + + }, + + vertexShader: [ + + "varying vec2 vUv;", + + "void main() {", + + " vUv = uv;", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform sampler2D tDepth;", + + "uniform float cameraNear;", + "uniform float cameraFar;", + + "varying vec2 vUv;", + + "#include ", + + "float getLinearDepth( const in vec2 screenPosition ) {", + + " #if PERSPECTIVE_CAMERA == 1", + + " float fragCoordZ = texture2D( tDepth, screenPosition ).x;", + " float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );", + " return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );", + + " #else", + + " return texture2D( depthSampler, coord ).x;", + + " #endif", + + "}", + + "void main() {", + + " float depth = getLinearDepth( vUv );", + " gl_FragColor = vec4( vec3( 1.0 - depth ), 1.0 );", + + "}" + + ].join( "\n" ) + +}; + +var SSAOBlurShader = { + + uniforms: { + + "tDiffuse": { value: null }, + "resolution": { value: new Vector2() } + + }, + + vertexShader: [ + + "varying vec2 vUv;", + + "void main() {", + + " vUv = uv;", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform sampler2D tDiffuse;", + + "uniform vec2 resolution;", + + "varying vec2 vUv;", + + "void main() {", + + " vec2 texelSize = ( 1.0 / resolution );", + " float result = 0.0;", + + " for ( int i = - 2; i <= 2; i ++ ) {", + + " for ( int j = - 2; j <= 2; j ++ ) {", + + " vec2 offset = ( vec2( float( i ), float( j ) ) ) * texelSize;", + " result += texture2D( tDiffuse, vUv + offset ).r;", + + " }", + + " }", + + " gl_FragColor = vec4( vec3( result / ( 5.0 * 5.0 ) ), 1.0 );", + + "}" + + ].join( "\n" ) }; -export { SSRShader }; +export { SSAOShader, SSAODepthShader, SSAOBlurShader }; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index c3699b467b27b3..08af3149fe2be3 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -1,51 +1,53 @@ - three.js webgl - postprocessing - afterimage + three.js webgl - postprocessing - Screen Space Ambient Occlusion + +
+ three.js - screen space ambient occlusion
+
+ - - diff --git a/examples/webgl_postprocessing_ssr_bak_1.html b/examples/webgl_postprocessing_ssr_bak_1.html new file mode 100644 index 00000000000000..371d4d21e62e0e --- /dev/null +++ b/examples/webgl_postprocessing_ssr_bak_1.html @@ -0,0 +1,149 @@ + + + + three.js webgl - postprocessing - Screen Space Ambient Occlusion + + + + + + +
+ three.js - screen space ambient occlusion
+
+ + + + diff --git a/examples/webgl_postprocessing_ssr_bak_2.html b/examples/webgl_postprocessing_ssr_bak_2.html new file mode 100644 index 00000000000000..1fb9770e86bd25 --- /dev/null +++ b/examples/webgl_postprocessing_ssr_bak_2.html @@ -0,0 +1,157 @@ + + + + + three.js webgl - postprocessing - Screen Space Ambient Occlusion + + + + + + + +
+ three.js - screen space ambient occlusion
+
+ + + + + From 1bcff91a4a13412c2ff5f324223367f9feb1d43c Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 13:06:51 +0800 Subject: [PATCH 005/103] a --- examples/jsm/postprocessing/SSRPass.js | 621 +++++++++++++------------ examples/jsm/shaders/SSRShader.js | 10 +- examples/webgl_postprocessing_ssr.html | 4 +- 3 files changed, 332 insertions(+), 303 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 631f47bfd328aa..5ea4259f394e86 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -1,25 +1,27 @@ import { - AddEquation, - Color, - CustomBlending, - DataTexture, - DepthTexture, - DstAlphaFactor, - DstColorFactor, - FloatType, - LinearFilter, - MathUtils, - MeshNormalMaterial, - NearestFilter, - NoBlending, - RGBAFormat, - RepeatWrapping, - ShaderMaterial, - UniformsUtils, - UnsignedShortType, - Vector3, - WebGLRenderTarget, - ZeroFactor + AddEquation, + Color, + CustomBlending, + DataTexture, + DepthTexture, + DstAlphaFactor, + DstColorFactor, + FloatType, + LinearFilter, + MathUtils, + MeshNormalMaterial, + NearestFilter, + NoBlending, + RGBAFormat, + RepeatWrapping, + ShaderMaterial, + UniformsUtils, + UnsignedShortType, + Vector3, + WebGLRenderTarget, + ZeroFactor, + MeshDepthMaterial, + DoubleSide } from "../../../build/three.module.js"; import { Pass } from "../postprocessing/Pass.js"; import { SimplexNoise } from "../math/SimplexNoise.js"; @@ -28,404 +30,431 @@ import { SSRBlurShader } from "../shaders/SSRShader.js"; import { SSRDepthShader } from "../shaders/SSRShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; -var SSRPass = function ( scene, camera, width, height ) { +var SSRPass = function(scene, camera, width, height) { - Pass.call( this ); + Pass.call(this); - this.width = ( width !== undefined ) ? width : 512; - this.height = ( height !== undefined ) ? height : 512; + this.width = (width !== undefined) ? width : 512; + this.height = (height !== undefined) ? height : 512; - this.clear = true; + this.clear = true; - this.camera = camera; - this.scene = scene; + this.camera = camera; + this.scene = scene; - this.kernelRadius = 8; - this.kernelSize = 32; - this.kernel = []; - this.noiseTexture = null; - this.output = 0; + this.kernelRadius = 8; + this.kernelSize = 32; + this.kernel = []; + this.noiseTexture = null; + this.output = 0; - this.minDistance = 0.005; - this.maxDistance = 0.1; + this.minDistance = 0.005; + this.maxDistance = 0.1; - // + // - this.generateSampleKernel(); - this.generateRandomKernelRotations(); + this.generateSampleKernel(); + this.generateRandomKernelRotations(); - // beauty render target with depth buffer - - var depthTexture = new DepthTexture(); - depthTexture.type = UnsignedShortType; - depthTexture.minFilter = NearestFilter; - depthTexture.maxFilter = NearestFilter; - - this.beautyRenderTarget = new WebGLRenderTarget( this.width, this.height, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat, - depthTexture: depthTexture, - depthBuffer: true - } ); + // beauty render target with depth buffer - // normal render target + var depthTexture = new DepthTexture(); + depthTexture.type = UnsignedShortType; + depthTexture.minFilter = NearestFilter; + depthTexture.maxFilter = NearestFilter; - this.normalRenderTarget = new WebGLRenderTarget( this.width, this.height, { - minFilter: NearestFilter, - magFilter: NearestFilter, - format: RGBAFormat - } ); + this.beautyRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: LinearFilter, + magFilter: LinearFilter, + format: RGBAFormat, + depthTexture: depthTexture, + depthBuffer: true + }); - // ssr render target + // normal render target + + this.normalRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + format: RGBAFormat + }); - this.ssrRenderTarget = new WebGLRenderTarget( this.width, this.height, { - minFilter: LinearFilter, - magFilter: LinearFilter, - format: RGBAFormat - } ); + // depth render target - this.blurRenderTarget = this.ssrRenderTarget.clone(); + this.depthRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + format: RGBAFormat + }); - // ssr material + // ssr render target - if ( SSRShader === undefined ) { + this.ssrRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: LinearFilter, + magFilter: LinearFilter, + format: RGBAFormat + }); - console.error( 'THREE.SSRPass: The pass relies on SSRShader.' ); + this.blurRenderTarget = this.ssrRenderTarget.clone(); - } + // ssr material - this.ssrMaterial = new ShaderMaterial( { - defines: Object.assign( {}, SSRShader.defines ), - uniforms: UniformsUtils.clone( SSRShader.uniforms ), - vertexShader: SSRShader.vertexShader, - fragmentShader: SSRShader.fragmentShader, - blending: NoBlending - } ); + if (SSRShader === undefined) { - this.ssrMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; - this.ssrMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture; - this.ssrMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture; - this.ssrMaterial.uniforms[ 'tNoise' ].value = this.noiseTexture; - this.ssrMaterial.uniforms[ 'kernel' ].value = this.kernel; - this.ssrMaterial.uniforms[ 'cameraNear' ].value = this.camera.near; - this.ssrMaterial.uniforms[ 'cameraFar' ].value = this.camera.far; - this.ssrMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height ); - this.ssrMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix ); - this.ssrMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.getInverse( this.camera.projectionMatrix ); + console.error('THREE.SSRPass: The pass relies on SSRShader.'); - // normal material + } - this.normalMaterial = new MeshNormalMaterial(); - this.normalMaterial.blending = NoBlending; + this.ssrMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRShader.defines), + uniforms: UniformsUtils.clone(SSRShader.uniforms), + vertexShader: SSRShader.vertexShader, + fragmentShader: SSRShader.fragmentShader, + blending: NoBlending + }); - // blur material + this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; + this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; + this.ssrMaterial.uniforms['tDepth'].value = this.depthRenderTarget.texture; + this.ssrMaterial.uniforms['tNoise'].value = this.noiseTexture; + this.ssrMaterial.uniforms['kernel'].value = this.kernel; + this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; + this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far; + this.ssrMaterial.uniforms['resolution'].value.set(this.width, this.height); + this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix); + this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.getInverse(this.camera.projectionMatrix); - this.blurMaterial = new ShaderMaterial( { - defines: Object.assign( {}, SSRBlurShader.defines ), - uniforms: UniformsUtils.clone( SSRBlurShader.uniforms ), - vertexShader: SSRBlurShader.vertexShader, - fragmentShader: SSRBlurShader.fragmentShader - } ); - this.blurMaterial.uniforms[ 'tDiffuse' ].value = this.ssrRenderTarget.texture; - this.blurMaterial.uniforms[ 'resolution' ].value.set( this.width, this.height ); + // normal material - // material for rendering the depth - - this.depthRenderMaterial = new ShaderMaterial( { - defines: Object.assign( {}, SSRDepthShader.defines ), - uniforms: UniformsUtils.clone( SSRDepthShader.uniforms ), - vertexShader: SSRDepthShader.vertexShader, - fragmentShader: SSRDepthShader.fragmentShader, - blending: NoBlending - } ); - this.depthRenderMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture; - this.depthRenderMaterial.uniforms[ 'cameraNear' ].value = this.camera.near; - this.depthRenderMaterial.uniforms[ 'cameraFar' ].value = this.camera.far; - - // material for rendering the content of a render target - - this.copyMaterial = new ShaderMaterial( { - uniforms: UniformsUtils.clone( CopyShader.uniforms ), - vertexShader: CopyShader.vertexShader, - fragmentShader: CopyShader.fragmentShader, - transparent: true, - depthTest: false, - depthWrite: false, - blendSrc: DstColorFactor, - blendDst: ZeroFactor, - blendEquation: AddEquation, - blendSrcAlpha: DstAlphaFactor, - blendDstAlpha: ZeroFactor, - blendEquationAlpha: AddEquation - } ); - - this.fsQuad = new Pass.FullScreenQuad( null ); - - this.originalClearColor = new Color(); + this.normalMaterial = new MeshNormalMaterial(); + this.normalMaterial.blending = NoBlending; + + // depth material + + this.depthMaterial = new MeshDepthMaterial(); + this.depthMaterial.blending = NoBlending; + + // blur material + + this.blurMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRBlurShader.defines), + uniforms: UniformsUtils.clone(SSRBlurShader.uniforms), + vertexShader: SSRBlurShader.vertexShader, + fragmentShader: SSRBlurShader.fragmentShader + }); + this.blurMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; + this.blurMaterial.uniforms['resolution'].value.set(this.width, this.height); + + // material for rendering the depth + + this.depthRenderMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRDepthShader.defines), + uniforms: UniformsUtils.clone(SSRDepthShader.uniforms), + vertexShader: SSRDepthShader.vertexShader, + fragmentShader: SSRDepthShader.fragmentShader, + blending: NoBlending + }); + this.depthRenderMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; + this.depthRenderMaterial.uniforms['cameraNear'].value = this.camera.near; + this.depthRenderMaterial.uniforms['cameraFar'].value = this.camera.far; + + // material for rendering the content of a render target + + this.copyMaterial = new ShaderMaterial({ + uniforms: UniformsUtils.clone(CopyShader.uniforms), + vertexShader: CopyShader.vertexShader, + fragmentShader: CopyShader.fragmentShader, + transparent: true, + depthTest: false, + depthWrite: false, + blendSrc: DstColorFactor, + blendDst: ZeroFactor, + blendEquation: AddEquation, + blendSrcAlpha: DstAlphaFactor, + blendDstAlpha: ZeroFactor, + blendEquationAlpha: AddEquation + }); + + this.fsQuad = new Pass.FullScreenQuad(null); + + this.originalClearColor = new Color(); }; -SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), { +SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { + + constructor: SSRPass, + + dispose: function() { - constructor: SSRPass, + // dispose render targets - dispose: function () { + this.beautyRenderTarget.dispose(); + this.normalRenderTarget.dispose(); + this.depthRenderTarget.dispose(); + this.ssrRenderTarget.dispose(); + this.blurRenderTarget.dispose(); - // dispose render targets + // dispose materials - this.beautyRenderTarget.dispose(); - this.normalRenderTarget.dispose(); - this.ssrRenderTarget.dispose(); - this.blurRenderTarget.dispose(); + this.normalMaterial.dispose(); + this.depthMaterial.dispose(); + this.blurMaterial.dispose(); + this.copyMaterial.dispose(); + this.depthRenderMaterial.dispose(); - // dispose materials + // dipsose full screen quad - this.normalMaterial.dispose(); - this.blurMaterial.dispose(); - this.copyMaterial.dispose(); - this.depthRenderMaterial.dispose(); + this.fsQuad.dispose(); - // dipsose full screen quad + }, - this.fsQuad.dispose(); + render: function(renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) { - }, + // render beauty and depth - render: function ( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) { + renderer.setRenderTarget(this.beautyRenderTarget); + renderer.clear(); + renderer.render(this.scene, this.camera); - // render beauty and depth + // render normals - renderer.setRenderTarget( this.beautyRenderTarget ); - renderer.clear(); - renderer.render( this.scene, this.camera ); + this.renderOverride(renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0); - // render normals + // render depths - this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 ); + this.renderOverride(renderer, this.depthMaterial, this.depthRenderTarget, 0, 0); - // render SSR + // render SSR - this.ssrMaterial.uniforms[ 'kernelRadius' ].value = this.kernelRadius; - this.ssrMaterial.uniforms[ 'minDistance' ].value = this.minDistance; - this.ssrMaterial.uniforms[ 'maxDistance' ].value = this.maxDistance; - this.renderPass( renderer, this.ssrMaterial, this.ssrRenderTarget ); + this.ssrMaterial.uniforms['kernelRadius'].value = this.kernelRadius; + this.ssrMaterial.uniforms['minDistance'].value = this.minDistance; + this.ssrMaterial.uniforms['maxDistance'].value = this.maxDistance; + this.renderPass(renderer, this.ssrMaterial, this.ssrRenderTarget); - // render blur + // render blur - this.renderPass( renderer, this.blurMaterial, this.blurRenderTarget ); + this.renderPass(renderer, this.blurMaterial, this.blurRenderTarget); - // output result to screen + // output result to screen - switch ( this.output ) { + switch (this.output) { - case SSRPass.OUTPUT.SSR: + case SSRPass.OUTPUT.SSR: - this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssrRenderTarget.texture; - this.copyMaterial.blending = NoBlending; - this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - break; + break; - case SSRPass.OUTPUT.Blur: + case SSRPass.OUTPUT.Blur: - this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture; - this.copyMaterial.blending = NoBlending; - this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - break; + break; - case SSRPass.OUTPUT.Beauty: + case SSRPass.OUTPUT.Beauty: - this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; - this.copyMaterial.blending = NoBlending; - this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + this.copyMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - break; + break; - case SSRPass.OUTPUT.Depth: + case SSRPass.OUTPUT.Depth: - this.renderPass( renderer, this.depthRenderMaterial, this.renderToScreen ? null : writeBuffer ); + this.copyMaterial.uniforms['tDiffuse'].value = this.depthRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - break; + break; - case SSRPass.OUTPUT.Normal: + case SSRPass.OUTPUT.Normal: - this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture; - this.copyMaterial.blending = NoBlending; - this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + this.copyMaterial.uniforms['tDiffuse'].value = this.normalRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - break; + break; - case SSRPass.OUTPUT.Default: + case SSRPass.OUTPUT.Default: - this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; - this.copyMaterial.blending = NoBlending; - this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + this.copyMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget.texture; - this.copyMaterial.blending = CustomBlending; - this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + // this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget.texture; + this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; + // this.copyMaterial.blending = CustomBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - break; + break; - default: - console.warn( 'THREE.SSRPass: Unknown output type.' ); + default: + console.warn('THREE.SSRPass: Unknown output type.'); - } + } - }, + }, - renderPass: function ( renderer, passMaterial, renderTarget, clearColor, clearAlpha ) { + renderPass: function(renderer, passMaterial, renderTarget, clearColor, clearAlpha) { + clearColor = 'black' + clearAlpha = 1 - // save original state - this.originalClearColor.copy( renderer.getClearColor() ); - var originalClearAlpha = renderer.getClearAlpha(); - var originalAutoClear = renderer.autoClear; + // save original state + this.originalClearColor.copy(renderer.getClearColor()); + var originalClearAlpha = renderer.getClearAlpha(); + var originalAutoClear = renderer.autoClear; - renderer.setRenderTarget( renderTarget ); + renderer.setRenderTarget(renderTarget); - // setup pass state - renderer.autoClear = false; - if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) { + // setup pass state + renderer.autoClear = false; + if ((clearColor !== undefined) && (clearColor !== null)) { - renderer.setClearColor( clearColor ); - renderer.setClearAlpha( clearAlpha || 0.0 ); - renderer.clear(); + renderer.setClearColor(clearColor); + renderer.setClearAlpha(clearAlpha || 0.0); + renderer.clear(); - } + } - this.fsQuad.material = passMaterial; - this.fsQuad.render( renderer ); + this.fsQuad.material = passMaterial; + this.fsQuad.render(renderer); - // restore original state - renderer.autoClear = originalAutoClear; - renderer.setClearColor( this.originalClearColor ); - renderer.setClearAlpha( originalClearAlpha ); + // restore original state + renderer.autoClear = originalAutoClear; + renderer.setClearColor(this.originalClearColor); + renderer.setClearAlpha(originalClearAlpha); - }, + }, - renderOverride: function ( renderer, overrideMaterial, renderTarget, clearColor, clearAlpha ) { + renderOverride: function(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { + clearColor = 'black' + clearAlpha = 1 - this.originalClearColor.copy( renderer.getClearColor() ); - var originalClearAlpha = renderer.getClearAlpha(); - var originalAutoClear = renderer.autoClear; + this.originalClearColor.copy(renderer.getClearColor()); + var originalClearAlpha = renderer.getClearAlpha(); + var originalAutoClear = renderer.autoClear; - renderer.setRenderTarget( renderTarget ); - renderer.autoClear = false; + renderer.setRenderTarget(renderTarget); + renderer.autoClear = false; - clearColor = overrideMaterial.clearColor || clearColor; - clearAlpha = overrideMaterial.clearAlpha || clearAlpha; + clearColor = overrideMaterial.clearColor || clearColor; + clearAlpha = overrideMaterial.clearAlpha || clearAlpha; - if ( ( clearColor !== undefined ) && ( clearColor !== null ) ) { + if ((clearColor !== undefined) && (clearColor !== null)) { - renderer.setClearColor( clearColor ); - renderer.setClearAlpha( clearAlpha || 0.0 ); - renderer.clear(); + renderer.setClearColor(clearColor); + renderer.setClearAlpha(clearAlpha || 0.0); + renderer.clear(); - } + } - this.scene.overrideMaterial = overrideMaterial; - renderer.render( this.scene, this.camera ); - this.scene.overrideMaterial = null; + this.scene.overrideMaterial = overrideMaterial; + renderer.render(this.scene, this.camera); + this.scene.overrideMaterial = null; - // restore original state + // restore original state - renderer.autoClear = originalAutoClear; - renderer.setClearColor( this.originalClearColor ); - renderer.setClearAlpha( originalClearAlpha ); + renderer.autoClear = originalAutoClear; + renderer.setClearColor(this.originalClearColor); + renderer.setClearAlpha(originalClearAlpha); - }, + }, - setSize: function ( width, height ) { + setSize: function(width, height) { - this.width = width; - this.height = height; + this.width = width; + this.height = height; - this.beautyRenderTarget.setSize( width, height ); - this.ssrRenderTarget.setSize( width, height ); - this.normalRenderTarget.setSize( width, height ); - this.blurRenderTarget.setSize( width, height ); + this.beautyRenderTarget.setSize(width, height); + this.ssrRenderTarget.setSize(width, height); + this.normalRenderTarget.setSize(width, height); + this.blurRenderTarget.setSize(width, height); - this.ssrMaterial.uniforms[ 'resolution' ].value.set( width, height ); - this.ssrMaterial.uniforms[ 'cameraProjectionMatrix' ].value.copy( this.camera.projectionMatrix ); - this.ssrMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.getInverse( this.camera.projectionMatrix ); + this.ssrMaterial.uniforms['resolution'].value.set(width, height); + this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix); + this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.getInverse(this.camera.projectionMatrix); - this.blurMaterial.uniforms[ 'resolution' ].value.set( width, height ); + this.blurMaterial.uniforms['resolution'].value.set(width, height); - }, + }, - generateSampleKernel: function () { + generateSampleKernel: function() { - var kernelSize = this.kernelSize; - var kernel = this.kernel; + var kernelSize = this.kernelSize; + var kernel = this.kernel; - for ( var i = 0; i < kernelSize; i ++ ) { + for (var i = 0; i < kernelSize; i++) { - var sample = new Vector3(); - sample.x = ( Math.random() * 2 ) - 1; - sample.y = ( Math.random() * 2 ) - 1; - sample.z = Math.random(); + var sample = new Vector3(); + sample.x = (Math.random() * 2) - 1; + sample.y = (Math.random() * 2) - 1; + sample.z = Math.random(); - sample.normalize(); + sample.normalize(); - var scale = i / kernelSize; - scale = MathUtils.lerp( 0.1, 1, scale * scale ); - sample.multiplyScalar( scale ); + var scale = i / kernelSize; + scale = MathUtils.lerp(0.1, 1, scale * scale); + sample.multiplyScalar(scale); - kernel.push( sample ); + kernel.push(sample); - } + } - }, + }, - generateRandomKernelRotations: function () { + generateRandomKernelRotations: function() { - var width = 4, height = 4; + var width = 4, + height = 4; - if ( SimplexNoise === undefined ) { + if (SimplexNoise === undefined) { - console.error( 'THREE.SSRPass: The pass relies on SimplexNoise.' ); + console.error('THREE.SSRPass: The pass relies on SimplexNoise.'); - } + } - var simplex = new SimplexNoise(); + var simplex = new SimplexNoise(); - var size = width * height; - var data = new Float32Array( size * 4 ); + var size = width * height; + var data = new Float32Array(size * 4); - for ( var i = 0; i < size; i ++ ) { + for (var i = 0; i < size; i++) { - var stride = i * 4; + var stride = i * 4; - var x = ( Math.random() * 2 ) - 1; - var y = ( Math.random() * 2 ) - 1; - var z = 0; + var x = (Math.random() * 2) - 1; + var y = (Math.random() * 2) - 1; + var z = 0; - var noise = simplex.noise3d( x, y, z ); + var noise = simplex.noise3d(x, y, z); - data[ stride ] = noise; - data[ stride + 1 ] = noise; - data[ stride + 2 ] = noise; - data[ stride + 3 ] = 1; + data[stride] = noise; + data[stride + 1] = noise; + data[stride + 2] = noise; + data[stride + 3] = 1; - } + } - this.noiseTexture = new DataTexture( data, width, height, RGBAFormat, FloatType ); - this.noiseTexture.wrapS = RepeatWrapping; - this.noiseTexture.wrapT = RepeatWrapping; + this.noiseTexture = new DataTexture(data, width, height, RGBAFormat, FloatType); + this.noiseTexture.wrapS = RepeatWrapping; + this.noiseTexture.wrapT = RepeatWrapping; - } + } -} ); +}); SSRPass.OUTPUT = { - 'Default': 0, - 'SSR': 1, - 'Blur': 2, - 'Beauty': 3, - 'Depth': 4, - 'Normal': 5 + 'Default': 0, + 'SSR': 1, + 'Blur': 2, + 'Beauty': 3, + 'Depth': 4, + 'Normal': 5 }; export { SSRPass }; diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index de358d01a14e59..712f7875012e8e 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -85,9 +85,9 @@ var SSRShader = { // gl_FragColor.a=1.; // return; - vec4 color=texture2D(tDiffuse,uv); - vec4 reflectDiffuse; - gl_FragColor=color; + // vec4 color=texture2D(tDiffuse,uv); + // vec4 reflectDiffuse; + // gl_FragColor=color; float depth=texture2D(tDepth,uv).r; if(depth<=0.) return; @@ -122,8 +122,8 @@ var SSRShader = { if(length(rayPos-p) @@ -64,7 +64,7 @@ scene = new THREE.Scene(); s.scene = scene - scene.background = new THREE.Color(0xaaaaaa); + // scene.background = new THREE.Color(0xaaaaaa); scene.add(new THREE.DirectionalLight()); scene.add(new THREE.HemisphereLight()); From 4078f7aaa1d7aa8740f08f469c7e1b15e1b9370a Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 13:10:34 +0800 Subject: [PATCH 006/103] a --- examples/jsm/postprocessing/SSRPass.js | 13 +++++++------ examples/webgl_postprocessing_ssr.html | 6 ++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 5ea4259f394e86..9ff657f5e85d6f 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -1,7 +1,8 @@ import { AddEquation, Color, - CustomBlending, + CustomBlending, + AdditiveBlending, DataTexture, DepthTexture, DstAlphaFactor, @@ -288,7 +289,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget.texture; this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; - // this.copyMaterial.blending = CustomBlending; + this.copyMaterial.blending = AdditiveBlending; this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); break; @@ -301,8 +302,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, renderPass: function(renderer, passMaterial, renderTarget, clearColor, clearAlpha) { - clearColor = 'black' - clearAlpha = 1 + // clearColor = 'black' + // clearAlpha = 1 // save original state this.originalClearColor.copy(renderer.getClearColor()); @@ -332,8 +333,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, renderOverride: function(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { - clearColor = 'black' - clearAlpha = 1 + // clearColor = 'black' + // clearAlpha = 1 this.originalClearColor.copy(renderer.getClearColor()); var originalClearAlpha = renderer.getClearAlpha(); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index c2cb82940ba609..194bf52ad832df 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -74,7 +74,8 @@ let geo = new THREE.BoxBufferGeometry(1, 1, 1) // let geo = new THREE.IcosahedronBufferGeometry(.5, 3) let mtl = new THREE.MeshBasicMaterial({ - color: 'red' + color: 'red', + side: THREE.DoubleSide, }) let mesh = new THREE.Mesh(geo, mtl) s.mesh = mesh @@ -95,7 +96,8 @@ {//ground let geo = new THREE.PlaneBufferGeometry(4, 4) let mtl = new THREE.MeshBasicMaterial({ - color: 'blue' + color: 'blue', + side: THREE.DoubleSide, }) let mesh = new THREE.Mesh(geo, mtl) s.ground = mesh From 78fa2728dcc4f60797a877f87f4537a260a8f773 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 13:17:57 +0800 Subject: [PATCH 007/103] a --- examples/webgl_postprocessing_ssr_bak_3.html | 172 ++++++++++++++++++ examples/webgl_postprocessing_ssr_ok.html | 182 +++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 examples/webgl_postprocessing_ssr_bak_3.html create mode 100644 examples/webgl_postprocessing_ssr_ok.html diff --git a/examples/webgl_postprocessing_ssr_bak_3.html b/examples/webgl_postprocessing_ssr_bak_3.html new file mode 100644 index 00000000000000..8012ef4b87b8ed --- /dev/null +++ b/examples/webgl_postprocessing_ssr_bak_3.html @@ -0,0 +1,172 @@ + + + + + three.js webgl - postprocessing - Screen Space Ambient Occlusion + + + + + + + +
+ three.js - screen space ambient occlusion
+
+ + + + + diff --git a/examples/webgl_postprocessing_ssr_ok.html b/examples/webgl_postprocessing_ssr_ok.html new file mode 100644 index 00000000000000..194bf52ad832df --- /dev/null +++ b/examples/webgl_postprocessing_ssr_ok.html @@ -0,0 +1,182 @@ + + + + + three.js webgl - postprocessing - Screen Space Ambient Occlusion + + + + + + + +
+ three.js - screen space ambient occlusion
+
+ + + + + From 9703d2c896a7ae94583af75f385cd2cbafdb5c0b Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 14:24:57 +0800 Subject: [PATCH 008/103] a --- examples/jsm/postprocessing/SSRPass.js | 10 +++++++--- examples/jsm/shaders/SSRShader.js | 13 +++++++++---- examples/webgl_postprocessing_ssr.html | 6 +++--- examples/webgl_postprocessing_ssr_ok.html | 6 +++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 9ff657f5e85d6f..86eee939868a56 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -1,8 +1,8 @@ import { AddEquation, Color, - CustomBlending, - AdditiveBlending, + CustomBlending, + AdditiveBlending, DataTexture, DepthTexture, DstAlphaFactor, @@ -31,7 +31,8 @@ import { SSRBlurShader } from "../shaders/SSRShader.js"; import { SSRDepthShader } from "../shaders/SSRShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; -var SSRPass = function(scene, camera, width, height) { +var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, cameraFar) { + // console.log(cameraRadius, cameraNear, cameraFar) Pass.call(this); @@ -124,6 +125,9 @@ var SSRPass = function(scene, camera, width, height) { this.ssrMaterial.uniforms['resolution'].value.set(this.width, this.height); this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix); this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.getInverse(this.camera.projectionMatrix); + this.ssrMaterial.uniforms['cameraNear2'].value = cameraNear + this.ssrMaterial.uniforms['cameraRange'].value = cameraFar - cameraNear + this.ssrMaterial.uniforms['UVWR'].value = cameraRadius * 2 // normal material diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 712f7875012e8e..b4e4e63ad4a8fd 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -30,7 +30,10 @@ var SSRShader = { "cameraInverseProjectionMatrix": { value: new Matrix4() }, "kernelRadius": { value: 8 }, "minDistance": { value: 0.005 }, - "maxDistance": { value: 0.05 }, + "maxDistance": { value: 0.05 }, + "cameraNear2": { value: 0 }, + "cameraRange": { value: 0 }, + "UVWR": { value: 0 }, }, @@ -52,13 +55,15 @@ var SSRShader = { #define MAX_DISTuv 1. //uv unit #define MAX_STEP ${innerWidth * Math.sqrt(2)} #define SURF_DISTuv .01 - #define UVWR 4.//uv unit to world unit ratio varying vec2 vUv; uniform sampler2D tDepth; uniform sampler2D tNormal; uniform sampler2D tDiffuse; + uniform float cameraRange; + uniform float cameraNear2; + uniform float UVWR; //uv unit to world unit ratio float depthToDistance(float depth){ - return (1.-depth)*${10}.+${1}.; + return (1.-depth)*cameraRange+cameraNear2; } vec3 getPos(vec2 uv,float depth){ vec3 pos; @@ -81,7 +86,7 @@ var SSRShader = { // gl_FragColor=texture2D(tDiffuse,uv); // gl_FragColor=texture2D(tNormal,uv)*2.-1.; // gl_FragColor.x=abs(gl_FragColor.x); - // gl_FragColor=vec4(depthToDistance(texture2D(tDepth,uv).r)/4.); + // gl_FragColor=vec4(depthToDistance(texture2D(tDepth,uv).r)/UVWR); // gl_FragColor.a=1.; // return; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 194bf52ad832df..e4a3b44e1762b4 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -55,10 +55,10 @@ s.cameraNear = 1 s.cameraFar = 11 - s.cameraRange = s.cameraFar - s.cameraNear s.cameraZ = 6 + s.cameraRadius = 2 // s.camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) - camera = new THREE.OrthographicCamera(-2, 2, 2, -2, s.cameraNear, s.cameraFar) + camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) s.camera = camera s.camera.position.z = s.cameraZ @@ -118,7 +118,7 @@ composer = new EffectComposer(renderer); - var ssrPass = new SSRPass(scene, camera, width, height); + var ssrPass = new SSRPass(scene, camera, width, height, s.cameraRadius, s.cameraNear, s.cameraFar); ssrPass.kernelRadius = 16; composer.addPass(ssrPass); diff --git a/examples/webgl_postprocessing_ssr_ok.html b/examples/webgl_postprocessing_ssr_ok.html index 194bf52ad832df..e4a3b44e1762b4 100644 --- a/examples/webgl_postprocessing_ssr_ok.html +++ b/examples/webgl_postprocessing_ssr_ok.html @@ -55,10 +55,10 @@ s.cameraNear = 1 s.cameraFar = 11 - s.cameraRange = s.cameraFar - s.cameraNear s.cameraZ = 6 + s.cameraRadius = 2 // s.camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) - camera = new THREE.OrthographicCamera(-2, 2, 2, -2, s.cameraNear, s.cameraFar) + camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) s.camera = camera s.camera.position.z = s.cameraZ @@ -118,7 +118,7 @@ composer = new EffectComposer(renderer); - var ssrPass = new SSRPass(scene, camera, width, height); + var ssrPass = new SSRPass(scene, camera, width, height, s.cameraRadius, s.cameraNear, s.cameraFar); ssrPass.kernelRadius = 16; composer.addPass(ssrPass); From 88c78e8e1018beff5b6e6d320047d4f8ea23ccb9 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 15:01:25 +0800 Subject: [PATCH 009/103] a --- examples/jsm/shaders/SSRShader.js | 9 +- examples/webgl_loader_stl_ssr.html | 254 +++++++++++++++++++++++++ examples/webgl_postprocessing_ssr.html | 150 ++++++++++----- 3 files changed, 357 insertions(+), 56 deletions(-) create mode 100644 examples/webgl_loader_stl_ssr.html diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index b4e4e63ad4a8fd..6a695929049804 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -30,10 +30,10 @@ var SSRShader = { "cameraInverseProjectionMatrix": { value: new Matrix4() }, "kernelRadius": { value: 8 }, "minDistance": { value: 0.005 }, - "maxDistance": { value: 0.05 }, - "cameraNear2": { value: 0 }, - "cameraRange": { value: 0 }, - "UVWR": { value: 0 }, + "maxDistance": { value: 0.05 }, + "cameraNear2": { value: 0 }, + "cameraRange": { value: 0 }, + "UVWR": { value: 0 }, }, @@ -128,6 +128,7 @@ var SSRShader = { vec4 reflect=texture2D(tDiffuse,vec2(u,v)); // gl_FragColor=color; gl_FragColor=reflect; + gl_FragColor.a=.5; // gl_FragColor=mix(color,reflect,.5); // gl_FragColor=vec4(u,v,0,1); break; diff --git a/examples/webgl_loader_stl_ssr.html b/examples/webgl_loader_stl_ssr.html new file mode 100644 index 00000000000000..fddb4e1fd71fb8 --- /dev/null +++ b/examples/webgl_loader_stl_ssr.html @@ -0,0 +1,254 @@ + + + + + three.js webgl - STL + + + + + + +
+ three.js - + STL loader test by aleeper.
+ PR2 head from www.ros.org +
+ + + + + diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index e4a3b44e1762b4..608210e3981f01 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -53,59 +53,101 @@ renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); - s.cameraNear = 1 - s.cameraFar = 11 - s.cameraZ = 6 - s.cameraRadius = 2 - // s.camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) - camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) - s.camera = camera - s.camera.position.z = s.cameraZ - - scene = new THREE.Scene(); - s.scene = scene - // scene.background = new THREE.Color(0xaaaaaa); - - scene.add(new THREE.DirectionalLight()); - scene.add(new THREE.HemisphereLight()); - - - {//mesh - let geo = new THREE.BoxBufferGeometry(1, 1, 1) - // let geo = new THREE.IcosahedronBufferGeometry(.5, 3) - let mtl = new THREE.MeshBasicMaterial({ - color: 'red', - side: THREE.DoubleSide, - }) - let mesh = new THREE.Mesh(geo, mtl) - s.mesh = mesh - s.scene.add(mesh) - window.mesh = mesh - // mesh.position.x=2 - // mesh.position.y=1 + + if (0) { + + s.cameraNear = 1 + s.cameraFar = 11 + s.cameraZ = 6 + s.cameraRadius = 2 + // s.camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) + camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) + s.camera = camera + s.camera.position.z = s.cameraZ + + scene = new THREE.Scene(); + s.scene = scene + // scene.background = new THREE.Color(0xaaaaaa); + {//mesh + let geo = new THREE.BoxBufferGeometry(1, 1, 1) + // let geo = new THREE.IcosahedronBufferGeometry(.5, 3) + let mtl = new THREE.MeshBasicMaterial({ + color: 'red', + side: THREE.DoubleSide, + }) + let mesh = new THREE.Mesh(geo, mtl) + s.mesh = mesh + s.scene.add(mesh) + window.mesh = mesh + // mesh.position.x=2 + // mesh.position.y=1 + } + // {//mesh 2 + // let geo = new THREE.BoxBufferGeometry(1, 1, 1) + // // let geo = new THREE.IcosahedronBufferGeometry(.5, 2) + // let mesh = new THREE.Mesh(geo, s.mtl_depth) + // s.mesh_2 = mesh + // // s.scene.add(mesh) + // window.mesh = mesh + // mesh.position.x = 2 + // } + {//ground + let geo = new THREE.PlaneBufferGeometry(4, 4) + let mtl = new THREE.MeshBasicMaterial({ + color: 'blue', + side: THREE.DoubleSide, + }) + let mesh = new THREE.Mesh(geo, mtl) + s.ground = mesh + s.scene.add(mesh) + // mesh.rotation.x = -Math.PI / 2 + // mesh.position.y = -.5 + geo.rotateX(-Math.PI / 2) + geo.translate(0, -.5, 0) + } } - // {//mesh 2 - // let geo = new THREE.BoxBufferGeometry(1, 1, 1) - // // let geo = new THREE.IcosahedronBufferGeometry(.5, 2) - // let mesh = new THREE.Mesh(geo, s.mtl_depth) - // s.mesh_2 = mesh - // // s.scene.add(mesh) - // window.mesh = mesh - // mesh.position.x = 2 - // } - {//ground - let geo = new THREE.PlaneBufferGeometry(4, 4) - let mtl = new THREE.MeshBasicMaterial({ - color: 'blue', - side: THREE.DoubleSide, - }) - let mesh = new THREE.Mesh(geo, mtl) - s.ground = mesh - s.scene.add(mesh) - // mesh.rotation.x = -Math.PI / 2 - // mesh.position.y = -.5 - geo.rotateX(-Math.PI / 2) - geo.translate(0, -.5, 0) + + if (1) { + + s.cameraNear = 100 + s.cameraFar = 700 + s.cameraZ = 500 + s.cameraRadius = 300 + // s.camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) + camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) + s.camera = camera + s.camera.position.z = s.cameraZ + + scene = new THREE.Scene(); + s.scene = scene + // scene.background = new THREE.Color(0xaaaaaa); + + scene.add(new THREE.DirectionalLight()); + scene.add(new THREE.HemisphereLight()); + + group = new THREE.Group(); + scene.add(group); + + var geometry = new THREE.BoxBufferGeometry(10, 10, 10); + + for (var i = 0; i < 100; i++) { + + var material = new THREE.MeshLambertMaterial({ + color: Math.random() * 0xffffff + }); + + var mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 400 - 200; + mesh.position.y = Math.random() * 400 - 200; + mesh.position.z = Math.random() * 400 - 200; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.rotation.z = Math.random(); + + mesh.scale.setScalar(Math.random() * 10 + 2); + group.add(mesh); + + } } new OrbitControls(s.camera, s.renderer.domElement) @@ -171,6 +213,10 @@ function render() { var timer = performance.now(); + if (0) { + group.rotation.x = timer * 0.0002; + group.rotation.y = timer * 0.0001; + } composer.render(); From d103220f17e53c5e8922bd5ac5dde415b28a1446 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 16:44:19 +0800 Subject: [PATCH 010/103] a --- examples/jsm/postprocessing/SSRPass.js | 2 +- examples/jsm/shaders/SSRShader.js | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 86eee939868a56..785b0127d2fdc6 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -224,7 +224,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render normals - this.renderOverride(renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0); + this.renderOverride(renderer, this.normalMaterial, this.normalRenderTarget, 0, 0); // render depths diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 6a695929049804..4597f3512e094b 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -105,6 +105,8 @@ var SSRShader = { vec3 normal=texture2D(tNormal,uv).xyz*2.-1.;//screen rigth always red vec3 reflectDir=reflect(vec3(0,0,-1),normal); + // float reflectDirLen=length(reflectDir); + // if(reflectDirLen<=0.) return; // reflectDir.x=abs(reflectDir.x); // reflectDir=normalize(vec3(-1,-1,0)); d1=d0+(reflectDir*MAX_DISTuv).xy*vec2(${innerWidth}.,${innerHeight}.); @@ -114,7 +116,7 @@ var SSRShader = { float totalStep=max(abs(xLen),abs(yLen)); float xSpan=xLen/totalStep; float ySpan=yLen/totalStep; - for(float i=20.;i=totalStep) break; float x=d0.x+i*xSpan; float y=d0.y+i*ySpan; @@ -124,7 +126,19 @@ var SSRShader = { float v=y/${innerHeight}.; vec3 p=getPos(vec2(u,v)); vec3 rayPos=pos+(length(vec2(x,y)-d0)/totalLen)*(reflectDir*MAX_DISTuv); - if(length(rayPos-p)=0.) continue; + // gl_FragColor=vec4(away*100.,0,0,1); + // break; + // gl_FragColor=vec4(u,v,0,1); + // break; vec4 reflect=texture2D(tDiffuse,vec2(u,v)); // gl_FragColor=color; gl_FragColor=reflect; @@ -237,20 +251,20 @@ var SSRBlurShader = { "void main() {", " vec2 texelSize = ( 1.0 / resolution );", - " float result = 0.0;", + " vec3 result = vec3(0);", " for ( int i = - 2; i <= 2; i ++ ) {", " for ( int j = - 2; j <= 2; j ++ ) {", " vec2 offset = ( vec2( float( i ), float( j ) ) ) * texelSize;", - " result += texture2D( tDiffuse, vUv + offset ).r;", + " result += texture2D( tDiffuse, vUv + offset ).xyz;", " }", " }", - " gl_FragColor = vec4( vec3( result / ( 5.0 * 5.0 ) ), 1.0 );", + " gl_FragColor = vec4( result / ( 5.0 * 5.0 ) , 1.0 );", "}" From 7468084e64b99d67e79874294f7addda3fb8fb0f Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 17:29:54 +0800 Subject: [PATCH 011/103] use resolution & delete depthRenderMaterial --- examples/jsm/postprocessing/SSRPass.js | 24 ------------------------ examples/jsm/shaders/SSRShader.js | 11 ++++++----- examples/webgl_postprocessing_ssr.html | 5 +++-- 3 files changed, 9 insertions(+), 31 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 785b0127d2fdc6..32d66851e6999f 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -28,7 +28,6 @@ import { Pass } from "../postprocessing/Pass.js"; import { SimplexNoise } from "../math/SimplexNoise.js"; import { SSRShader } from "../shaders/SSRShader.js"; import { SSRBlurShader } from "../shaders/SSRShader.js"; -import { SSRDepthShader } from "../shaders/SSRShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, cameraFar) { @@ -58,19 +57,10 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c this.generateSampleKernel(); this.generateRandomKernelRotations(); - // beauty render target with depth buffer - - var depthTexture = new DepthTexture(); - depthTexture.type = UnsignedShortType; - depthTexture.minFilter = NearestFilter; - depthTexture.maxFilter = NearestFilter; - this.beautyRenderTarget = new WebGLRenderTarget(this.width, this.height, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat, - depthTexture: depthTexture, - depthBuffer: true }); // normal render target @@ -150,19 +140,6 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c this.blurMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; this.blurMaterial.uniforms['resolution'].value.set(this.width, this.height); - // material for rendering the depth - - this.depthRenderMaterial = new ShaderMaterial({ - defines: Object.assign({}, SSRDepthShader.defines), - uniforms: UniformsUtils.clone(SSRDepthShader.uniforms), - vertexShader: SSRDepthShader.vertexShader, - fragmentShader: SSRDepthShader.fragmentShader, - blending: NoBlending - }); - this.depthRenderMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; - this.depthRenderMaterial.uniforms['cameraNear'].value = this.camera.near; - this.depthRenderMaterial.uniforms['cameraFar'].value = this.camera.far; - // material for rendering the content of a render target this.copyMaterial = new ShaderMaterial({ @@ -206,7 +183,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.depthMaterial.dispose(); this.blurMaterial.dispose(); this.copyMaterial.dispose(); - this.depthRenderMaterial.dispose(); // dipsose full screen quad diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 4597f3512e094b..4c2ecb66fe92eb 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -62,6 +62,7 @@ var SSRShader = { uniform float cameraRange; uniform float cameraNear2; uniform float UVWR; //uv unit to world unit ratio + uniform vec2 resolution; float depthToDistance(float depth){ return (1.-depth)*cameraRange+cameraNear2; } @@ -109,7 +110,7 @@ var SSRShader = { // if(reflectDirLen<=0.) return; // reflectDir.x=abs(reflectDir.x); // reflectDir=normalize(vec3(-1,-1,0)); - d1=d0+(reflectDir*MAX_DISTuv).xy*vec2(${innerWidth}.,${innerHeight}.); + d1=d0+(reflectDir*MAX_DISTuv).xy*vec2(resolution.x,resolution.y); float totalLen=length(d1-d0); float xLen=d1.x-d0.x; float yLen=d1.y-d0.y; @@ -120,10 +121,10 @@ var SSRShader = { if(i>=totalStep) break; float x=d0.x+i*xSpan; float y=d0.y+i*ySpan; - if(x<0.||x>${innerWidth}.) break; - if(y<0.||y>${innerHeight}.) break; - float u=x/${innerWidth}.; - float v=y/${innerHeight}.; + if(x<0.||x>resolution.x) break; + if(y<0.||y>resolution.y) break; + float u=x/resolution.x; + float v=y/resolution.y; vec3 p=getPos(vec2(u,v)); vec3 rayPos=pos+(length(vec2(x,y)-d0)/totalLen)*(reflectDir*MAX_DISTuv); float away=length(rayPos-p); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 608210e3981f01..2898d4147ccb58 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -54,7 +54,7 @@ document.body.appendChild(renderer.domElement); - if (0) { + if (1) { s.cameraNear = 1 s.cameraFar = 11 @@ -107,7 +107,7 @@ } } - if (1) { + if (0) { s.cameraNear = 100 s.cameraFar = 700 @@ -167,6 +167,7 @@ // Init gui var gui = new GUI(); + // console.log(ssrPass) gui.add(ssrPass, 'output', { 'Default': SSRPass.OUTPUT.Default, 'SSR Only': SSRPass.OUTPUT.SSR, From 67aa9502cc3e7070172a9d804dffa6d5eb30870e Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 11 Aug 2020 19:06:31 +0800 Subject: [PATCH 012/103] SSRPassPerspective --- examples/jsm/postprocessing/SSRPass.js | 53 ++++++------- examples/jsm/shaders/SSRShader.js | 105 +++++++++++-------------- 2 files changed, 74 insertions(+), 84 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 32d66851e6999f..9d42bba9e95845 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -28,6 +28,7 @@ import { Pass } from "../postprocessing/Pass.js"; import { SimplexNoise } from "../math/SimplexNoise.js"; import { SSRShader } from "../shaders/SSRShader.js"; import { SSRBlurShader } from "../shaders/SSRShader.js"; +import { SSRDepthShader } from "../shaders/SSRShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, cameraFar) { @@ -47,7 +48,7 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c this.kernelSize = 32; this.kernel = []; this.noiseTexture = null; - this.output = 0; + this.output = 1; this.minDistance = 0.005; this.maxDistance = 0.1; @@ -57,10 +58,19 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c this.generateSampleKernel(); this.generateRandomKernelRotations(); + // beauty render target with depth buffer + + var depthTexture = new DepthTexture(); + depthTexture.type = UnsignedShortType; + depthTexture.minFilter = NearestFilter; + depthTexture.maxFilter = NearestFilter; + this.beautyRenderTarget = new WebGLRenderTarget(this.width, this.height, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat, + depthTexture: depthTexture, + depthBuffer: true }); // normal render target @@ -71,13 +81,7 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c format: RGBAFormat }); - // depth render target - this.depthRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: NearestFilter, - magFilter: NearestFilter, - format: RGBAFormat - }); // ssr render target @@ -107,7 +111,7 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; - this.ssrMaterial.uniforms['tDepth'].value = this.depthRenderTarget.texture; + this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; this.ssrMaterial.uniforms['tNoise'].value = this.noiseTexture; this.ssrMaterial.uniforms['kernel'].value = this.kernel; this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; @@ -115,19 +119,13 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c this.ssrMaterial.uniforms['resolution'].value.set(this.width, this.height); this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix); this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.getInverse(this.camera.projectionMatrix); - this.ssrMaterial.uniforms['cameraNear2'].value = cameraNear - this.ssrMaterial.uniforms['cameraRange'].value = cameraFar - cameraNear - this.ssrMaterial.uniforms['UVWR'].value = cameraRadius * 2 // normal material this.normalMaterial = new MeshNormalMaterial(); this.normalMaterial.blending = NoBlending; - // depth material - this.depthMaterial = new MeshDepthMaterial(); - this.depthMaterial.blending = NoBlending; // blur material @@ -139,6 +137,18 @@ var SSRPass = function(scene, camera, width, height, cameraRadius, cameraNear, c }); this.blurMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; this.blurMaterial.uniforms['resolution'].value.set(this.width, this.height); + // material for rendering the depth + + this.depthRenderMaterial = new ShaderMaterial({ + defines: Object.assign({}, SSRDepthShader.defines), + uniforms: UniformsUtils.clone(SSRDepthShader.uniforms), + vertexShader: SSRDepthShader.vertexShader, + fragmentShader: SSRDepthShader.fragmentShader, + blending: NoBlending + }); + this.depthRenderMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; + this.depthRenderMaterial.uniforms['cameraNear'].value = this.camera.near; + this.depthRenderMaterial.uniforms['cameraFar'].value = this.camera.far; // material for rendering the content of a render target @@ -173,16 +183,15 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.beautyRenderTarget.dispose(); this.normalRenderTarget.dispose(); - this.depthRenderTarget.dispose(); this.ssrRenderTarget.dispose(); this.blurRenderTarget.dispose(); // dispose materials this.normalMaterial.dispose(); - this.depthMaterial.dispose(); this.blurMaterial.dispose(); this.copyMaterial.dispose(); + this.depthRenderMaterial.dispose(); // dipsose full screen quad @@ -202,10 +211,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.renderOverride(renderer, this.normalMaterial, this.normalRenderTarget, 0, 0); - // render depths - - this.renderOverride(renderer, this.depthMaterial, this.depthRenderTarget, 0, 0); - // render SSR this.ssrMaterial.uniforms['kernelRadius'].value = this.kernelRadius; @@ -247,9 +252,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { case SSRPass.OUTPUT.Depth: - this.copyMaterial.uniforms['tDiffuse'].value = this.depthRenderTarget.texture; - this.copyMaterial.blending = NoBlending; - this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); + this.renderPass(renderer, this.depthRenderMaterial, this.renderToScreen ? null : writeBuffer); break; @@ -282,8 +285,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, renderPass: function(renderer, passMaterial, renderTarget, clearColor, clearAlpha) { - // clearColor = 'black' - // clearAlpha = 1 // save original state this.originalClearColor.copy(renderer.getClearColor()); @@ -313,8 +314,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, renderOverride: function(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { - // clearColor = 'black' - // clearAlpha = 1 this.originalClearColor.copy(renderer.getClearColor()); var originalClearAlpha = renderer.getClearAlpha(); diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 4c2ecb66fe92eb..55f426d48d546b 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -12,7 +12,7 @@ import { var SSRShader = { defines: { - "PERSPECTIVE_CAMERA": 1, + "PERSPECTIVE_CAMERA": 0, "KERNEL_SIZE": 32 }, @@ -63,53 +63,52 @@ var SSRShader = { uniform float cameraNear2; uniform float UVWR; //uv unit to world unit ratio uniform vec2 resolution; - float depthToDistance(float depth){ - return (1.-depth)*cameraRange+cameraNear2; + uniform float cameraNear; + uniform float cameraFar; + uniform mat4 cameraProjectionMatrix; + uniform mat4 cameraInverseProjectionMatrix; + #include + float getDepth( const in vec2 screenPosition ) { + return texture2D( tDepth, screenPosition ).x; } - vec3 getPos(vec2 uv,float depth){ - vec3 pos; - vec3 viewDir=vec3(0,0,-1); - float distance=depthToDistance(depth)/UVWR; - vec3 viewRay=viewDir*distance; - pos=vec3(uv,0)+viewRay; - return pos; + float getLinearDepth( const in vec2 screenPosition ) { + #if PERSPECTIVE_CAMERA == 1 + float fragCoordZ = texture2D( tDepth, screenPosition ).x; + float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar ); + return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); + #else + return texture2D( tDepth, screenPosition ).x; + #endif } - vec3 getPos(vec2 uv){ - float depth=texture2D(tDepth,uv).r; - return getPos(uv,depth); + float getViewZ( const in float depth ) { + #if PERSPECTIVE_CAMERA == 1 + return perspectiveDepthToViewZ( depth, cameraNear, cameraFar ); + #else + return orthographicDepthToViewZ( depth, cameraNear, cameraFar ); + #endif + } + vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) { + float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3]; + vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 ); + clipPosition *= clipW; // unprojection. + return ( cameraInverseProjectionMatrix * clipPosition ).xyz; + } + vec3 getViewNormal( const in vec2 screenPosition ) { + return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz ); } void main(){ - //use uv unit/coordinate primarily - vec2 uv=vUv; - - // gl_FragColor=texture2D(tDepth,uv); - // gl_FragColor=texture2D(tNormal,uv); - // gl_FragColor=texture2D(tDiffuse,uv); - // gl_FragColor=texture2D(tNormal,uv)*2.-1.; - // gl_FragColor.x=abs(gl_FragColor.x); - // gl_FragColor=vec4(depthToDistance(texture2D(tDepth,uv).r)/UVWR); - // gl_FragColor.a=1.; - // return; - - // vec4 color=texture2D(tDiffuse,uv); - // vec4 reflectDiffuse; - // gl_FragColor=color; - - float depth=texture2D(tDepth,uv).r; - if(depth<=0.) return; + float depth = getDepth( vUv ); + float viewZ = getViewZ( depth ); + vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); + vec3 viewNormal = getViewNormal( vUv ); + + // if(depth<=0.) return; vec2 d0=gl_FragCoord.xy; vec2 d1; - vec3 pos=getPos(uv,depth); - // gl_FragColor.xyz=abs(pos); - // gl_FragColor.a=1.; - // return; + vec3 pos=viewPosition; - vec3 normal=texture2D(tNormal,uv).xyz*2.-1.;//screen rigth always red + vec3 normal=viewNormal; vec3 reflectDir=reflect(vec3(0,0,-1),normal); - // float reflectDirLen=length(reflectDir); - // if(reflectDirLen<=0.) return; - // reflectDir.x=abs(reflectDir.x); - // reflectDir=normalize(vec3(-1,-1,0)); d1=d0+(reflectDir*MAX_DISTuv).xy*vec2(resolution.x,resolution.y); float totalLen=length(d1-d0); float xLen=d1.x-d0.x; @@ -125,27 +124,19 @@ var SSRShader = { if(y<0.||y>resolution.y) break; float u=x/resolution.x; float v=y/resolution.y; - vec3 p=getPos(vec2(u,v)); + vec2 uv=vec2(u,v); + + float d = getDepth(uv); + float vZ = getViewZ( d ); + vec3 p=getViewPosition( uv, d, vZ ); vec3 rayPos=pos+(length(vec2(x,y)-d0)/totalLen)*(reflectDir*MAX_DISTuv); float away=length(rayPos-p); if(away=0.) continue; - // gl_FragColor=vec4(away*100.,0,0,1); - // break; - // gl_FragColor=vec4(u,v,0,1); - // break; - vec4 reflect=texture2D(tDiffuse,vec2(u,v)); - // gl_FragColor=color; + vec4 reflect=texture2D(tDiffuse,uv); gl_FragColor=reflect; gl_FragColor.a=.5; - // gl_FragColor=mix(color,reflect,.5); - // gl_FragColor=vec4(u,v,0,1); break; } } @@ -157,7 +148,7 @@ var SSRShader = { var SSRDepthShader = { defines: { - "PERSPECTIVE_CAMERA": 1 + "PERSPECTIVE_CAMERA": 0 }, uniforms: { @@ -202,7 +193,7 @@ var SSRDepthShader = { " #else", - " return texture2D( depthSampler, coord ).x;", + " return texture2D( tDepth, screenPosition ).x;", " #endif", From ebc4ab831f452ad9056be61f2ce2462bb3c3dc12 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Wed, 12 Aug 2020 05:11:06 +0800 Subject: [PATCH 013/103] a --- examples/jsm/shaders/SSRShader.js | 31 ++++++++++++++------------ examples/webgl_postprocessing_ssr.html | 13 ++++++----- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 55f426d48d546b..a07759c2d3621f 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -12,7 +12,7 @@ import { var SSRShader = { defines: { - "PERSPECTIVE_CAMERA": 0, + "PERSPECTIVE_CAMERA": 1, "KERNEL_SIZE": 32 }, @@ -52,9 +52,9 @@ var SSRShader = { ].join("\n"), fragmentShader: ` - #define MAX_DISTuv 1. //uv unit + #define MAX_DIST 10. #define MAX_STEP ${innerWidth * Math.sqrt(2)} - #define SURF_DISTuv .01 + #define SURF_DIST .05 varying vec2 vUv; uniform sampler2D tDepth; uniform sampler2D tNormal; @@ -100,16 +100,18 @@ var SSRShader = { float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); - vec3 viewNormal = getViewNormal( vUv ); + viewPosition=vec3(viewPosition.xy,viewZ); // if(depth<=0.) return; vec2 d0=gl_FragCoord.xy; vec2 d1; - vec3 pos=viewPosition; - vec3 normal=viewNormal; - vec3 reflectDir=reflect(vec3(0,0,-1),normal); - d1=d0+(reflectDir*MAX_DISTuv).xy*vec2(resolution.x,resolution.y); + vec3 viewNormal=getViewNormal( vUv );; + vec3 reflectDir=reflect(vec3(0,0,-1),viewNormal); + + vec3 d1pos=viewPosition+reflectDir*MAX_DIST; + d1=d0+(reflectDir*MAX_DIST).xy*vec2(resolution.x,resolution.y);///todo + float totalLen=length(d1-d0); float xLen=d1.x-d0.x; float yLen=d1.y-d0.y; @@ -128,12 +130,13 @@ var SSRShader = { float d = getDepth(uv); float vZ = getViewZ( d ); - vec3 p=getViewPosition( uv, d, vZ ); - vec3 rayPos=pos+(length(vec2(x,y)-d0)/totalLen)*(reflectDir*MAX_DISTuv); - float away=length(rayPos-p); - if(away=0.) continue; + vec3 vP=getViewPosition( uv, d, vZ ); + vP=vec3(vP.xy,vZ); + vec3 rayPos=viewPosition+(length(vec2(x,y)-d0)/totalLen)*(reflectDir*MAX_DIST); + float away=length(rayPos-vP); + if(away=0.) continue; vec4 reflect=texture2D(tDiffuse,uv); gl_FragColor=reflect; gl_FragColor.a=.5; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 2898d4147ccb58..3d7379ab472258 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -56,12 +56,12 @@ if (1) { - s.cameraNear = 1 - s.cameraFar = 11 - s.cameraZ = 6 + s.cameraNear = 0.1 + s.cameraFar = 10 + s.cameraZ = 5 s.cameraRadius = 2 - // s.camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) - camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) + camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) + // camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) s.camera = camera s.camera.position.z = s.cameraZ @@ -70,6 +70,7 @@ // scene.background = new THREE.Color(0xaaaaaa); {//mesh let geo = new THREE.BoxBufferGeometry(1, 1, 1) + // let geo = new THREE.PlaneBufferGeometry(2, 2) // let geo = new THREE.IcosahedronBufferGeometry(.5, 3) let mtl = new THREE.MeshBasicMaterial({ color: 'red', @@ -92,7 +93,7 @@ // mesh.position.x = 2 // } {//ground - let geo = new THREE.PlaneBufferGeometry(4, 4) + let geo = new THREE.PlaneBufferGeometry(10, 10) let mtl = new THREE.MeshBasicMaterial({ color: 'blue', side: THREE.DoubleSide, From d483010630cd353fec90e792bf8c3be4fafd69b2 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Wed, 12 Aug 2020 07:15:38 +0800 Subject: [PATCH 014/103] a --- examples/jsm/shaders/SSRShader.js | 34 ++++++++++++++++++++------ examples/webgl_loader_stl_ssr.html | 3 ++- examples/webgl_postprocessing_ssr.html | 4 +-- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index a07759c2d3621f..1e29c77e8f4f69 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -40,10 +40,12 @@ var SSRShader = { vertexShader: [ "varying vec2 vUv;", + "varying mat4 vProjectionMatrix;", "void main() {", " vUv = uv;", + " vProjectionMatrix = projectionMatrix;", " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", @@ -56,6 +58,7 @@ var SSRShader = { #define MAX_STEP ${innerWidth * Math.sqrt(2)} #define SURF_DIST .05 varying vec2 vUv; + varying mat4 vProjectionMatrix; uniform sampler2D tDepth; uniform sampler2D tNormal; uniform sampler2D tDiffuse; @@ -93,6 +96,15 @@ var SSRShader = { clipPosition *= clipW; // unprojection. return ( cameraInverseProjectionMatrix * clipPosition ).xyz; } + vec2 getViewPositionReverse( const in vec3 viewPosition, const in float depth, const in float viewZ ) { + float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3]; + vec4 clipPosition=cameraProjectionMatrix*vec4(viewPosition,1); + clipPosition/=clipW; + clipPosition.xyz/=2.; + clipPosition.xyz+=.5; + vec2 uv= clipPosition.xy; + return uv; + } vec3 getViewNormal( const in vec2 screenPosition ) { return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz ); } @@ -100,17 +112,26 @@ var SSRShader = { float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); - viewPosition=vec3(viewPosition.xy,viewZ); // if(depth<=0.) return; vec2 d0=gl_FragCoord.xy; + + // vec2 test=(vProjectionMatrix*vec4(viewPosition,1)).xy; + // // vec2 test=(cameraProjectionMatrix*vec4(viewPosition,1)).xy; + // test+=1.; + // test/=2.; + // vec2 test=getViewPositionReverse(viewPosition,depth,viewZ); + // gl_FragColor=vec4(test,0,1);return; + + vec2 d1; vec3 viewNormal=getViewNormal( vUv );; - vec3 reflectDir=reflect(vec3(0,0,-1),viewNormal); + vec3 viewReflectDir=reflect(vec3(0,0,-1),viewNormal); - vec3 d1pos=viewPosition+reflectDir*MAX_DIST; - d1=d0+(reflectDir*MAX_DIST).xy*vec2(resolution.x,resolution.y);///todo + vec3 d1viewPosition=viewPosition+viewReflectDir*MAX_DIST; + d1=getViewPositionReverse(d1viewPosition,depth,viewZ); + d1*=resolution; float totalLen=length(d1-d0); float xLen=d1.x-d0.x; @@ -131,12 +152,11 @@ var SSRShader = { float d = getDepth(uv); float vZ = getViewZ( d ); vec3 vP=getViewPosition( uv, d, vZ ); - vP=vec3(vP.xy,vZ); - vec3 rayPos=viewPosition+(length(vec2(x,y)-d0)/totalLen)*(reflectDir*MAX_DIST); + vec3 rayPos=viewPosition+(length(vec2(x,y)-d0)/totalLen)*(viewReflectDir*MAX_DIST); float away=length(rayPos-vP); if(away=0.) continue; + if(dot(viewReflectDir,vN)>=0.) continue; vec4 reflect=texture2D(tDiffuse,uv); gl_FragColor=reflect; gl_FragColor.a=.5; diff --git a/examples/webgl_loader_stl_ssr.html b/examples/webgl_loader_stl_ssr.html index fddb4e1fd71fb8..5b662cdd74a375 100644 --- a/examples/webgl_loader_stl_ssr.html +++ b/examples/webgl_loader_stl_ssr.html @@ -56,7 +56,8 @@ var cameraFar = 7 var cameraZ = 5 var cameraRadius = 1.5 - camera = new THREE.OrthographicCamera(-cameraRadius, cameraRadius, cameraRadius, -cameraRadius, cameraNear, cameraFar) + // camera = new THREE.OrthographicCamera(-cameraRadius, cameraRadius, cameraRadius, -cameraRadius, cameraNear, cameraFar) + camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, cameraNear, cameraFar) camera.position.z = cameraZ scene = new THREE.Scene(); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 3d7379ab472258..a229f339084cb8 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -10,9 +10,6 @@ rel="stylesheet" href="main.css"> @@ -63,6 +60,7 @@ camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, s.cameraNear, s.cameraFar) // camera = new THREE.OrthographicCamera(-s.cameraRadius, s.cameraRadius, s.cameraRadius, -s.cameraRadius, s.cameraNear, s.cameraFar) s.camera = camera + window.camera = camera s.camera.position.z = s.cameraZ scene = new THREE.Scene(); From 16a6725241cb6dd132e14858da4ae48f7c4428bc Mon Sep 17 00:00:00 2001 From: gonnavis Date: Wed, 12 Aug 2020 14:14:55 +0800 Subject: [PATCH 015/103] a --- examples/jsm/shaders/SSRShader.js | 31 +++++++++++++++++--------- examples/webgl_postprocessing_ssr.html | 5 +++-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 1e29c77e8f4f69..d7ad87712abdd9 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -54,11 +54,10 @@ var SSRShader = { ].join("\n"), fragmentShader: ` - #define MAX_DIST 10. + #define MAX_DIST 10.0 #define MAX_STEP ${innerWidth * Math.sqrt(2)} - #define SURF_DIST .05 + #define SURF_DIST .1 varying vec2 vUv; - varying mat4 vProjectionMatrix; uniform sampler2D tDepth; uniform sampler2D tNormal; uniform sampler2D tDiffuse; @@ -96,8 +95,8 @@ var SSRShader = { clipPosition *= clipW; // unprojection. return ( cameraInverseProjectionMatrix * clipPosition ).xyz; } - vec2 getViewPositionReverse( const in vec3 viewPosition, const in float depth, const in float viewZ ) { - float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3]; + vec2 getViewPositionReverse( const in vec3 viewPosition ) { + float clipW = cameraProjectionMatrix[2][3] * viewPosition.z + cameraProjectionMatrix[3][3]; vec4 clipPosition=cameraProjectionMatrix*vec4(viewPosition,1); clipPosition/=clipW; clipPosition.xyz/=2.; @@ -112,12 +111,15 @@ var SSRShader = { float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); + // gl_FragColor=vec4(viewPosition.xy,-viewPosition.z,1);return; + + // vec2 uv2=getViewPositionReverse(viewPosition); + // gl_FragColor=vec4(uv2,0,1);return; // if(depth<=0.) return; - vec2 d0=gl_FragCoord.xy; + vec2 d0=vUv*resolution; - // vec2 test=(vProjectionMatrix*vec4(viewPosition,1)).xy; - // // vec2 test=(cameraProjectionMatrix*vec4(viewPosition,1)).xy; + // vec2 test=(transpose(cameraProjectionMatrix)*vec4(viewPosition,1)).xy; // test+=1.; // test/=2.; // vec2 test=getViewPositionReverse(viewPosition,depth,viewZ); @@ -128,9 +130,16 @@ var SSRShader = { vec3 viewNormal=getViewNormal( vUv );; vec3 viewReflectDir=reflect(vec3(0,0,-1),viewNormal); + // gl_FragColor=vec4(viewReflectDir,1); return; vec3 d1viewPosition=viewPosition+viewReflectDir*MAX_DIST; - d1=getViewPositionReverse(d1viewPosition,depth,viewZ); + d1=getViewPositionReverse(d1viewPosition); + // d1=(transpose(cameraProjectionMatrix)*vec4(d1viewPosition,1)).xy; + // d1=(cameraInverseProjectionMatrix*vec4(d1viewPosition,1)).xy; + // d1+=1.; + // d1/=2.; + // gl_FragColor=vec4(vUv,0,1); return; + // gl_FragColor=vec4(d1,0,1); return; d1*=resolution; float totalLen=length(d1-d0); @@ -152,8 +161,8 @@ var SSRShader = { float d = getDepth(uv); float vZ = getViewZ( d ); vec3 vP=getViewPosition( uv, d, vZ ); - vec3 rayPos=viewPosition+(length(vec2(x,y)-d0)/totalLen)*(viewReflectDir*MAX_DIST); - float away=length(rayPos-vP); + vec3 vRayPos=viewPosition+(length(vec2(x,y)-d0)/totalLen)*(viewReflectDir*MAX_DIST); + float away=length(vRayPos-vP); if(away=0.) continue; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index a229f339084cb8..635a9aafb66ebb 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -23,6 +23,7 @@ + + + From 5262a8c44504af231dceefb3e9d67ba68236f415 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sat, 22 Aug 2020 02:42:13 +0800 Subject: [PATCH 022/103] almost OK --- examples/jsm/postprocessing/SSRPass.js | 5 +- examples/jsm/shaders/SSRShader.js | 6 +- examples/webgl_postprocessing_ssr.html | 480 +++++++++++++++++-------- 3 files changed, 333 insertions(+), 158 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index e108166af18353..f66fec415783cc 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -47,10 +47,11 @@ var SSRPass = function(scene, camera, width, height) { this.kernelSize = 32; this.kernel = []; this.noiseTexture = null; - this.output = 1; + this.output = 0; this.minDistance = 0.005; this.maxDistance = 0.1; + this.surfDist = 1. // @@ -115,6 +116,7 @@ var SSRPass = function(scene, camera, width, height) { this.ssrMaterial.uniforms['kernel'].value = this.kernel; this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far; + this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; this.ssrMaterial.uniforms['resolution'].value.set(this.width, this.height); this.ssrMaterial.uniforms['cameraProjectionMatrix'].value.copy(this.camera.projectionMatrix); this.ssrMaterial.uniforms['cameraInverseProjectionMatrix'].value.getInverse(this.camera.projectionMatrix); @@ -215,6 +217,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.ssrMaterial.uniforms['kernelRadius'].value = this.kernelRadius; this.ssrMaterial.uniforms['minDistance'].value = this.minDistance; this.ssrMaterial.uniforms['maxDistance'].value = this.maxDistance; + this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; this.renderPass(renderer, this.ssrMaterial, this.ssrRenderTarget); // render blur diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index f6e9177d4c9b5e..9698ac6c289330 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -13,7 +13,6 @@ var SSRShader = { defines: { "PERSPECTIVE_CAMERA": 1, - "KERNEL_SIZE": 32 }, uniforms: { @@ -32,6 +31,7 @@ var SSRShader = { "minDistance": { value: 0.005 }, "maxDistance": { value: 0.05 }, "cameraRange": { value: 0 }, + "surfDist": { value: 0 }, }, @@ -54,7 +54,6 @@ var SSRShader = { fragmentShader: ` #define MAX_DIST 1000.0 #define MAX_STEP ${innerWidth * Math.sqrt(2)} - #define SURF_DIST 1. varying vec2 vUv; uniform sampler2D tDepth; uniform sampler2D tNormal; @@ -63,6 +62,7 @@ var SSRShader = { uniform vec2 resolution; uniform float cameraNear; uniform float cameraFar; + uniform float surfDist; uniform mat4 cameraProjectionMatrix; uniform mat4 cameraInverseProjectionMatrix; #include @@ -147,7 +147,7 @@ var SSRShader = { float vZ = getViewZ( d ); vec3 vP=getViewPosition( uv, d, vZ ); float away=pointToLineDistance(vP,viewPosition,viewPosition+viewReflectDir*MAX_DIST); - if(away=0.) continue; vec4 reflectColor=texture2D(tDiffuse,uv); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 5b95c1c4112630..6ade7ae10037e4 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -2,180 +2,352 @@ - three.js webgl - postprocessing - Screen Space Ambient Occlusion - - - - - + + + three.js webgl - postprocessing - Screen Space Reflection + + + + -
- three.js - screen space ambient occlusion
-
- - + } + + + From 673b2ff50948c9137c68b6ed6088e74a4a06b47c Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sat, 22 Aug 2020 02:57:28 +0800 Subject: [PATCH 023/103] increase FOV --- examples/webgl_postprocessing_ssr.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 6ade7ae10037e4..61342ff9fe3d10 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -80,8 +80,9 @@ // camera = new THREE.OrthographicCamera(initialFrustumSize * aspect / - 2, initialFrustumSize * aspect / 2, initialFrustumSize / 2, initialFrustumSize / - 2, cameraNear, cameraFar); // camera.position.set(394.8768477903498, 424.03752576248496, 815.0242032138592) - camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 2, 10000 ); - camera.position.set( 500, 400, 1200 ); + camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 2, 10000 ); + camera.position.set( 307.043866722481, 340.37194439741677, 673.1047168390921); + window.camera=camera // SCENE @@ -275,7 +276,7 @@ // GUI gui = new GUI( { width: 400 } ); - ssrPass.surfDist=10 + ssrPass.surfDist=4.2 gui.add(ssrPass, 'output', { 'Default': SSRPass.OUTPUT.Default, 'DefaultBlur': SSRPass.OUTPUT.DefaultBlur, From 304b3ad4df7d839b1124816492ab1d17e679738a Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sat, 22 Aug 2020 03:08:00 +0800 Subject: [PATCH 024/103] a --- examples/jsm/shaders/SSRShader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 9698ac6c289330..7bb2e551860a65 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -106,7 +106,7 @@ var SSRShader = { return xy; } float pointToLineDistance(vec3 point, vec3 lineStart, vec3 lineEnd) { - //https://math.stackexchange.com/questions/1905533/find-perpendicular-distance-from-point-to-line-in-3d //Marco13 + //modified from https://math.stackexchange.com/questions/1905533/find-perpendicular-distance-from-point-to-line-in-3d answer: Marco13 vec3 d = (lineEnd - lineStart) / length(lineEnd-lineStart); vec3 v = point - lineStart; float t = dot(v,d); From b65ed773d03f551ec6690b6327d3327656672972 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 05:00:40 +0800 Subject: [PATCH 025/103] a --- examples/jsm/postprocessing/SSRPass.js | 85 ++----------------- examples/jsm/shaders/SSRShader.js | 18 ++-- examples/webgl_postprocessing_ssr.html | 9 +- ...webgl_postprocessing_ssr_simple_scene.html | 6 +- 4 files changed, 16 insertions(+), 102 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index f66fec415783cc..9ee6d4611f4d0c 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -25,7 +25,6 @@ import { DoubleSide } from "../../../build/three.module.js"; import { Pass } from "../postprocessing/Pass.js"; -import { SimplexNoise } from "../math/SimplexNoise.js"; import { SSRShader } from "../shaders/SSRShader.js"; import { SSRBlurShader } from "../shaders/SSRShader.js"; import { SSRDepthShader } from "../shaders/SSRShader.js"; @@ -43,21 +42,12 @@ var SSRPass = function(scene, camera, width, height) { this.camera = camera; this.scene = scene; - this.kernelRadius = 8; - this.kernelSize = 32; - this.kernel = []; - this.noiseTexture = null; + // this.opacity = .5; this.output = 0; - this.minDistance = 0.005; - this.maxDistance = 0.1; + this.maxDistance = 500; this.surfDist = 1. - // - - this.generateSampleKernel(); - this.generateRandomKernelRotations(); - // beauty render target with depth buffer var depthTexture = new DepthTexture(); @@ -112,8 +102,6 @@ var SSRPass = function(scene, camera, width, height) { this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; - this.ssrMaterial.uniforms['tNoise'].value = this.noiseTexture; - this.ssrMaterial.uniforms['kernel'].value = this.kernel; this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far; this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; @@ -214,14 +202,14 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render SSR - this.ssrMaterial.uniforms['kernelRadius'].value = this.kernelRadius; - this.ssrMaterial.uniforms['minDistance'].value = this.minDistance; + // this.ssrMaterial.uniforms['opacity'].value = this.opacity; this.ssrMaterial.uniforms['maxDistance'].value = this.maxDistance; - this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; + this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; this.renderPass(renderer, this.ssrMaterial, this.ssrRenderTarget); // render blur + // this.blurMaterial.uniforms['opacity'].value = this.opacity; this.renderPass(renderer, this.blurMaterial, this.blurRenderTarget); // output result to screen @@ -365,69 +353,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, - generateSampleKernel: function() { - - var kernelSize = this.kernelSize; - var kernel = this.kernel; - - for (var i = 0; i < kernelSize; i++) { - - var sample = new Vector3(); - sample.x = (Math.random() * 2) - 1; - sample.y = (Math.random() * 2) - 1; - sample.z = Math.random(); - - sample.normalize(); - - var scale = i / kernelSize; - scale = MathUtils.lerp(0.1, 1, scale * scale); - sample.multiplyScalar(scale); - - kernel.push(sample); - - } - - }, - - generateRandomKernelRotations: function() { - - var width = 4, - height = 4; - - if (SimplexNoise === undefined) { - - console.error('THREE.SSRPass: The pass relies on SimplexNoise.'); - - } - - var simplex = new SimplexNoise(); - - var size = width * height; - var data = new Float32Array(size * 4); - - for (var i = 0; i < size; i++) { - - var stride = i * 4; - - var x = (Math.random() * 2) - 1; - var y = (Math.random() * 2) - 1; - var z = 0; - - var noise = simplex.noise3d(x, y, z); - - data[stride] = noise; - data[stride + 1] = noise; - data[stride + 2] = noise; - data[stride + 3] = 1; - - } - - this.noiseTexture = new DataTexture(data, width, height, RGBAFormat, FloatType); - this.noiseTexture.wrapS = RepeatWrapping; - this.noiseTexture.wrapT = RepeatWrapping; - - } - }); SSRPass.OUTPUT = { diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 7bb2e551860a65..1c2488cd979153 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -4,9 +4,7 @@ import { } from "../../../build/three.module.js"; /** * References: - * http://john-chapman-graphics.blogspot.com/2013/01/ssr-tutorial.html - * https://learnopengl.com/Advanced-Lighting/SSR - * https://github.com/McNopper/OpenGL/blob/master/Example28/shader/ssr.frag.glsl + * https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html */ var SSRShader = { @@ -20,15 +18,12 @@ var SSRShader = { "tDiffuse": { value: null }, "tNormal": { value: null }, "tDepth": { value: null }, - "tNoise": { value: null }, - "kernel": { value: null }, "cameraNear": { value: null }, "cameraFar": { value: null }, "resolution": { value: new Vector2() }, "cameraProjectionMatrix": { value: new Matrix4() }, "cameraInverseProjectionMatrix": { value: new Matrix4() }, - "kernelRadius": { value: 8 }, - "minDistance": { value: 0.005 }, + // "opacity": { value: .5 }, "maxDistance": { value: 0.05 }, "cameraRange": { value: 0 }, "surfDist": { value: 0 }, @@ -38,12 +33,10 @@ var SSRShader = { vertexShader: [ "varying vec2 vUv;", - "varying mat4 vProjectionMatrix;", "void main() {", " vUv = uv;", - " vProjectionMatrix = projectionMatrix;", " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", @@ -52,7 +45,6 @@ var SSRShader = { ].join("\n"), fragmentShader: ` - #define MAX_DIST 1000.0 #define MAX_STEP ${innerWidth * Math.sqrt(2)} varying vec2 vUv; uniform sampler2D tDepth; @@ -62,6 +54,8 @@ var SSRShader = { uniform vec2 resolution; uniform float cameraNear; uniform float cameraFar; + // uniform float opacity; + uniform float maxDistance; uniform float surfDist; uniform mat4 cameraProjectionMatrix; uniform mat4 cameraInverseProjectionMatrix; @@ -124,7 +118,7 @@ var SSRShader = { vec3 viewNormal=getViewNormal( vUv );; vec3 viewReflectDir=reflect(normalize(viewPosition),viewNormal); - vec3 d1viewPosition=viewPosition+viewReflectDir*MAX_DIST; + vec3 d1viewPosition=viewPosition+viewReflectDir*maxDistance; d1=viewPositionToXY(d1viewPosition); float totalLen=length(d1-d0); @@ -146,7 +140,7 @@ var SSRShader = { float d = getDepth(uv); float vZ = getViewZ( d ); vec3 vP=getViewPosition( uv, d, vZ ); - float away=pointToLineDistance(vP,viewPosition,viewPosition+viewReflectDir*MAX_DIST); + float away=pointToLineDistance(vP,viewPosition,viewPosition+viewReflectDir*maxDistance); if(away=0.) continue; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 61342ff9fe3d10..c0476f0fc3c659 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -290,13 +290,8 @@ ssrPass.output = parseInt(value); }); - // gui.add(params, 'enableSSR').name( 'Enable SSR' ); - // gui.add(ssrPass, 'opacity').min(0).max(1); - // gui.add(ssrPass, 'maxDistance').min(0).max(2); - // gui.add(ssrPass, 'stepStride').min(1).max(10).step(1); - gui.add(ssrPass, 'surfDist').min(1).max(20).step(.1); - // gui.add(ssrPass, 'isFade'); - // gui.add(ssrPass, 'fadeIntensity').min(0).max(10).step(.1); + gui.add(ssrPass, 'maxDistance').min(1).max(1000); + gui.add(ssrPass, 'surfDist').min(1).max(10).step(.1); } diff --git a/examples/webgl_postprocessing_ssr_simple_scene.html b/examples/webgl_postprocessing_ssr_simple_scene.html index 5b95c1c4112630..76c1e6916c0a18 100644 --- a/examples/webgl_postprocessing_ssr_simple_scene.html +++ b/examples/webgl_postprocessing_ssr_simple_scene.html @@ -120,6 +120,7 @@ var gui = new GUI(); // console.log(ssrPass) + ssrPass.output=1 gui.add(ssrPass, 'output', { 'Default': SSRPass.OUTPUT.Default, 'SSR Only': SSRPass.OUTPUT.SSR, @@ -132,9 +133,8 @@ ssrPass.output = parseInt(value); }); - gui.add(ssrPass, 'kernelRadius').min(0).max(32); - gui.add(ssrPass, 'minDistance').min(0.001).max(0.02); - gui.add(ssrPass, 'maxDistance').min(0.01).max(0.3); + gui.add(ssrPass, 'maxDistance').min(1).max(1000); + gui.add(ssrPass, 'surfDist').min(1).max(10).step(.1); window.addEventListener('resize', onWindowResize, false); From 963e6b13b403fdbd2025c035ebb1108d4a9f396a Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 05:07:53 +0800 Subject: [PATCH 026/103] a --- examples/jsm/postprocessing/SSRPass.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 9ee6d4611f4d0c..a866d76b5d1795 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -45,7 +45,7 @@ var SSRPass = function(scene, camera, width, height) { // this.opacity = .5; this.output = 0; - this.maxDistance = 500; + this.maxDistance = 550; this.surfDist = 1. // beauty render target with depth buffer From 0d24e9dc8fd0d2504ff75ec25f923e9ed3373d4e Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 06:39:48 +0800 Subject: [PATCH 027/103] A --- examples/jsm/postprocessing/SSRPass.js | 2 +- examples/jsm/shaders/SSRShader.js | 8 +++++++- examples/webgl_postprocessing_ssr.html | 4 ++-- examples/webgl_postprocessing_ssr_simple_scene.html | 4 ++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index a866d76b5d1795..68884029c95663 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -45,7 +45,7 @@ var SSRPass = function(scene, camera, width, height) { // this.opacity = .5; this.output = 0; - this.maxDistance = 550; + this.maxDistance = 900; this.surfDist = 1. // beauty render target with depth buffer diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 1c2488cd979153..3dc149ccd88907 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -117,9 +117,15 @@ var SSRShader = { vec3 viewNormal=getViewNormal( vUv );; vec3 viewReflectDir=reflect(normalize(viewPosition),viewNormal); - vec3 d1viewPosition=viewPosition+viewReflectDir*maxDistance; + if(d1viewPosition.z>0.){ + float scale=viewPosition.z/(viewPosition.z+-d1viewPosition.z); + d1viewPosition.xy*=scale; + d1viewPosition.z=0.; + } + // gl_FragColor=vec4(d1viewPosition/100.,1);return; d1=viewPositionToXY(d1viewPosition); + // gl_FragColor=vec4(d1/resolution,0,1);return; float totalLen=length(d1-d0); float xLen=d1.x-d0.x; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index c0476f0fc3c659..2bbf41c0521af8 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -290,8 +290,8 @@ ssrPass.output = parseInt(value); }); - gui.add(ssrPass, 'maxDistance').min(1).max(1000); - gui.add(ssrPass, 'surfDist').min(1).max(10).step(.1); + gui.add(ssrPass, 'maxDistance').min(0).max(1000); + gui.add(ssrPass, 'surfDist').min(0).max(10).step(.1); } diff --git a/examples/webgl_postprocessing_ssr_simple_scene.html b/examples/webgl_postprocessing_ssr_simple_scene.html index 76c1e6916c0a18..bd129782914da2 100644 --- a/examples/webgl_postprocessing_ssr_simple_scene.html +++ b/examples/webgl_postprocessing_ssr_simple_scene.html @@ -133,8 +133,8 @@ ssrPass.output = parseInt(value); }); - gui.add(ssrPass, 'maxDistance').min(1).max(1000); - gui.add(ssrPass, 'surfDist').min(1).max(10).step(.1); + gui.add(ssrPass, 'maxDistance').min(0).max(1000); + gui.add(ssrPass, 'surfDist').min(0).max(10).step(.1); window.addEventListener('resize', onWindowResize, false); From 4e9f48bf8bf0217f560340e21b03059c49ecf5d8 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 06:41:08 +0800 Subject: [PATCH 028/103] A --- examples/webgl_postprocessing_ssr.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 2bbf41c0521af8..9679666d11e12e 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -279,7 +279,7 @@ ssrPass.surfDist=4.2 gui.add(ssrPass, 'output', { 'Default': SSRPass.OUTPUT.Default, - 'DefaultBlur': SSRPass.OUTPUT.DefaultBlur, + // 'DefaultBlur': SSRPass.OUTPUT.DefaultBlur, 'SSR Only': SSRPass.OUTPUT.SSR, 'SSR Only + Blur': SSRPass.OUTPUT.Blur, 'Beauty': SSRPass.OUTPUT.Beauty, From 83f19f8396bf21ed5936722389bea0bdbd19f081 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 06:44:59 +0800 Subject: [PATCH 029/103] a --- examples/webgl_postprocessing_ssr.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 9679666d11e12e..4468f8457469f6 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -81,8 +81,8 @@ // camera.position.set(394.8768477903498, 424.03752576248496, 815.0242032138592) camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 2, 10000 ); - camera.position.set( 307.043866722481, 340.37194439741677, 673.1047168390921); - window.camera=camera + camera.position.set( 388.5770726262176, 305.6568142796153, 647.1326965696304); + // window.camera=camera // SCENE From 5c777456ab79c3f8ff91f556d654aabd0ff7dd86 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 06:47:02 +0800 Subject: [PATCH 030/103] clean --- examples/webgl_postprocessing_ssr_bak_1.html | 149 -------------- examples/webgl_postprocessing_ssr_bak_2.html | 157 --------------- examples/webgl_postprocessing_ssr_bak_3.html | 172 ----------------- examples/webgl_postprocessing_ssr_ok.html | 182 ------------------ ...webgl_postprocessing_ssr_simple_scene.html | 181 ----------------- 5 files changed, 841 deletions(-) delete mode 100644 examples/webgl_postprocessing_ssr_bak_1.html delete mode 100644 examples/webgl_postprocessing_ssr_bak_2.html delete mode 100644 examples/webgl_postprocessing_ssr_bak_3.html delete mode 100644 examples/webgl_postprocessing_ssr_ok.html delete mode 100644 examples/webgl_postprocessing_ssr_simple_scene.html diff --git a/examples/webgl_postprocessing_ssr_bak_1.html b/examples/webgl_postprocessing_ssr_bak_1.html deleted file mode 100644 index 371d4d21e62e0e..00000000000000 --- a/examples/webgl_postprocessing_ssr_bak_1.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - three.js webgl - postprocessing - Screen Space Ambient Occlusion - - - - - - -
- three.js - screen space ambient occlusion
-
- - - - diff --git a/examples/webgl_postprocessing_ssr_bak_2.html b/examples/webgl_postprocessing_ssr_bak_2.html deleted file mode 100644 index 1fb9770e86bd25..00000000000000 --- a/examples/webgl_postprocessing_ssr_bak_2.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - three.js webgl - postprocessing - Screen Space Ambient Occlusion - - - - - - - -
- three.js - screen space ambient occlusion
-
- - - - - diff --git a/examples/webgl_postprocessing_ssr_bak_3.html b/examples/webgl_postprocessing_ssr_bak_3.html deleted file mode 100644 index 8012ef4b87b8ed..00000000000000 --- a/examples/webgl_postprocessing_ssr_bak_3.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - three.js webgl - postprocessing - Screen Space Ambient Occlusion - - - - - - - -
- three.js - screen space ambient occlusion
-
- - - - - diff --git a/examples/webgl_postprocessing_ssr_ok.html b/examples/webgl_postprocessing_ssr_ok.html deleted file mode 100644 index e4a3b44e1762b4..00000000000000 --- a/examples/webgl_postprocessing_ssr_ok.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - three.js webgl - postprocessing - Screen Space Ambient Occlusion - - - - - - - -
- three.js - screen space ambient occlusion
-
- - - - - diff --git a/examples/webgl_postprocessing_ssr_simple_scene.html b/examples/webgl_postprocessing_ssr_simple_scene.html deleted file mode 100644 index bd129782914da2..00000000000000 --- a/examples/webgl_postprocessing_ssr_simple_scene.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - three.js webgl - postprocessing - Screen Space Ambient Occlusion - - - - - - - -
- three.js - screen space ambient occlusion
-
- - - - - From f776e9a3b7a396b4f422bc55975b99aa7c618b61 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 06:48:12 +0800 Subject: [PATCH 031/103] clean --- examples/webgl_loader_stl_ssr.html | 255 ----------------------------- 1 file changed, 255 deletions(-) delete mode 100644 examples/webgl_loader_stl_ssr.html diff --git a/examples/webgl_loader_stl_ssr.html b/examples/webgl_loader_stl_ssr.html deleted file mode 100644 index 5b662cdd74a375..00000000000000 --- a/examples/webgl_loader_stl_ssr.html +++ /dev/null @@ -1,255 +0,0 @@ - - - - - three.js webgl - STL - - - - - - -
- three.js - - STL loader test by aleeper.
- PR2 head from www.ros.org -
- - - - - From acf4d0622763ee424311179de98d7598a73365f4 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 07:17:37 +0800 Subject: [PATCH 032/103] screenshot --- examples/files.js | 2 ++ .../screenshots/webgl_postprocessing_ssr.jpg | Bin 0 -> 17580 bytes 2 files changed, 2 insertions(+) create mode 100644 examples/screenshots/webgl_postprocessing_ssr.jpg diff --git a/examples/files.js b/examples/files.js index 262ee47ee27649..cad1388ce24142 100644 --- a/examples/files.js +++ b/examples/files.js @@ -268,6 +268,7 @@ var files = { "webgl_postprocessing_smaa", "webgl_postprocessing_sobel", "webgl_postprocessing_ssao", + "webgl_postprocessing_ssr", "webgl_postprocessing_taa", "webgl_postprocessing_unreal_bloom", "webgl_postprocessing_unreal_bloom_selective" @@ -483,6 +484,7 @@ var tags = { "webgl_postprocessing_smaa": [ "msaa", "multisampled" ], "webgl_postprocessing_sobel": [ "filter", "edge detection" ], "webgl_postprocessing_ssao": [ "ambient occlusion" ], + "webgl_postprocessing_ssr": [ "screen space reflection" ], "webgl_postprocessing_unreal_bloom": [ "glow" ], "webgl_postprocessing_unreal_bloom_selective": [ "glow" ], "webgl_fire": [ "smoke" ], diff --git a/examples/screenshots/webgl_postprocessing_ssr.jpg b/examples/screenshots/webgl_postprocessing_ssr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..450a125de016ee0cd2e4e1bfd24f10d43ca16fc0 GIT binary patch literal 17580 zcmdVBby!~pKo1PvS+VZ_ZqwRWM=lt-OSwzfJV_9VhaGMs&WDF0soS_ zJpj3ahZWQZfC0e1S4#l^cPm(Y_U`U35`274a9#^*XG46Sq_`qS%460X%+)vO@2)mc^i9(im#iEuCJD!l`qsv+?qvJ1}Nn% z;SFw?bRG^`z4p83N%?2pUE5c(1 z5)uH4it~a*_{9Z;o&g2;L85&8qI@7h9)6GnzlemOIPmYna$lO8wXMWU1*N~2b$=(# z^7lr0d3o`A3GzC-+3|tI#l`vf1^5I6cVZ<@=v$_ZD0MHp{C~lwjISBKj)ZO7#JA;ngTE|v9NJ)@$m0;e`WmNIb;9~EKF=HTpTP6d`t|S`xf52Ajf_T zdWZvlL17Wc@)8%%HAsMxD*HKWtn5M45_q7o@`wg%Uz5}>kWPh7@8B|k9S5%*P(6yObeFrdw z${d(!cY`Jk>e{xGfBzD}YhYSBc+ud5mfmQIBR@a5102`0CpIu;@x;}c3I^MQJzl-5 z+u4@YEWR(eB%@+$#M$lb`D8yK&0C@VY4xQ)p7Tq@6^ArDJ?*(5qJh&s9 zIo|s5N)u?*rCf^Q`esgxufCD?HpBV0u}->h23=36+|GPq5qYg{699~`USMrW$!ap> zv8$c8LFove?pseyA?!^Qxs->OZfm)(eyJSR!c;EiSOk}2_SxTQY)yh>*`s&&4vW9g zJptCuuS_(4H01iD6)V)jfG1oxf^<}>4;n`=#3w5@&QHJ4rQ;uO+2 zHrKOy)%a1|NgX?|Ht*8-4lqr;Bt9GAHsw>cKrWKp%g_yvaX9-~21;2u_}xsgXBK|C zYiJ5{ZJy7_tCX)Z`T>L@$Hu3<+^3RjWq;8B#DRnw2Hci)`lv2?bjg`|#LR38)mLmG!COrDvEE9pRF$*% z{CsV$)YDUgkoQA>-kDdXH+_K^txbQqHOC8EtWWRtUEmef>{l8Ja9`fuaCGfrSjK|p zuvaDs^#oIdb^8X$bc;YJ3lb`bZQuGfdWo{1r)tyMmwhJtAB(TK8q6%AsXlSbZ{Div zXCDn~a=+2hdHkHfqPVTBddbQPC0*#m=z&bBpW7#LwV~>TnDheHoW z*mT;r6Ma*@5MnduRKaJzdFG@b@}dT?m})i?HBpVZ>~RNpW}8B{Ds~5`-?`w}t$k`v zwCL}VVHiVNuoUdvTx)n`X&bPV5pcA%O9ThcU4x*UGIRm%*<#Q3Hza*EVU4e2c2oWNhL~}3OY0r=12Plo zUHlqZ^X*$^9HZ)_wQJ&cXiqv7KB;@q^h$K?i8Cl@CoT$??^oZvcpc*beSHUTe@m$R zim^7v_8o2JC+^mFKcUx&Ztt+B8GtJLsgoP%F>M zfWsZ28F_gJKuIrhEY4*JC!cry0Wk}|-JQMOEg|=?|1JBwoF`Ibe_Yn3rXhW`CJRO0 zD`Bad`sEAMXz-opFWG}Kt0ntCq?hd8gT8Cp??--=Haad&SBaOyE>NsUt^saaQwLW{ zN{fa%`{I$Vvx4at6B=Dw3%NZ$vV?<@~%;Ln-L1L)hGf%6=T~vSZ{f`7BCT9Io;;J|F z@2kiE>1F>)X1$|bPWYq1o1d9RI+J;|4Zpk{dW#~*jbK{OZcO)KOY>J+Vl|L!@%)fi z(2_iLldpGx#LOqZx6*Z!ic)Uv!~V$PO}JAJFG{xiofwpe^oeBZI$fJKXI%Rcq9Y7V zALDGq_WztSk+UzOkHWkm%wI?!Dlzk(tCYF)Z#!eDueGYOWvFci-48ByZMkbMm?O4Z zq2IDv>d{Z_J3!e&x3Z8|#d*bo%%-rdCFcJ~h@;w85~t6nNwKSFU$X|ob4?!PLw@KV zCnsy#J-jjA>+U+NTY#yTVrzfY7YN4dW12>8g+`SwxA#HF9gOSXOnYzLu4H*@RxOU0 zeb2AeN!`6Jd91d(ep@xb9ZX;I0;7FQ4IcWxR9Vwv;5UD@?w8oEs+zGK<36bTok`Z* zFlyHd#eYmV=^BbJ*a2mmxq0@B`Czjc+9f(SQ~T#}%PtLTN6o%}a%QZd(%wMxwbAr> zWIWB2V!qFK#Evj}{o5U>o$QU3ry!B&b@+)EvTkjG2OA^Pj$)mPUHMGd3am{yH!njd zTkUw9Cc#lsAoRrsxj1v6%TLID+Bv^f#UV?Ld=c1ZjZ&kdW4J8U^s!Qh#;Br*AR_bW z&}4Y|xq7IzpPe0AEP!r@?!*KKBOlkJ7^uUO3!mGZ-(C~^Bg-LS$QBx988lOK#99e4 zRycw?!Hm)jCsRW4{|6$geof!dW;)?vLw<7>_$h}mzv45s6a*rcSksm!SK)9ua>CPo znPVxd*+zFe5%_9~QtmL^;S;WTD}FGMA7I?@-0*0kp$4|p7V*3oe#H*rv|6PbT2iZkvJM8c7M!l ztl?mq;}I7uvoUXv;?q|*oinDDNL(3f(5b0eR(1$zIX04r)<)3;z|rk`zQz+qo|!K@ zD6R^%%>t#wmWlQC=X!}5jRUl$pyaY57fmw#%@)-G3tw;pa=<0@1v;bTMiQBma80kL z_BC1t5wHUV6lvh1QL0Z`|Bk)PBR&JCKch#!QJM9Qp2Cwe|IHxrpx%AH0J<-2NcS;{ z{?>NG)4bK45Bh(hywF_d*}&uZHm?!S0<>u8 z!ASG#-_pF{mo<`0=RLz4Q@6>D)_fi<&aKg^!Kzl~z`)9KPq_xARXjQ-^?^G8S&N;U zU*n}7}ef2ju14>OPc`IW9ezbDrE9ob72hbZ~^R(Y`mdRh->v9VA z5csxP7ws4gjR@*DYN{P>0#y9ut3<)fJPJ4_qO0A|!jVSoZRsbO1H|9EM69UR2gqZv_6b zf#YyASC_(ttj0C{!8(1$%%Q69m%7dG7USWnAeIK5NxLBi$+_X7t=(wQc9=hEi4?lu zD%_?i9o%`o-5yV(z&z)t@8_3T)@W0HFy!@gguyS9$z2;a@S%8M^QswRY1nrO=aY;L zuJr%61pF_g4*t1>2=05tESdZH4<(aa+Sb!cPO0EV@nPK~ejiMDTH$im3HFw_b_aO< z!LVEAy)8xBhAb9dEQfgiTLMy`7X06EL4Uz?{vGzMitsxC-BP%R;jP2qTiM{TUFeXuUc1ySE-BDF3*HiK!1op*-L}xm^DHqyqlgdM z`E(6c5Csg*pNrP&+oavh)YfLUGA&tk+xFFV`~*X{%gV&T14`(DM{?GVz#lxSL~Is8 zE2};4d6`PRGVTBlVg|-2yeLGfSle&|E2So|c z5qcR+kQOp>MVkHdN@8ylo{|)?X$F-{&KC+lzctTf+7jDyiC48}+cfYuT^_WBODXNS z)PxAvu(I&0)_E7CeA(o9I3WE#rXG|@J4m7VI-0#DNx05RygbI-YKUjxNAsCMdp&Ax z*QGwf&!@w^Y+S)6d+Px`--M}J>##F2H}jxabf#rmTU%S}!OoTMoFK)_7VJXu!-t+S zt#I#j4e#*~*>nTNRR;8!3_|##BU-cs8ei^BMF{Ds3^S|=upL8Qx{}(!BX+YzNBob^su=*t+}EmxJ)o|cy9k7FXhZH*y9UvQkKGafvim0xN@ugssHdKK87k!;oMO~rW4cAX0t{Dh|Ur6|)$C(B414QTnQ z^oAcv98^gJG#{YPv`IVBoqSofvMVtgh0IH9QcMwxt^HGnQ=Ux78joiIl1_8R;oA?T z%Opw!T}bQ?&CD+|wVi7v&u@%B^?sLiDu0`EY#I&8{4L7H~tmU1Go4IMyd-q;8 zl4QAUY=#?@(?i_Bo=4)*(2O1f-R%!J+?}L|;i~|h(<{cG$?2so8BFcy?e2BaRB~tK zugzJkw~V$mP!q6I1-XRDz8D={43B}*?uoWApC!>VP{k5CrUYNz86qvClBv1Nw)@5L!jW7!=@b%Fs8P-P<%$78Qe)lAz zo+qHGJA@47V9C%Yvc1l_xv#_^p}0^sy^92sviC!f2L%mtN5t+8Z}f=DPA5OC zGvO~dyO}&?bDE@art4WL$_(!9aC7p|&%5X?bl!uRCRdM`!|tc6h%(+zRjZbVR^#3k zLAO8@ip}bUk!N{&>(BW@;dfs9HbO}B!)vd4>eRPe`^_R5m06EG4J>L%qsChgcqWwM zmuK5bUifpQ8KF&`=kEZTxxF-hEGD&4Aw4`_zOY$4vul%K>>=@|OzM5UF_TGklBxSJdK&7Ek1tpq%(iNf1Y+KDa4kyVJyUwW7oZd?zd@~-FMdAt z9em}EWqgl6ZUUX?*>r`g6juA#SjxPCt6W@yX3S|$bFDmOuanco-jy)=y$WklXzSQ% zSG#gWGwyfR4H(*0*Cndh)I&mgtR}_}!l0%Rio%#}qPf4cazwe!{4|WlDAN7>;YaQ_ zB_l*_I87=SS{Pyg6FPo-Ua?qQtjF=!i>XG#CfA=Ll!RPw`cCI1skd7k593Dun2ud5 zAufU;f>)p*q0ZeK2JuQ=ej=syi`DAz%!`kz;u;iR`zuob{YKhP4??NaxL3F6Gu% zL3pF*Rj$8s5!2o1Q8HxARd5eo&2HBf+*FIjXj@m!&O{t2XcO6*`^TV0I~=BZNkZr5 z1fsICI!QK;{Q?~4W>Y42hM?c+Gd@+GUW-2WQsS@6z~DfcO`c|$PZ%J@8>AL1oMx`P z8*cZ1Y%7fb<`gWKNjHBkFAgTP`g|Edb!?6E#1tRzFGLE8C`FoZ9ww^3elmiZ`SS5k zD%BrPYOj;ZFLmuZHz|BD>z|SupY7SgCDW;?b|BEXIN4XAOrj(0XKOs~zBb+;AzsBC z8^ggL#aZ2*#*d8jvQ5OZ!hyP#7?{EFIGDJfi8<-i@Uzzur<|1gV9I^DLWc)AxKgp4 z2P#}9&v8tDU|%)@(>cN)WP!acr;a#PXqt&WK*Ga5cS+VA+S?Nfr*lJCR}r=#@nsz9 zbP7^%b$uzTMqXPWLA>gChn$QiCE@p-{m`*(_p`yBUEkDkPrs>wXCnKPo>NJ$`;KUi zpJ1RO=Dtm%6xEAla`*{*xBYw2^pzqv6j!Zg2g6cQlE!EBQl~3t%D5F@{UQoxFHBpy zRO=d|T|urA?~hMAg;2z@&Lc6F^}m&dMW6Z~f9Y+4-vK@i%_a?7qO)t-7euZ(iS+9v zqxNgRC?qj`_7cE_@bbcoa6nz7C)`Wu+KPI0^y^w~!QC$Q01>JPT)~GCCsWWZkFkDm>Y7BXODEw|b6o8jxR9$PLebl>gY0Fua5@(y5qc7S4gh2%~Rb^`M9#FV-B8uwg4`k--5U&UO+ zc(sMMp{=O7>VlLD=p`S@Nz<8h(ty4z#43Yvy$YI|3b|dFI#wqspeZdv|CsW(LDs}> zF+k#6>@RuRpT)FNe;MI{F}N-*6$C6jYYkh-Fz8!GqnR6+GBYH@Slu7hX*EQBjPkbm z#s-0YojfDRkX|xw)i_1RG1k`q=nQb&xnAKZ+bUXb4xgR+jNaR5x)mE}Du7sFDhujN zX4Of9=PPqgq>zc|FZy<}uPS?Kx_n!mtqM?<@J_xUv)LwUx=;BXWA#Lw-+et;qmiWX zSHCkz1#N|Dyc&+xgS#HU;FV)w;lM53cZ6b?pL4U&rX44b2gTTyQ2FHnoNamigR>HRy)rY6d)@>VV$ z4oJ^`6hUn#msM|!gi+L#1O)w#|ibfkE&FeI)ti2dx+dWf=eH2 za;Y8t$?!SfZso7En=T)!#_)-LA3t_lvo1bnRxf<-!&VSt^G8SL(lzkXl`I!2*|}1|ge;H!Jnsh>YbdE!vZN!vxvsM(PUMpiszhDwy@w4kzd>B{Z*wuapv@Wm+zqqbWg$v(=ih%RsalkZD4Vrp){Gz-^nOu{l2Dr-Ebk5FU z8&`;8XxkS{h}5`{!fQGwZm31m?K&tr&RRr!FO^MLKvT)^sACz6mK{hL2o8Skht;)s z+_a^4=ZH!5^fodE!)uxvNaMcPli7QPWtY3=YYGyin`=v+A(faeTc>Z_*Q1WLT+GVSO5vO0s2kxD5z=Zl+DkF6ln(+mggM<{8E9d4!q z6z`Vz_7iBX$DdD)hkRC#-p{!8vH%~)IDT-q1CmdnZRUAi?2dARL-K*YOb{oIj z6kGdN>Xcb?j`1qHo7$4dptlF=+Ys8MPf$x1f5SRhopHlT+M`|u-P!_`m|s{rhimuC zHZiKi{mNuih%>2ka5<}_&#{MR=}@nITh*fHbdt!>U_i?k$EZl*5OCNq_9Lw4(`&26 z%auEx&{p-A$NAOF^~cd$3}z7fd<6vA+J^ruzY8R}e)u6KS`Bf9izKZ#F3!tk}Nu~w;B-z<$Ea~fv zv?$MTr)vOXQCw7G_#&Dv4Ag^leGb?3iJ z1<{#HmlAKo=NzA$QHs`Uf@b$&o@+jW#6rpr!XXeUUb;>&F_p<8bn;z?aC!aw6^rEN zoPYJQ{wInQZ&=S2tkb2bJz2QgbcpRlIDwcXu6tc152^RdEP8kXHeM4=6&mCANj$A~ zD%4pBw}wPr<;5GLJS_&UEWHc|d2Avb?H^d!1n${LQT>LxhUKpdH^fh`GUd@;y~M=UK?m{Cj*b)BDsPuJh1VZF z1Qm8N7z~}coQc>JADA~*?#bLA|JJ4)A2vrSaoZ9*x?3#bnFLPPj*TH}=x%&nBuur; zpPkI^h~}V}kEcA2Z!?*hNlgTIosD#vyQQSf(wLZM%X(cJTI`X^t!><%CIDtu!c?WP z5oo0iv^a0#5SI^R^sA%^hT6nt82sl+myNGx@*qil_#c9`qU!f z?+HGxWt{kZ6DwMlts+Yc^Ql{kP37fiV`c~M7Q4b{PW3)cUJnLi+aQE_iP7WdlHX~` zy>Q2d#E=9y3#~NC(S6>{0S5_N1*veN@7(&|jCLyXyL;3uOnraO#hm_`a)o@@6j;A{ z=WHcyI6yP7?0?+G@ksYFpFBnE1|}_WbXDC+f7mNBJvmdpm^3yqe}k`yDvaN+rvPBF z!i7Y!OjO_rA{QW&=TilZNn8hW_D&MoVPg&BQDV~{Da%~fOFQf%haaChzfP8>*nc~; zJ!^UgxVQ*uc5kl1>*`x)6!Ty%Zlm4^ntU>Os2_0vSw~vtBj4&ivB+$)&kgx-o%x^0q&GH%$uy5z6iOl z{9ZrP#=*Flo|#!3d8m&{@wKlXaTeuJnC0C^`$%cJ=h!#-T0b75YE zDMd0Is1}_0358wy+nK+$63kl_-po7S-QKfnsy>})m4EY$j~2^AQ#k7(ZoPJhp+&4v zI!82@=f0!u7-;ttF-D7`*l|nQA|1!;s{pfYIqF3GmR?wDY;Cqrxp|>&z{dbZ3yK||wep0!O$qKo zoC}Ck$Iv~ygz9{v27-{Vy=;K$pL)8vL;Qyd3lbkR-3p!W=29{h{e#a7`pH$QeBy>fs@OnBN0$I2 z@Q1ITpGUrBZKQ%Y52R+(yR|-N(@a;+RYijdN=wP;gq*ScnJFCNA0?;=W< z&@gBys>mQZUU|sPN9%MhW7eQFI-m`5y61hu_>IqEJqu6&{T%=q8Le5Lzt6fzax_~I zuvp(mcOmrE;XbegIaVfSS(83Eom6R9(CA?UU-vAutq%P@UUt8GlrXwEX;} zqynU!v@Wdtx19pichHOF`@X9eA}=LkJh8X{bYpUKV@lx|h~4cgU&ogs+cag~3cmh+ z8e73z)6JC)jqv%7tTziRpP6&^*4?x=i$8kLV*w^QJG#RCJM@tKjUQ3x-r3U1Lrg4X zwqLaasNSykyOND34vS7MXacPT4I)-vm#Xd&3*oj?mFwBYxHQ?uTKggUArRNBeB9SA zdg)CgmSa8vBWU6!|D^z7sS&T2_IcDgQrnSL+}>H+wfP9pX_T<1zfT2nx5*dgq+p;j zh1yN2dn?iEl;q~D9r9!Lg4ZvUWky6b@8J(CYbU!2e5ClHwSdf1uxqvzT|XwqT9wu4TG#|QpN+YPTuQ3wr_j=;XGiXVYfp@0z9-yJKiYwqGwT}d z8yOo&!oSQ+?M@Nf@91u*C4BH|+{oKM=`?3Z46o%qPgRdqPtCsdeDm&GsbT>+C`sxH zp2x^x((v^m9c@_W&4Aj0L*7^=$($*0+G*Qx6EKsS-%x{~GkN-a$2+}0OE0z{# z%36y1v}N7ubmPoy%>mtVHA(tyvnsW6=$Kqr=AyO>D-Qy`SJ`Yt zqnm}Ba{PUtz@a*jmD_yp4Bf^bey|aSvgZ0^%3~g4h#}K*dl$f z-{@q(4jl*?dMYNqjx-1?`5E5DU$;IRG}>q4QoN=p{>rUa;6oHofpt;8i^^{%E>i=x z=TG97JTh>9!f9E>LU4>>3OhAU8cOsPtuqI2vI9G0ABp5KPvdB*cO8#zhOLpn_vg&y znedkne;IWrB!^7iq$0fPcq)HkzykbP(vfphjqxHP4VY`1)^DDMi4nP&;iVl8&ui}X z)QmLqDd(0$!w%g8)LUeImJTnJACY?qW-@)9YEU*(n#Ntx{|ZPa)jSu0*8i!jsHk6c zGDgnA<=6rR#c-x_eeMHFH9k;>bN=l1c}k92N9>m?;(X=8l6%Q0fROM<>ycSG+shFZ zD6a>_N%jpHk*V+tcZ&I0F$YA>oAf7;?pNQEMmooZDf2FSLl7uRS`;d1$s6 zwVi{0Z;DS>x;YsO;m%a|W4!Y&>OHIFb`1`Ri6#{at5cY@g|>(47Of{@+0^6toq z>YS|_4gB%>2VFLU-20mxT*kq1I`bqZ(|&2Z8%aWBuHcTOcg@j0EFVSAfPN)MW5vVH zA>SF?!y`dlsg()EeDI(9tI%1+n!zuh`2@mWCiF%3kNFs%dBO(jcYeak>O@l{-lT>u zI8N0FcZ^FxNAwFN^`hA@LI#U|3QAT+9!($pp>=+na#ou`Je^g(3N_Tw>DOu}yA`l5 z!zhw!WN6o3`kJzS_Zt5dX@RrWVdcV= z=j!v>S%Wzhk|(*{c?S1;cfT*_YsuQhP*g2iPzoiJ?0<4Q?B}!igFgS;Wok4tqhUq% z+Md7wz4R{pQYb%OR4REE1^JN`FZ=3?ytwZ7y&)McrS8_G*DGK976S4} zcZ#8F;gbd4pn1h7E&1gg`$BAVF=Lvx?Bw>HyNhETFxmVkNVSN*3uzsVUi)~NNLLLe zeC$!_DCgVPh?W@s0xuR&A#a=bpw-%u=PByc&-4a$ALii7VKh5r9WC28ttWK8Ou|)L zN2h60EK*u34o();(tw+QgqCG0#-OSLl1exw2>cGr5F~DiEkZu1FAJG~DIfRbIgU{% zJ`Rq$I2DWDgB*gNC4{)xn49m_TID;`Xx2%@rdq==qoD0WDh-jY-Eu!+6sHHiwn6dB z-j)J)0Gz~qIN|9z(ocx#@~fUV+Jjg|1yRRhtCOH0XF%KxYE2inclhA!$n2= zR9JMTG1OiLYm%_HYreGNmq%ZbJf?hTDv5bQvlQ$qTe7k+H;|JA4}kA9Ts&o|ta)1s zwM%LPtI5c561tSpJ?LqeUN&%691m!j^B%}7THG9G${bH8Y^^(3)EBVN8`W^e*#jbs z)QRbn2d(BGk(weGtLa2%LX(sITVkih-v=7m+k>g_f~au(zW(}lC8oQ*s;9wT9p>)H z_XKf3nS#gq1Kk;eJgSLNQvY^>rkra7IrwXZB#Ko$een;qy)5o+xAV z3=HT#o`x%Ds|}z^X|Y*2olXjXXj$XdSdWpOM1FmwH>wPHP`5IZzuhL949!f>Z zP%%mXf`pS>M-VL0tfOxJEvr?W6O$WBK=wR#Vx=2bjZ^Ib!x%naPMoQh_-6tp#-D6L zz)S@GICs$f#{PbRj$Jd^Kpx79^T0RN$2U$HP7N5FKW(rD4S#T5Y>f^_*Dk&9b)~R= zhAo{(7ry+qV678pb57ijq$us{Jj~eYr#YF`2bmZW!1UvfQsdQ-WexcR>2`EtRW$i{ z8G8ux{QXgke6+mqY&{)+O{HzkD@t(pnf~%Z(=dIK{PdS};E>VVf=@DOuBdP3;< zAy*8LutHv`=|?ZddiHv3#%kMzLNc2hJtiln`Rt)vetB?1&QUW5Iot-zrfoCB&;tv| z;6`{kEdy2T0K+;NzA&VSmA_ONV!To_5T$kdhEc;^l7(8=YzyYa@=pKDH13p&!;HNu zRlbxE3^yJieWq6^q)nY#seZpzs7CejDjiqKTs!A^w|FNza50dGr}@j`VCB3NAUx8Nu)t4gYxOCu;eoe!%X7=vwhreXNGrxWn>c$VT3m8%|H&{U_Z2f zjZoF5v_!BQHbOQ+AyKJH7PXNzmG&yft>lBs@W6KRw+;<~CodrnYm7<9sU>x0zwmg* z9jD5N}7q_x3I=wugM&4{Y7btQambvB11i zfd=0NPMkAKxfc})=S>v(yQXVBx-33w;BU-?f^wc1U>ZS!Xrd=Mtw@SW9!!wo7Zrhx zFcJ2cgd%EhT=DseTy>bSiGfF8nzV_~OCUrpi-AnLtB72OGO&yc4AXi2o1FELQ!8IpH zD)UG;?TJb;-Z}!W8+)u5V-fKUK)U0TRn3G;Lgl<8Lr_gPb-6kdZYNw5HHmkgpl%># zDzuQi+?YOuS^@sy&#Bq;I5z7)`Z=P-QtDxmF|xV5?$06KzXwx^zLUvYn|rs1E;C2 zN6in{Uizv1vIOO}jx4bgRf6JHKL_HtW=WK4$D_zlwi`k*`H*&{3qCe{-e0G zmSh(0)>7M$akm25F)f`UU@^g;@CTHhK1I~y2traK9jwrA>xc?Wm{4*I?+!nFt0l)t~GIi&$j--0#B0ioQ`nxE3ke!267XoKMh|f7pTS{UK zx|$?bSb1km>*?G_@NYWkwC2(2ET`cKs0cMgrU~wwGQ2Kk0FM4pen_Xz&qIP+O9j}> zvt`Ys!uqlB-J&u6S+I$FG(2Um&%hgqz?Nh!@_xGKM(~R@Oe=GV8Z)S~b*= ziP^hGTi;Awd5Vd6r`j>(GOSxyVR9#ZNJg!6yPVZ*ZbWa7e78WMjA;Xu=tG~p0ZCU- zVvnwJCn)1|g7|mCTopGOn6BDB*T+xk3 z#zH^%NuZgrRy{PBBqdY@i#;9*e9cjhgQ0E66Ix~|gX8X2S4j!-SGhUScY-hIKN_<41bP1fY`eS_e+* zQ)a`Wt!^bed02c$j89YWfu&2n(Q0q?jb=8M0naPO4|a{l8W6FBQqbJbW~=%J==$72 ziYvItNOig4syILR>C+b)X$QoH0lzDDBfWb`oxOTkTMN-)Hv-+v1zyt#&Ek)lbt{8` znSlv|Z2nY*CFs4ht7_S2x%;YUbfSCFESM1E^V3 zvk1zjePliLr?5JcRTN zTb|Li@T^+}8Lh%fko8r%AICnA6Tzk0$+U=%O*G6&*9c_zI)sCqwspZ5@KzGiiDl3s zg_K}mX)=aNky#QG53uAD#SL*|rP9y$w7gi!3tZ_#2~&_i4SS_VpDH~Te*C43mM^H2 z;SS(r0!56tHGU|TXr(e~M6<<{sE9Z3`R>zmQh_8XOptq|yNcx#JNawM7{eH~`Pw+m z?4W24Do!qk;4<8fXLWH4>V6O?L*eE7@yTHK5lSweB~I!1~!~ywOwX4Ehzh*j|v?vD8RUcs&n>QtDEZI zyrdWI76w%|I!{B+lro=bcQc$tla<~;o88l$nIa5{OAm(w$+t^5#Vuc3D860TI|>j}d~Ilm(xf7xGd?4*`t}q(-!j5e z8g>}Xl)+4CR2kXTh#A%4UX5`K?3;~nc={rafwWs6`nhZ6$GoR8G==dQbLZ2Z&qtqP zyv{oy>KacSHhLT9%3)ywF>B0!qPklos|&bQ+FotEIDc8iROd?Zfl_hR?g3IuVCzR! zwMSFkdvEgzd%qr%ZT$*B8W;UbexvT+7MZ+eH~V>tZuOSfA2Ei%&qTV(;f7FBlRm}?-pS&QVIw=o3jLkc8D*~*_5=G4;7F#Gg{Wm)3x808 zFT5J`BA%!cQp}*IQeA4+rN$|iL(Pn>_5f^T5Hmy;i%Gx;p0Uo8pC`alPhQ@9$biyO z!X^uzGM*P%rPdgeJ2r9?C+}owWCw}4D{REKP!fr{1a#+BLduNX!^g{MVkYnZ;}RCx z*&o|9!>Td}EM69PNt1;n5-%d4eCW0Z21qA=9X$aj_iy9-{bX3gdP1WnZ*-z*uT4TA z#zCw4J~-SunPEZfmqxbH`BQ4!PdaWdSYO@&tg4V8)Ge#_gBXlnk&T;bUE?1PHJ%Gd zb@fi6Xz1Lif_ssN7FGV!1n)8)|L<`o>R-38XtR5hhHRSxSHghJZDw&taR%KK1=Dwv7`kvN;EA$P(*O}TI#10JxENS` z;RKsLpC92V5)jRZ=~>NXa|+RXmScXQfp~)b{<%G8*sGq<571XEDNJ?<9M^2{!b~|~ zwmS*yW#yYSWxEiI+fw40X&wk~wQIL^Q<4F>ahG-MSnlJl46vpZ+c1;9os#uC6>?hF zQ4)*VZ?2{~TZy2#JVowXP9S3b1T2P4U5*d5MBs8P2S0PI9P}`uTUNwa1(n=~P;t}H zMT@aTB$^O8K}`gd1)uY%x=)$n!pRMAbE+S7aV1>y88`DKbNa3|qX_ zYK)$kfRGy|pTk@R=#GDXrdcFO;8gm8Cq#gd)X{t(*NsE0Z3$p6;=n`@rtuGYX7w@1 zdNP+h;913It;EsZK|u8=lC#0@Yl6dLf%lXmB$vxlv z;)P5c;cxoy0Dh0{D<))Jd)nzrPB>DcMevXW2JtohG#NYLF~=RRUs=mw45{R+c3^(2 zk;56{e8wD3&@O<$!M}gq@h%4=8!SeKsDW$YZ6f4H7<7zvwdt599wN$NO0-#7LbpeG zsva%`m}$pg?5xBS@SAU192gxq#XsbbV_5t_fnaQeUJwvi)Qz152)y5v#y-^}*CPO0 zBPJ&iL3jkk4>_L)Df5$QDLkd3$|oZu)W#;8o5o>T8Fmi!@5Q0OR@-;sDFbi>{!pTb zrATn$e0GK@fL((k-9^L!u%E~4ks_1HKyq0F;SW|6$O0V@MiUR!2x19v9|Ic5=MW${ z9yyFoR)vR5&`>#VX5F{;tj}Uq_dBq0fw2>hFhhZjfLGYT;P4=v?p~6!$66{Zp}0jf zpNSk0lX7e?a9k@aA1ot`PznSm|GE#!DJklsY?L3SUofs&?((p5Mo4u}!f zl~pTVM9KC^kwp#z+ZD`-k3EKgS%f9@aOVY%5wVVm9u}{@3F}c_if~z{~jow^)agwjL&&Mp!DK21`()`i+Ie}2kiRO@Xj}mXf+tP zoMp&jIFbD(OAWh`jo<@I1y~Oo5J;x>z=7cDBPTULR`tosuOYeaZbNNML{Z4y?EeD$ CIGxe} literal 0 HcmV?d00001 From 898c68896ab5058b729718789370a4408fc239cc Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 07:25:46 +0800 Subject: [PATCH 033/103] a --- .../screenshots/webgl_postprocessing_ssr.jpg | Bin 17580 -> 28234 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/screenshots/webgl_postprocessing_ssr.jpg b/examples/screenshots/webgl_postprocessing_ssr.jpg index 450a125de016ee0cd2e4e1bfd24f10d43ca16fc0..10a7fa24b05f24192aa60c49a5e88c146761a438 100644 GIT binary patch literal 28234 zcmdqIcU)87x91&-pa{|hsVY@^??phmfE4LP1f=)g5&;3Jk*>5Tz4zWC9YlKX5Tw^o z0|{Z`_cyP(Gq1UGXP)~!|2%W@%1O@7-Ye^~&pGexwf4^4+}#?0L`_Lm34nzK0AOJr zfV)M&Cjd6q-|g=n`|pN}^LKv_7Z(Q??;alBKTrGz_wn!_;N#)le|Y}^!QTz@j_@G? z;opOQHN(D#gL97n9}oYZkN+R-?tTJD?*neIzTjYy0Up7G1!k!xGxKX<1P2ub*HpGm&D zlTv5=gjw*tN9Y5B$5hl$XjoX;*k5o635$q|iAyNFQdCk_QB~8`d#i6?Xk=_KhuHnp?WMdwTo& z2L^vlOioSD%+Ad(tiv|`Y;JAu?C!x&&(1F{uMpQaSOA=V$-(UZCp{S9SlEC29RIH# zENoxQ6NeP{-ZOqYGC6I0OLy|;0wMP)-{&-*r)3k5}}18GnKaE3)IidB~r-?^ZT`O!lW>~=96k{>@LcLxY<_mg+!M3Y13hEzc3 zO7RfG^M^*&>s@J&zhUd{SV<+*8$`E3@b! zna!k$g&$TkaMx@_zxXADLaTZ#OXf@Mjl*ZsG$(pIpwYvgZ21#Ym51hZm9F+`d0w+? z#T5<9x-E+u5_=C}S_r1mp6?JxIM)gt(u?NQP*;*t`yX+UwXID$dh5CY4L5*a&798oBQP=^6UKp!mQmgH=6D zuMno)0dQv!QFnmn_=mb{`=ENb>m7jd?M&Kc%Y_yqb5XI@XSJPe@a&|!zC!@!#E4um z_#D@GyTq|`a|fuMDh~9C+brx}0ac#{takNG`l8RkLstoL?dI904qqlDH>8sdl`Jh)uQV)n(bfcXB{kP3MDtY+LkStEhwAQ zesZq?OWO=FoYqmTa$5YU2oT;rI78B)f4TL$7a^>A(9%E%w=&T)r9G(*+yYDbI?rq7(dYVp7+*ROe{58? zR3bA4TLm>rnoKK}2Z6Z|ahQ8V5Z)i6y@rrP(%G3m@Up0_sNX2EoxPy8y{}h=R8z2~ zQdB z&k@{;^8B>)C?n!xcp|KssrNoJpEXh6AUPxH!nxz%+DYko1y5V)Ti@iYl_&>PO5!yW zO)H`N{}LkqE?NGA!YjzU6_fD*pPI2`unk&c~WUq z+4rRRmE&F;bw5Gg4!z|$+-v7O0i!Zm$AC^fM1WA9}a;HdU$dp?UHWBz< z`UguG=-*Cw1@0pYi3818;M`p2%FJR((s7lalcBxGcYs}k$st#!k_pgS*&U!>=rN3u z!VX02JwyKZ%mvM8XjCnae*}e@r*6379`(VS)?2L7&1wFOr<}}XYRK}I=@nOkRwXJo zfo3xF$8CNYjE;KY;-Dq5{>>xyI{@U{j2-mEfS+d-p#ieOT=#=D??AAO+4?|kI6TF* zZfQAaiH`5*lRu)AgSsCD1AK2f+}|#Ph8FbLY&Q>f$0u8S7nR~ayR*{Y0mvT^BYku& zZuAOFnr_=c@9qG!N|T7=O9?n-9n8m#dFH(RotjB$YLZq1`}~Ms&~{P3KvQ6k6lcAZ z4?|8P3R$kU%3@qTJ0fy$qdV*uP;+&1riFR~LC@0ynYCcY2xj8A#_O3C&IzfsB~ZQ8 zBPZ0vJQ6a0lYEUs7deM#;Bw@%P!4mU+UT0dx&v&lFr}|_%!G6Ln`D$9<`21*JC~@* z!U|nmQ}dv-{uTumaUk1O1Z(?MxUh!rPf&eo3iFM3SrT`7?p~EDQ;LkKBRx7ZPQ=ja zD)2MV8Jor9k&hIA`XzU|YTF_2Xh8byejtZ(Y8;=&J9#$%{cTPvH`K#ETM`j zcNI?G{RgAD|KwRaADw?_Vn(&G6s||{jj47@{qZA23Mkl8#dqERvuDuuHbXgX@tB^lFE2HIv*0N!A|ya!NsvF~w_s0tnM+%?WKIulw9U%YCR?`F(rF-}@gKNd>Gr=>m9No>5bxF%_H zC8tOrsM@1`H(ik4BEI=V-n2&ly)N_r`@4b&5^4U_l>pPnitwiyLyslO$R(*bM7W|2 z$s|d?1V@$e>)kfcxE-aVi0riHXJT80KrbODN)U?M+HM)~6S_ufB+Eq>id1-X^-M?Q zj}5p%>gyHXezRO39w=JMqs!xcm0?{6`v}qEwXwtT=(l-)krqhX3D5H>M{U;+*|$g8 z5SGdx*UvD-?l__E@4f>dIEZ_tr8k=S_NXq6v&ybWlF7=4!`sT+iXI{>-9WT(n7EGHow^G+HF_*7! zo9sG~g4sj23GVi0w+^ppRj16L5LtdV;>y!E7K4DP4j*A1jchx;Ai_FG~t<-Z&!_-`!? z5CITp9@-(dFR|}t_Rg{^H|Z1a0E6uW+`tYRXyU4Thhxq-qv)^K93TBV#W!%uy^x~O z1zCot`}tSm*&I(apLIVF6`5?WQ(Mk%r$Q0Me?%O2r%5B#M2@W z%l5h=Uu|yve-$XORup zmKv=I-@tNVh%fccfVtJ>RqZB^ERW|x$E!8oS}~E88a#N_RhKNo#j5h zX`;(Jelkqsn9bj>G*>TfV-6b*#54t`$IT>@JiF05U6ZcZLn~!Ze%2?-$NO=6__)zkzhxicPY!-k-W;O|myNLWj`GR) z6lL0sAFoQyuy)qRA(OM|KUQ?H>l2M$ywnu(Bowgc^fZ#}NMAPcUp3=$Kv=*=ichu< z_OdDB_xje2XjasX!sPceQ9p0IP{AeU5BIq_%2gc$%Yo(vW1}{yFVr7A&@>e%I92WUS7}#K{Vo9(FB;N7uQm2e!tToTj-?llZEz) z@I-K-=Ipyy!6k31lx@Vh_~BY!_Mu^7jFlBONZ9LVwHFV#ey*zbufKb}bM8|I$wI93$wyH=IlZ2L|pc z9hO&8GJC(Rlrefui5_DO{kBV5WNHBwO%uV zy2QXX(LdOhD?9ctq;=7cS`n7aH_Dx$=$7D2+V9OXbs5)q#}Y61?S%k@?{cnvpA6zY z!NVHt--aq4^k2L^C)LaH!G~sY^Har;%i

JC6a-O|y;-!3LTnWVFDQ`A%{O*XyD{e-s%O6(W8 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 literal 17580 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 CIGxe} From fbf6f8e982005545e1e27a128aa872ec1a5f2cb6 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 08:23:52 +0800 Subject: [PATCH 034/103] gui --- examples/jsm/postprocessing/SSRPass.js | 25 ++++++++++++++++++------- examples/jsm/shaders/SSRShader.js | 26 ++++++++++++-------------- examples/webgl_postprocessing_ssr.html | 4 +++- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 68884029c95663..f0aac58b0596f3 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -42,8 +42,8 @@ var SSRPass = function(scene, camera, width, height) { this.camera = camera; this.scene = scene; - // this.opacity = .5; - this.output = 0; + this.opacity = .5; + this.output = 6; this.maxDistance = 900; this.surfDist = 1. @@ -202,14 +202,14 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render SSR - // this.ssrMaterial.uniforms['opacity'].value = this.opacity; + this.ssrMaterial.uniforms['opacity'].value = this.opacity; this.ssrMaterial.uniforms['maxDistance'].value = this.maxDistance; this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; this.renderPass(renderer, this.ssrMaterial, this.ssrRenderTarget); // render blur - // this.blurMaterial.uniforms['opacity'].value = this.opacity; + this.blurMaterial.uniforms['opacity'].value = this.opacity; this.renderPass(renderer, this.blurMaterial, this.blurRenderTarget); // output result to screen @@ -260,10 +260,20 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.copyMaterial.blending = NoBlending; this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); - // this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget.texture; this.copyMaterial.uniforms['tDiffuse'].value = this.ssrRenderTarget.texture; this.copyMaterial.blending = AdditiveBlending; this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); + break; + + case SSRPass.OUTPUT.DefaultBlur: + + this.copyMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); + + this.copyMaterial.uniforms['tDiffuse'].value = this.blurRenderTarget.texture; + this.copyMaterial.blending = AdditiveBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); break; @@ -357,11 +367,12 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { SSRPass.OUTPUT = { 'Default': 0, - 'SSR': 1, + 'OrthographicSSR': 1, 'Blur': 2, 'Beauty': 3, 'Depth': 4, - 'Normal': 5 + 'Normal': 5, + 'DefaultBlur': 6 }; export { SSRPass }; diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 3dc149ccd88907..725fa399416fa6 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -23,7 +23,7 @@ var SSRShader = { "resolution": { value: new Vector2() }, "cameraProjectionMatrix": { value: new Matrix4() }, "cameraInverseProjectionMatrix": { value: new Matrix4() }, - // "opacity": { value: .5 }, + "opacity": { value: .5 }, "maxDistance": { value: 0.05 }, "cameraRange": { value: 0 }, "surfDist": { value: 0 }, @@ -52,9 +52,9 @@ var SSRShader = { uniform sampler2D tDiffuse; uniform float cameraRange; uniform vec2 resolution; + uniform float opacity; uniform float cameraNear; uniform float cameraFar; - // uniform float opacity; uniform float maxDistance; uniform float surfDist; uniform mat4 cameraProjectionMatrix; @@ -135,13 +135,10 @@ var SSRShader = { float ySpan=yLen/totalStep; for(float i=0.;i=totalStep) break; - float x=d0.x+i*xSpan; - float y=d0.y+i*ySpan; - if(x<0.||x>resolution.x) break; - if(y<0.||y>resolution.y) break; - float u=x/resolution.x; - float v=y/resolution.y; - vec2 uv=vec2(u,v); + vec2 xy=vec2(d0.x+i*xSpan,d0.y+i*ySpan); + if(xy.x<0.||xy.x>resolution.x) break; + if(xy.y<0.||xy.y>resolution.y) break; + vec2 uv=xy/resolution; float d = getDepth(uv); float vZ = getViewZ( d ); @@ -152,7 +149,7 @@ var SSRShader = { if(dot(viewReflectDir,vN)>=0.) continue; vec4 reflectColor=texture2D(tDiffuse,uv); gl_FragColor=reflectColor; - gl_FragColor.a=.5; + gl_FragColor.a=opacity; break; } } @@ -231,7 +228,8 @@ var SSRBlurShader = { uniforms: { "tDiffuse": { value: null }, - "resolution": { value: new Vector2() } + "resolution": { value: new Vector2() }, + "opacity": { value: .5 }, }, @@ -259,20 +257,20 @@ var SSRBlurShader = { "void main() {", " vec2 texelSize = ( 1.0 / resolution );", - " vec3 result = vec3(0);", + " vec4 result = vec4(0);", " for ( int i = - 2; i <= 2; i ++ ) {", " for ( int j = - 2; j <= 2; j ++ ) {", " vec2 offset = ( vec2( float( i ), float( j ) ) ) * texelSize;", - " result += texture2D( tDiffuse, vUv + offset ).xyz;", + " result += texture2D( tDiffuse, vUv + offset );", " }", " }", - " gl_FragColor = vec4( result / ( 5.0 * 5.0 ) , 1.0 );", + " gl_FragColor = vec4( result / ( 5.0 * 5.0 ) );", "}" diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 4468f8457469f6..b64d23936aa2b1 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -279,7 +279,7 @@ ssrPass.surfDist=4.2 gui.add(ssrPass, 'output', { 'Default': SSRPass.OUTPUT.Default, - // 'DefaultBlur': SSRPass.OUTPUT.DefaultBlur, + 'DefaultBlur': SSRPass.OUTPUT.DefaultBlur, 'SSR Only': SSRPass.OUTPUT.SSR, 'SSR Only + Blur': SSRPass.OUTPUT.Blur, 'Beauty': SSRPass.OUTPUT.Beauty, @@ -290,6 +290,8 @@ ssrPass.output = parseInt(value); }); + gui.add(params, 'enableSSR').name( 'Enable SSR' ); + gui.add(ssrPass, 'opacity').min(0).max(1); gui.add(ssrPass, 'maxDistance').min(0).max(1000); gui.add(ssrPass, 'surfDist').min(0).max(10).step(.1); From e86f5c9ed769a876b0d9a7dc37ca07ac5ee24304 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 22:09:32 +0800 Subject: [PATCH 035/103] a --- examples/jsm/postprocessing/SSRPass.js | 4 ++-- examples/jsm/shaders/SSRShader.js | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index f0aac58b0596f3..31ec84c8565a18 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -367,12 +367,12 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { SSRPass.OUTPUT = { 'Default': 0, - 'OrthographicSSR': 1, + 'DefaultBlur': 6, + 'SSR': 1, 'Blur': 2, 'Beauty': 3, 'Depth': 4, 'Normal': 5, - 'DefaultBlur': 6 }; export { SSRPass }; diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 725fa399416fa6..7c3434d97247e8 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -90,7 +90,6 @@ var SSRShader = { } vec2 viewPositionToXY(vec3 viewPosition){ vec2 xy; - // d1=getViewPositionReverse(viewPosition); float clipW = cameraProjectionMatrix[2][3] * viewPosition.z + cameraProjectionMatrix[3][3]; xy=(cameraProjectionMatrix*vec4(viewPosition,1)).xy; xy/=clipW; @@ -101,6 +100,7 @@ var SSRShader = { } float pointToLineDistance(vec3 point, vec3 lineStart, vec3 lineEnd) { //modified from https://math.stackexchange.com/questions/1905533/find-perpendicular-distance-from-point-to-line-in-3d answer: Marco13 + ///todo: This function considers the length of the line? Isn't it considered infinite? vec3 d = (lineEnd - lineStart) / length(lineEnd-lineStart); vec3 v = point - lineStart; float t = dot(v,d); @@ -118,10 +118,10 @@ var SSRShader = { vec3 viewNormal=getViewNormal( vUv );; vec3 viewReflectDir=reflect(normalize(viewPosition),viewNormal); vec3 d1viewPosition=viewPosition+viewReflectDir*maxDistance; - if(d1viewPosition.z>0.){ - float scale=viewPosition.z/(viewPosition.z+-d1viewPosition.z); - d1viewPosition.xy*=scale; - d1viewPosition.z=0.; + if(d1viewPosition.z>-cameraNear){ + float ratio=(viewPosition.z+cameraNear)/(viewPosition.z-d1viewPosition.z); + d1viewPosition.xy*=ratio; + d1viewPosition.z=-cameraNear; } // gl_FragColor=vec4(d1viewPosition/100.,1);return; d1=viewPositionToXY(d1viewPosition); @@ -143,7 +143,7 @@ var SSRShader = { float d = getDepth(uv); float vZ = getViewZ( d ); vec3 vP=getViewPosition( uv, d, vZ ); - float away=pointToLineDistance(vP,viewPosition,viewPosition+viewReflectDir*maxDistance); + float away=pointToLineDistance(vP,viewPosition,d1viewPosition); if(away=0.) continue; From f005e085e17448c31ce3c9bbd48f7431aa9d7d2c Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 23 Aug 2020 22:32:00 +0800 Subject: [PATCH 036/103] new pointToLineDistance function --- examples/jsm/shaders/SSRShader.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 7c3434d97247e8..478f3cfd71d03d 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -98,14 +98,10 @@ var SSRShader = { xy*=resolution; return xy; } - float pointToLineDistance(vec3 point, vec3 lineStart, vec3 lineEnd) { - //modified from https://math.stackexchange.com/questions/1905533/find-perpendicular-distance-from-point-to-line-in-3d answer: Marco13 - ///todo: This function considers the length of the line? Isn't it considered infinite? - vec3 d = (lineEnd - lineStart) / length(lineEnd-lineStart); - vec3 v = point - lineStart; - float t = dot(v,d); - vec3 p = lineStart + t * d; - return length(p-point); + float pointToLineDistance(vec3 x0, vec3 x1, vec3 x2) { + //x0: point, x1: linePointA, x2: linePointB + //https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html + return length(cross(x0-x1,x0-x2))/length(x2-x1); } void main(){ From 0bb587ee01b491d097a6c5dc6dd3f229e39c7ac6 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 24 Aug 2020 00:00:08 +0800 Subject: [PATCH 037/103] #define MAX_STEP & onresize replace MAX_STEP --- examples/jsm/postprocessing/SSRPass.js | 3 +++ examples/jsm/shaders/SSRShader.js | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 31ec84c8565a18..04a69b38f46dc0 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -91,6 +91,7 @@ var SSRPass = function(scene, camera, width, height) { } + SSRShader.fragmentShader = SSRShader.fragmentShader.replace(/#define MAX_STEP .*/, `#define MAX_STEP ${Math.sqrt(window.innerWidth * window.innerWidth + window.innerHeight * window.innerHeight)}`) this.ssrMaterial = new ShaderMaterial({ defines: Object.assign({}, SSRShader.defines), uniforms: UniformsUtils.clone(SSRShader.uniforms), @@ -350,6 +351,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.width = width; this.height = height; + this.ssrMaterial.fragmentShader = this.ssrMaterial.fragmentShader = SSRShader.fragmentShader.replace(/#define MAX_STEP .*/, `#define MAX_STEP ${Math.sqrt(width * width + height * height)}`) + this.ssrMaterial.needsUpdate = true this.beautyRenderTarget.setSize(width, height); this.ssrRenderTarget.setSize(width, height); this.normalRenderTarget.setSize(width, height); diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 478f3cfd71d03d..cebbf7909fbe19 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -45,7 +45,7 @@ var SSRShader = { ].join("\n"), fragmentShader: ` - #define MAX_STEP ${innerWidth * Math.sqrt(2)} + #define MAX_STEP TO_BE_REPLACE varying vec2 vUv; uniform sampler2D tDepth; uniform sampler2D tNormal; @@ -108,17 +108,24 @@ var SSRShader = { float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); + // gl_FragColor=vec4(-viewPosition.z/1000.,0,0,1);return; vec2 d0=gl_FragCoord.xy; vec2 d1; vec3 viewNormal=getViewNormal( vUv );; vec3 viewReflectDir=reflect(normalize(viewPosition),viewNormal); vec3 d1viewPosition=viewPosition+viewReflectDir*maxDistance; + // if(d1viewPosition.z>=.0) return; if(d1viewPosition.z>-cameraNear){ float ratio=(viewPosition.z+cameraNear)/(viewPosition.z-d1viewPosition.z); d1viewPosition.xy*=ratio; d1viewPosition.z=-cameraNear; } + // if(d1viewPosition.z>0.){ + // float ratio=viewPosition.z/(viewPosition.z-d1viewPosition.z); + // d1viewPosition.xy*=ratio; + // d1viewPosition.z=0.; + // } // gl_FragColor=vec4(d1viewPosition/100.,1);return; d1=viewPositionToXY(d1viewPosition); // gl_FragColor=vec4(d1/resolution,0,1);return; From 27b2d88af9807b775dc11f600f6d42bab17e930b Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 24 Aug 2020 01:07:24 +0800 Subject: [PATCH 038/103] bug fix --- examples/jsm/shaders/SSRShader.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index cebbf7909fbe19..ace505a70c2656 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -108,6 +108,7 @@ var SSRShader = { float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); + // gl_FragColor=vec4(viewPosition/100.*vec3(1,1,-1),1);return; // gl_FragColor=vec4(-viewPosition.z/1000.,0,0,1);return; vec2 d0=gl_FragCoord.xy; vec2 d1; @@ -117,9 +118,17 @@ var SSRShader = { vec3 d1viewPosition=viewPosition+viewReflectDir*maxDistance; // if(d1viewPosition.z>=.0) return; if(d1viewPosition.z>-cameraNear){ + vec2 tempXY=viewPosition.xy; + viewPosition.x=0.; + viewPosition.y=0.; + d1viewPosition.xy-=tempXY; + float ratio=(viewPosition.z+cameraNear)/(viewPosition.z-d1viewPosition.z); d1viewPosition.xy*=ratio; d1viewPosition.z=-cameraNear; + + viewPosition.xy+=tempXY; + d1viewPosition.xy+=tempXY; } // if(d1viewPosition.z>0.){ // float ratio=viewPosition.z/(viewPosition.z-d1viewPosition.z); From 7b6a6d0f8b880f40c7ed78fc4121b79c89ddd7fc Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 24 Aug 2020 01:13:53 +0800 Subject: [PATCH 039/103] a --- examples/jsm/shaders/SSRShader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index ace505a70c2656..9b8f6ac8133845 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -127,7 +127,7 @@ var SSRShader = { d1viewPosition.xy*=ratio; d1viewPosition.z=-cameraNear; - viewPosition.xy+=tempXY; + viewPosition.xy=tempXY; d1viewPosition.xy+=tempXY; } // if(d1viewPosition.z>0.){ From a5b89eee9be3f3f58d3709be631c5ce34b14ba9d Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 25 Aug 2020 02:39:02 +0800 Subject: [PATCH 040/103] mobile bug fix --- examples/jsm/shaders/SSRShader.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 9b8f6ac8133845..97e61c7afbcb6a 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -45,6 +45,8 @@ var SSRShader = { ].join("\n"), fragmentShader: ` + precision highp float; + precision highp sampler2D; #define MAX_STEP TO_BE_REPLACE varying vec2 vUv; uniform sampler2D tDepth; From 0b3054b177f5bf28c8316ce708094f2977c1c2a9 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 25 Aug 2020 19:18:56 +0800 Subject: [PATCH 041/103] surfDist affected by clipW --- examples/jsm/shaders/SSRShader.js | 13 +++++++++---- examples/webgl_postprocessing_ssr.html | 9 ++++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 97e61c7afbcb6a..55fff5d829159c 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -81,12 +81,15 @@ var SSRShader = { return orthographicDepthToViewZ( depth, cameraNear, cameraFar ); #endif } - vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) { - float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3]; + vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ, const in float clipW ) { vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 ); clipPosition *= clipW; // unprojection. return ( cameraInverseProjectionMatrix * clipPosition ).xyz; } + vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) { + float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3]; + return getViewPosition(screenPosition, depth, viewZ, clipW); + } vec3 getViewNormal( const in vec2 screenPosition ) { return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz ); } @@ -156,9 +159,11 @@ var SSRShader = { float d = getDepth(uv); float vZ = getViewZ( d ); - vec3 vP=getViewPosition( uv, d, vZ ); + float clipW = cameraProjectionMatrix[2][3] * vZ + cameraProjectionMatrix[3][3]; + vec3 vP=getViewPosition( uv, d, vZ, clipW ); float away=pointToLineDistance(vP,viewPosition,d1viewPosition); - if(away=0.) continue; vec4 reflectColor=texture2D(tDiffuse,uv); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index b64d23936aa2b1..01765e920ae55b 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -276,7 +276,9 @@ // GUI gui = new GUI( { width: 400 } ); - ssrPass.surfDist=4.2 + // ssrPass.surfDist=4.2 + ssrPass.surfDist=.007 + // ssrPass.output=SSRPass.OUTPUT.SSR gui.add(ssrPass, 'output', { 'Default': SSRPass.OUTPUT.Default, 'DefaultBlur': SSRPass.OUTPUT.DefaultBlur, @@ -292,8 +294,9 @@ }); gui.add(params, 'enableSSR').name( 'Enable SSR' ); gui.add(ssrPass, 'opacity').min(0).max(1); - gui.add(ssrPass, 'maxDistance').min(0).max(1000); - gui.add(ssrPass, 'surfDist').min(0).max(10).step(.1); + gui.add(ssrPass, 'maxDistance').min(0).max(2000); + // gui.add(ssrPass, 'surfDist').min(0).max(10).step(.1); + gui.add(ssrPass, 'surfDist').min(0).max(.02).step(.0001); } From 600fc0f19afebb9b7e14145ada7ab105efca2df3 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Wed, 26 Aug 2020 13:42:16 +0800 Subject: [PATCH 042/103] performance improvement --- examples/jsm/shaders/SSRShader.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 55fff5d829159c..0314f420d40868 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -112,6 +112,8 @@ var SSRShader = { float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); + // gl_FragColor=vec4(vec3(-viewZ/cameraFar),1);return; + if(-viewZ>=cameraFar) return; vec3 viewPosition = getViewPosition( vUv, depth, viewZ ); // gl_FragColor=vec4(viewPosition/100.*vec3(1,1,-1),1);return; // gl_FragColor=vec4(-viewPosition.z/1000.,0,0,1);return; From 91da469c5872efae52435a9b66144347533f53db Mon Sep 17 00:00:00 2001 From: gonnavis Date: Wed, 26 Aug 2020 16:25:05 +0800 Subject: [PATCH 043/103] a --- examples/jsm/shaders/SSRShader.js | 2 +- examples/webgl_postprocessing_ssr.html | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 0314f420d40868..80406094e4e30d 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -182,7 +182,7 @@ var SSRShader = { var SSRDepthShader = { defines: { - "PERSPECTIVE_CAMERA": 0 + "PERSPECTIVE_CAMERA": 1 }, uniforms: { diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 01765e920ae55b..5166ccb7b1e9b4 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -27,19 +27,20 @@ import Stats from './jsm/libs/stats.module.js'; - import { GUI } from './jsm/libs/dat.gui.module.js'; - import { OrbitControls } from './jsm/controls/OrbitControls.js' import { GLTFLoader } from './jsm/loaders/GLTFLoader.js'; - + + import { OrbitControls } from './jsm/controls/OrbitControls.js' + + import { GUI } from './jsm/libs/dat.gui.module.js'; import { EffectComposer } from './jsm/postprocessing/EffectComposer.js'; import { SSRPass } from './jsm/postprocessing/SSRPass.js'; - // var initialFrustumSize = 1200; var params = { enableSSR: true, } var composer var ssrPass + var gui var container, stats; @@ -55,7 +56,7 @@ var clock = new THREE.Clock(); - var gui, shadowCameraHelper, shadowConfig = { + var shadowCameraHelper, shadowConfig = { shadowCameraVisible: false, shadowCameraNear: 750, @@ -339,7 +340,6 @@ } if(params.enableSSR){ - // ssrPass.setFrustumSize(initialFrustumSize/camera.zoom) composer.render(); }else{ renderer.render(scene,camera) From 58bd9ce28a1626bd8aba7c943e6bfc4e34003d24 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 30 Aug 2020 19:34:09 +0800 Subject: [PATCH 044/103] SSRPassSelective --- examples/webgl_postprocessing_ssr.html | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 5166ccb7b1e9b4..2830d7f2b2f6ca 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -88,6 +88,7 @@ // SCENE scene = new THREE.Scene(); + window.scene=scene scene.fog = new THREE.Fog( 0, 1000, 10000 ); // TEXTURES From 1c5854c9b43a592828367d1a3f16cf7d4bcbf47c Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 30 Aug 2020 21:39:44 +0800 Subject: [PATCH 045/103] a --- examples/jsm/postprocessing/SSRPass.js | 71 ++++++++++++++++++++++++++ examples/jsm/shaders/SSRShader.js | 2 + examples/webgl_postprocessing_ssr.html | 3 +- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 04a69b38f46dc0..172d6713c4567f 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -11,6 +11,7 @@ import { LinearFilter, MathUtils, MeshNormalMaterial, + MeshBasicMaterial, NearestFilter, NoBlending, RGBAFormat, @@ -71,6 +72,14 @@ var SSRPass = function(scene, camera, width, height) { format: RGBAFormat }); + // metalness render target + + this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + format: RGBAFormat + }); + // ssr render target @@ -102,6 +111,7 @@ var SSRPass = function(scene, camera, width, height) { this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; + this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture; this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far; @@ -115,6 +125,18 @@ var SSRPass = function(scene, camera, width, height) { this.normalMaterial = new MeshNormalMaterial(); this.normalMaterial.blending = NoBlending; + // metalnessOn material + + this.metalnessOnMaterial = new MeshBasicMaterial({ + color:'white' + }); + + // metalnessOff material + + this.metalnessOffMaterial = new MeshBasicMaterial({ + color: 'black' + }); + // blur material @@ -173,12 +195,15 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.beautyRenderTarget.dispose(); this.normalRenderTarget.dispose(); + this.metalnessRenderTarget.dispose(); this.ssrRenderTarget.dispose(); this.blurRenderTarget.dispose(); // dispose materials this.normalMaterial.dispose(); + this.metalnessOnMaterial.dispose(); + this.metalnessOffMaterial.dispose(); this.blurMaterial.dispose(); this.copyMaterial.dispose(); this.depthRenderMaterial.dispose(); @@ -201,6 +226,10 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.renderOverride(renderer, this.normalMaterial, this.normalRenderTarget, 0, 0); + // render metalnesses + + this.renderOverride(renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0); + // render SSR this.ssrMaterial.uniforms['opacity'].value = this.opacity; @@ -255,6 +284,14 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { break; + case SSRPass.OUTPUT.Metalness: + + this.copyMaterial.uniforms['tDiffuse'].value = this.metalnessRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass(renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer); + + break; + case SSRPass.OUTPUT.Default: this.copyMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; @@ -346,6 +383,38 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, + renderMetalness: function (renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { + + this.originalClearColor.copy(renderer.getClearColor()); + var originalClearAlpha = renderer.getClearAlpha(); + var originalAutoClear = renderer.autoClear; + + renderer.setRenderTarget(renderTarget); + renderer.autoClear = false; + + clearColor = overrideMaterial.clearColor || clearColor; + clearAlpha = overrideMaterial.clearAlpha || clearAlpha; + + if ((clearColor !== undefined) && (clearColor !== null)) { + + renderer.setClearColor(clearColor); + renderer.setClearAlpha(clearAlpha || 0.0); + renderer.clear(); + + } + + this.scene.overrideMaterial = overrideMaterial; + renderer.render(this.scene, this.camera); + this.scene.overrideMaterial = null; + + // restore original state + + renderer.autoClear = originalAutoClear; + renderer.setClearColor(this.originalClearColor); + renderer.setClearAlpha(originalClearAlpha); + + }, + setSize: function(width, height) { this.width = width; @@ -356,6 +425,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.beautyRenderTarget.setSize(width, height); this.ssrRenderTarget.setSize(width, height); this.normalRenderTarget.setSize(width, height); + this.metalnessRenderTarget.setSize(width, height); this.blurRenderTarget.setSize(width, height); this.ssrMaterial.uniforms['resolution'].value.set(width, height); @@ -376,6 +446,7 @@ SSRPass.OUTPUT = { 'Beauty': 3, 'Depth': 4, 'Normal': 5, + 'Metalness': 7, }; export { SSRPass }; diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 80406094e4e30d..e80ef010324280 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -17,6 +17,7 @@ var SSRShader = { "tDiffuse": { value: null }, "tNormal": { value: null }, + "tMetalness": { value: null }, "tDepth": { value: null }, "cameraNear": { value: null }, "cameraFar": { value: null }, @@ -51,6 +52,7 @@ var SSRShader = { varying vec2 vUv; uniform sampler2D tDepth; uniform sampler2D tNormal; + uniform sampler2D tMetalness; uniform sampler2D tDiffuse; uniform float cameraRange; uniform vec2 resolution; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 2830d7f2b2f6ca..2f35916a527701 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -288,7 +288,8 @@ 'SSR Only + Blur': SSRPass.OUTPUT.Blur, 'Beauty': SSRPass.OUTPUT.Beauty, 'Depth': SSRPass.OUTPUT.Depth, - 'Normal': SSRPass.OUTPUT.Normal + 'Normal': SSRPass.OUTPUT.Normal, + 'Metalness': SSRPass.OUTPUT.Metalness, }).onChange(function (value) { ssrPass.output = parseInt(value); From 135b3f36789b4f58f3c647a8518c4980c9a5aece Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 30 Aug 2020 22:08:55 +0800 Subject: [PATCH 046/103] selective ok --- examples/jsm/postprocessing/SSRPass.js | 15 ++++++++++++--- examples/jsm/shaders/SSRShader.js | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 172d6713c4567f..437b0a2b496d2e 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -228,7 +228,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render metalnesses - this.renderOverride(renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0); + this.renderMetalness(renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0); // render SSR @@ -403,9 +403,18 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { } - this.scene.overrideMaterial = overrideMaterial; + this.scene.traverse(child=>{ + child._material=child.material + if(child===this.scene.children[3]){ + child.material=this.metalnessOnMaterial + }else{ + child.material=this.metalnessOffMaterial + } + }) renderer.render(this.scene, this.camera); - this.scene.overrideMaterial = null; + this.scene.traverse(child => { + child.material = child._material + }) // restore original state diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index e80ef010324280..8b7435fd45fd09 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -111,6 +111,8 @@ var SSRShader = { return length(cross(x0-x1,x0-x2))/length(x2-x1); } void main(){ + float metalness=texture2D(tMetalness,vUv).r; + if(metalness==0.) return; float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); From 3ce1c0da3e9da52aebedeaab336d91f3d63d59b7 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 30 Aug 2020 22:29:11 +0800 Subject: [PATCH 047/103] selective ok --- examples/jsm/postprocessing/SSRPass.js | 60 ++++++++++++++++---------- examples/jsm/shaders/SSRShader.js | 8 +++- examples/webgl_postprocessing_ssr.html | 40 ++++++++++------- 3 files changed, 68 insertions(+), 40 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 437b0a2b496d2e..9f35644ddde5f2 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -31,7 +31,7 @@ import { SSRBlurShader } from "../shaders/SSRShader.js"; import { SSRDepthShader } from "../shaders/SSRShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; -var SSRPass = function(scene, camera, width, height) { +var SSRPass = function(scene, camera, width, height,selects) { Pass.call(this); @@ -49,6 +49,9 @@ var SSRPass = function(scene, camera, width, height) { this.maxDistance = 900; this.surfDist = 1. + this.selects=selects + this.isSelective=this.selects.length>0 + // beauty render target with depth buffer var depthTexture = new DepthTexture(); @@ -74,11 +77,13 @@ var SSRPass = function(scene, camera, width, height) { // metalness render target - this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { - minFilter: NearestFilter, - magFilter: NearestFilter, - format: RGBAFormat - }); + if(this.isSelective){ + this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + format: RGBAFormat + }); + } @@ -111,7 +116,10 @@ var SSRPass = function(scene, camera, width, height) { this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; - this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture; + if (this.isSelective){ + this.ssrMaterial.uniforms['isSelective'].value = true; + this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture; + } this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far; @@ -125,17 +133,19 @@ var SSRPass = function(scene, camera, width, height) { this.normalMaterial = new MeshNormalMaterial(); this.normalMaterial.blending = NoBlending; - // metalnessOn material + if (this.isSelective) { + // metalnessOn material - this.metalnessOnMaterial = new MeshBasicMaterial({ - color:'white' - }); + this.metalnessOnMaterial = new MeshBasicMaterial({ + color:'white' + }); - // metalnessOff material + // metalnessOff material - this.metalnessOffMaterial = new MeshBasicMaterial({ - color: 'black' - }); + this.metalnessOffMaterial = new MeshBasicMaterial({ + color: 'black' + }); + } @@ -195,15 +205,17 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.beautyRenderTarget.dispose(); this.normalRenderTarget.dispose(); - this.metalnessRenderTarget.dispose(); + if (this.isSelective) this.metalnessRenderTarget.dispose(); this.ssrRenderTarget.dispose(); this.blurRenderTarget.dispose(); // dispose materials this.normalMaterial.dispose(); - this.metalnessOnMaterial.dispose(); - this.metalnessOffMaterial.dispose(); + if (this.isSelective) { + this.metalnessOnMaterial.dispose(); + this.metalnessOffMaterial.dispose(); + } this.blurMaterial.dispose(); this.copyMaterial.dispose(); this.depthRenderMaterial.dispose(); @@ -228,7 +240,9 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render metalnesses - this.renderMetalness(renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0); + if (this.isSelective) { + this.renderMetalness(renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0); + } // render SSR @@ -404,8 +418,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { } this.scene.traverse(child=>{ - child._material=child.material - if(child===this.scene.children[3]){ + child._SSRPassMaterialBack=child.material + if(this.selects.includes(child)){ child.material=this.metalnessOnMaterial }else{ child.material=this.metalnessOffMaterial @@ -413,7 +427,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }) renderer.render(this.scene, this.camera); this.scene.traverse(child => { - child.material = child._material + child.material = child._SSRPassMaterialBack }) // restore original state @@ -434,7 +448,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.beautyRenderTarget.setSize(width, height); this.ssrRenderTarget.setSize(width, height); this.normalRenderTarget.setSize(width, height); - this.metalnessRenderTarget.setSize(width, height); + if (this.isSelective) this.metalnessRenderTarget.setSize(width, height); this.blurRenderTarget.setSize(width, height); this.ssrMaterial.uniforms['resolution'].value.set(width, height); diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 8b7435fd45fd09..2e9ae0fcb03d5c 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -28,6 +28,7 @@ var SSRShader = { "maxDistance": { value: 0.05 }, "cameraRange": { value: 0 }, "surfDist": { value: 0 }, + "isSelective": { value: null }, }, @@ -54,6 +55,7 @@ var SSRShader = { uniform sampler2D tNormal; uniform sampler2D tMetalness; uniform sampler2D tDiffuse; + uniform bool isSelective; uniform float cameraRange; uniform vec2 resolution; uniform float opacity; @@ -111,8 +113,10 @@ var SSRShader = { return length(cross(x0-x1,x0-x2))/length(x2-x1); } void main(){ - float metalness=texture2D(tMetalness,vUv).r; - if(metalness==0.) return; + if(isSelective){ + float metalness=texture2D(tMetalness,vUv).r; + if(metalness==0.) return; + } float depth = getDepth( vUv ); float viewZ = getViewZ( depth ); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 2f35916a527701..89c70161d12be3 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -3,27 +3,27 @@ - - three.js webgl - postprocessing - Screen Space Reflection - - - - + + three.js webgl - postprocessing - Screen Space Reflection + + + + -

- three.js - - SSRPass demo by Vis.
- based on this scene -
+
+ three.js - + SSRPass demo by Vis.
+ based on this scene +
- - + + + + From bed4359b29af08eecbdd01a71eea011439cdb8ae Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 30 Aug 2020 22:42:17 +0800 Subject: [PATCH 050/103] use traverse for selective reflect first, try other methods after --- .../webgl_postprocessing_ssr_selective.html | 366 ------------------ 1 file changed, 366 deletions(-) delete mode 100644 examples/webgl_postprocessing_ssr_selective.html diff --git a/examples/webgl_postprocessing_ssr_selective.html b/examples/webgl_postprocessing_ssr_selective.html deleted file mode 100644 index 5843e8f894cdba..00000000000000 --- a/examples/webgl_postprocessing_ssr_selective.html +++ /dev/null @@ -1,366 +0,0 @@ - - - - - - - three.js webgl - postprocessing - Screen Space Reflection - - - - - - -
- three.js - - SSRPass demo by Vis.
- based on this scene -
- - - - - - - From 518da6ab7f1ee86741112d088534094471417419 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 31 Aug 2020 12:40:28 +0800 Subject: [PATCH 051/103] Configurable encoding --- examples/jsm/postprocessing/SSRPass.js | 71 ++++++++++++++------------ examples/webgl_postprocessing_ssr.html | 24 +++++++-- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index a8f4de9ee62216..8e9f0374c3b30e 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -31,7 +31,7 @@ import { SSRBlurShader } from "../shaders/SSRShader.js"; import { SSRDepthShader } from "../shaders/SSRShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; -var SSRPass = function(scene, camera, width, height,selects) { +var SSRPass = function({ scene, camera, width, height, selects, encoding }) { Pass.call(this); @@ -49,8 +49,10 @@ var SSRPass = function(scene, camera, width, height,selects) { this.maxDistance = 900; this.surfDist = 1. - this.selects=selects - this.isSelective=this.selects?this.selects.length>0:false + this.selects = selects + this.isSelective = Array.isArray(this.selects) + + this.encoding = encoding // beauty render target with depth buffer @@ -77,7 +79,7 @@ var SSRPass = function(scene, camera, width, height,selects) { // metalness render target - if(this.isSelective){ + if (this.isSelective) { this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { minFilter: NearestFilter, magFilter: NearestFilter, @@ -116,7 +118,7 @@ var SSRPass = function(scene, camera, width, height,selects) { this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; - if (this.isSelective){ + if (this.isSelective) { this.ssrMaterial.uniforms['isSelective'].value = true; this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture; } @@ -134,10 +136,10 @@ var SSRPass = function(scene, camera, width, height,selects) { this.normalMaterial.blending = NoBlending; if (this.isSelective) { - // metalnessOn material + // metalnessOn material this.metalnessOnMaterial = new MeshBasicMaterial({ - color:'white' + color: 'white' }); // metalnessOff material @@ -230,6 +232,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // render beauty and depth + if (this.encoding) this.beautyRenderTarget.texture.encoding = this.encoding renderer.setRenderTarget(this.beautyRenderTarget); renderer.clear(); renderer.render(this.scene, this.camera); @@ -397,44 +400,44 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { }, - renderMetalness: function (renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { + renderMetalness: function(renderer, overrideMaterial, renderTarget, clearColor, clearAlpha) { - this.originalClearColor.copy(renderer.getClearColor()); - var originalClearAlpha = renderer.getClearAlpha(); - var originalAutoClear = renderer.autoClear; + this.originalClearColor.copy(renderer.getClearColor()); + var originalClearAlpha = renderer.getClearAlpha(); + var originalAutoClear = renderer.autoClear; - renderer.setRenderTarget(renderTarget); - renderer.autoClear = false; + renderer.setRenderTarget(renderTarget); + renderer.autoClear = false; - clearColor = overrideMaterial.clearColor || clearColor; - clearAlpha = overrideMaterial.clearAlpha || clearAlpha; + clearColor = overrideMaterial.clearColor || clearColor; + clearAlpha = overrideMaterial.clearAlpha || clearAlpha; - if ((clearColor !== undefined) && (clearColor !== null)) { + if ((clearColor !== undefined) && (clearColor !== null)) { - renderer.setClearColor(clearColor); - renderer.setClearAlpha(clearAlpha || 0.0); - renderer.clear(); + renderer.setClearColor(clearColor); + renderer.setClearAlpha(clearAlpha || 0.0); + renderer.clear(); - } + } - this.scene.traverse(child=>{ - child._SSRPassMaterialBack=child.material - if(this.selects.includes(child)){ - child.material=this.metalnessOnMaterial - }else{ - child.material=this.metalnessOffMaterial + this.scene.traverse(child => { + child._SSRPassMaterialBack = child.material + if (this.selects.includes(child)) { + child.material = this.metalnessOnMaterial + } else { + child.material = this.metalnessOffMaterial } }) - renderer.render(this.scene, this.camera); - this.scene.traverse(child => { - child.material = child._SSRPassMaterialBack - }) + renderer.render(this.scene, this.camera); + this.scene.traverse(child => { + child.material = child._SSRPassMaterialBack + }) - // restore original state + // restore original state - renderer.autoClear = originalAutoClear; - renderer.setClearColor(this.originalClearColor); - renderer.setClearAlpha(originalClearAlpha); + renderer.autoClear = originalAutoClear; + renderer.setClearColor(this.originalClearColor); + renderer.setClearAlpha(originalClearAlpha); }, diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index d275e279649e9d..f339c7babb4820 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -17,13 +17,13 @@ based on this scene - - - + From d042fdf8a4d9901ca016364e843f57a091ffb8ab Mon Sep 17 00:00:00 2001 From: gonnavis Date: Thu, 21 Jan 2021 12:18:30 +0800 Subject: [PATCH 087/103] surfDist compensation by angle --- examples/jsm/shaders/SSRShader.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 454a0026489d56..e71253ef423130 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -183,11 +183,14 @@ var SSRShader = { float cW = cameraProjectionMatrix[2][3] * vZ+cameraProjectionMatrix[3][3]; vec3 vP=getViewPosition( uv, d, cW ); + float fresnel=(dot(viewIncidenceDir,viewReflectDir)+1.)/2.; + #ifdef isPerspectiveCamera // https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf float recipVPZ=1./viewPosition.z; float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ)); - float sD=surfDist*cW; + // float sD=surfDist*cW; + float sD=surfDist*cW*(1.+pow(fresnel,20.)*9.); #else float viewReflectRayZ=viewPosition.z+s*(d1viewPosition.z-viewPosition.z); float sD=surfDist; @@ -211,7 +214,6 @@ var SSRShader = { op=opacity*attenuation; #endif #ifdef isFresnel - float fresnel=(dot(viewIncidenceDir,viewReflectDir)+1.)/2.; op*=fresnel; #endif vec4 reflectColor=texture2D(tDiffuse,uv); From 701f6a59c00c702705bb15b6eac9109242c6c988 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Fri, 22 Jan 2021 10:33:27 +0800 Subject: [PATCH 088/103] With Refelector.js, default off. Now just add a reflector to hide the apparent flaw of SSR, need more integration afterwards. --- examples/webgl_postprocessing_ssr.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 858dc2e4fd2f2d..a3eb3b5c798746 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -35,6 +35,7 @@ import { GUI } from './jsm/libs/dat.gui.module.js'; import { EffectComposer } from './jsm/postprocessing/EffectComposer.js'; import { SSRPass } from './jsm/postprocessing/SSRPass.js'; + import { Reflector } from './jsm/objects/Reflector.js'; import { DRACOLoader } from './jsm/loaders/DRACOLoader.js'; @@ -42,6 +43,7 @@ enableSSR: true, isOrbitControls: false, isOtherMeshes: true, + isReflector: false, } let composer let ssrPass @@ -52,6 +54,7 @@ let controls; let camera, scene, renderer; let otherMeshes = [] + let reflector const container = document.querySelector('#container'); @@ -132,6 +135,19 @@ scene.add(mesh) otherMeshes.push(mesh) } + { + const geometry = new THREE.PlaneBufferGeometry(100, 100); + reflector = new Reflector(geometry, { + clipBias: 0.003, + textureWidth: window.innerWidth, + textureHeight: window.innerHeight, + color: 0x888888 + }); + reflector.position.y = plane.position.y + .0001; + reflector.rotation.x = -Math.PI / 2 + reflector.visible = params.isReflector + scene.add(reflector); + } // renderer renderer = new THREE.WebGLRenderer({ antialias: false }); @@ -176,6 +192,13 @@ gui.add(ssrPass, 'isDistanceAttenuation'); ssrPass.maxDistance = .1 gui.add(ssrPass, 'maxDistance').min(0).max(1).step(.01); + gui.add(params, 'isReflector').onChange(() => { + if (params.isReflector) { + reflector.visible = true + } else { + reflector.visible = false + } + }) gui.add(params, 'isOrbitControls').onChange(() => { controls.enabled = params.isOrbitControls }) From cd8eb7af920010bca8a9e2e00d3e789a0aa8b55f Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sat, 23 Jan 2021 17:11:17 +0800 Subject: [PATCH 089/103] Let Reflector.js can handle opacity by depthTexture. --- examples/jsm/objects/ReflectorForSSRPass.js | 285 ++++++++++++++++++++ examples/webgl_postprocessing_ssr.html | 5 +- 2 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 examples/jsm/objects/ReflectorForSSRPass.js diff --git a/examples/jsm/objects/ReflectorForSSRPass.js b/examples/jsm/objects/ReflectorForSSRPass.js new file mode 100644 index 00000000000000..a3a2000f11165a --- /dev/null +++ b/examples/jsm/objects/ReflectorForSSRPass.js @@ -0,0 +1,285 @@ +import { + Color, + LinearFilter, + MathUtils, + Matrix4, + Mesh, + PerspectiveCamera, + Plane, + RGBFormat, + ShaderMaterial, + UniformsUtils, + Vector3, + Vector4, + WebGLRenderTarget, + DepthTexture, + UnsignedShortType, + NearestFilter +} from '../../../build/three.module.js'; + +var Reflector = function ( geometry, options ) { + + Mesh.call( this, geometry ); + + this.type = 'Reflector'; + + var scope = this; + + options = options || {}; + + var color = ( options.color !== undefined ) ? new Color( options.color ) : new Color( 0x7F7F7F ); + var textureWidth = options.textureWidth || 512; + var textureHeight = options.textureHeight || 512; + var clipBias = options.clipBias || 0; + var shader = options.shader || Reflector.ReflectorShader; + var useDepthTexture = options.useDepthTexture + + // + + var reflectorPlane = new Plane(); + var normal = new Vector3(); + var reflectorWorldPosition = new Vector3(); + var cameraWorldPosition = new Vector3(); + var rotationMatrix = new Matrix4(); + var lookAtPosition = new Vector3( 0, 0, - 1 ); + var clipPlane = new Vector4(); + + var view = new Vector3(); + var target = new Vector3(); + var q = new Vector4(); + + var textureMatrix = new Matrix4(); + var virtualCamera = new PerspectiveCamera(); + + if( useDepthTexture ){ + var depthTexture = new DepthTexture(); + depthTexture.type = UnsignedShortType; + depthTexture.minFilter = NearestFilter; + depthTexture.maxFilter = NearestFilter; + } + + var parameters = { + minFilter: LinearFilter, + magFilter: LinearFilter, + format: RGBFormat, + depthTexture: useDepthTexture ? depthTexture : null, + }; + + var renderTarget = new WebGLRenderTarget( textureWidth, textureHeight, parameters ); + + if ( ! MathUtils.isPowerOfTwo( textureWidth ) || ! MathUtils.isPowerOfTwo( textureHeight ) ) { + + renderTarget.texture.generateMipmaps = false; + + } + + var material = new ShaderMaterial( { + transparent: useDepthTexture, + defines: { useDepthTexture: useDepthTexture }, + uniforms: UniformsUtils.clone( shader.uniforms ), + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader + } ); + + material.uniforms[ 'tDiffuse' ].value = renderTarget.texture; + material.uniforms[ 'color' ].value = color; + material.uniforms[ 'textureMatrix' ].value = textureMatrix; + if (useDepthTexture) { + material.uniforms[ 'tDepth' ].value = renderTarget.depthTexture; + } + + this.material = material; + + this.onBeforeRender = function ( renderer, scene, camera ) { + + reflectorWorldPosition.setFromMatrixPosition( scope.matrixWorld ); + cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld ); + + rotationMatrix.extractRotation( scope.matrixWorld ); + + normal.set( 0, 0, 1 ); + normal.applyMatrix4( rotationMatrix ); + + view.subVectors( reflectorWorldPosition, cameraWorldPosition ); + + // Avoid rendering when reflector is facing away + + if ( view.dot( normal ) > 0 ) return; + + view.reflect( normal ).negate(); + view.add( reflectorWorldPosition ); + + rotationMatrix.extractRotation( camera.matrixWorld ); + + lookAtPosition.set( 0, 0, - 1 ); + lookAtPosition.applyMatrix4( rotationMatrix ); + lookAtPosition.add( cameraWorldPosition ); + + target.subVectors( reflectorWorldPosition, lookAtPosition ); + target.reflect( normal ).negate(); + target.add( reflectorWorldPosition ); + + virtualCamera.position.copy( view ); + virtualCamera.up.set( 0, 1, 0 ); + virtualCamera.up.applyMatrix4( rotationMatrix ); + virtualCamera.up.reflect( normal ); + virtualCamera.lookAt( target ); + + virtualCamera.far = camera.far; // Used in WebGLBackground + + virtualCamera.updateMatrixWorld(); + virtualCamera.projectionMatrix.copy( camera.projectionMatrix ); + + // Update the texture matrix + textureMatrix.set( + 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 + ); + textureMatrix.multiply( virtualCamera.projectionMatrix ); + textureMatrix.multiply( virtualCamera.matrixWorldInverse ); + textureMatrix.multiply( scope.matrixWorld ); + + // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html + // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf + reflectorPlane.setFromNormalAndCoplanarPoint( normal, reflectorWorldPosition ); + reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse ); + + clipPlane.set( reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant ); + + var projectionMatrix = virtualCamera.projectionMatrix; + + q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; + q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; + q.z = - 1.0; + q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; + + // Calculate the scaled plane vector + clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) ); + + // Replacing the third row of the projection matrix + projectionMatrix.elements[ 2 ] = clipPlane.x; + projectionMatrix.elements[ 6 ] = clipPlane.y; + projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias; + projectionMatrix.elements[ 14 ] = clipPlane.w; + + // Render + + renderTarget.texture.encoding = renderer.outputEncoding; + + scope.visible = false; + + var currentRenderTarget = renderer.getRenderTarget(); + + var currentXrEnabled = renderer.xr.enabled; + var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate; + + renderer.xr.enabled = false; // Avoid camera modification + renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows + + renderer.setRenderTarget( renderTarget ); + + renderer.state.buffers.depth.setMask( true ); // make sure the depth buffer is writable so it can be properly cleared, see #18897 + + if ( renderer.autoClear === false ) renderer.clear(); + renderer.render( scene, virtualCamera ); + + renderer.xr.enabled = currentXrEnabled; + renderer.shadowMap.autoUpdate = currentShadowAutoUpdate; + + renderer.setRenderTarget( currentRenderTarget ); + + // Restore viewport + + var viewport = camera.viewport; + + if ( viewport !== undefined ) { + + renderer.state.viewport( viewport ); + + } + + scope.visible = true; + + }; + + this.getRenderTarget = function () { + + return renderTarget; + + }; + +}; + +Reflector.prototype = Object.create( Mesh.prototype ); +Reflector.prototype.constructor = Reflector; + +Reflector.ReflectorShader = { + + uniforms: { + + 'color': { + value: null + }, + + 'tDiffuse': { + value: null + }, + + 'tDepth': { + value: null + }, + + 'textureMatrix': { + value: null + } + + }, + + vertexShader: [ + 'uniform mat4 textureMatrix;', + 'varying vec4 vUv;', + + 'void main() {', + + ' vUv = textureMatrix * vec4( position, 1.0 );', + + ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + + '}' + ].join( '\n' ), + + fragmentShader: [ + 'uniform vec3 color;', + 'uniform sampler2D tDiffuse;', + 'uniform sampler2D tDepth;', + 'varying vec4 vUv;', + + 'float blendOverlay( float base, float blend ) {', + + ' return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );', + + '}', + + 'vec3 blendOverlay( vec3 base, vec3 blend ) {', + + ' return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );', + + '}', + + 'void main() {', + + ' vec4 base = texture2DProj( tDiffuse, vUv );', + ' #ifdef useDepthTexture', + ' vec4 depth = texture2DProj( tDepth, vUv );', + ' gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.-depth.r );', + ' #else', + ' gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );', + ' #endif', + + '}' + ].join( '\n' ) +}; + +export { Reflector }; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index a3eb3b5c798746..d839cba2a7d808 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -35,7 +35,7 @@ import { GUI } from './jsm/libs/dat.gui.module.js'; import { EffectComposer } from './jsm/postprocessing/EffectComposer.js'; import { SSRPass } from './jsm/postprocessing/SSRPass.js'; - import { Reflector } from './jsm/objects/Reflector.js'; + import { Reflector } from './jsm/objects/ReflectorForSSRPass.js'; import { DRACOLoader } from './jsm/loaders/DRACOLoader.js'; @@ -141,7 +141,8 @@ clipBias: 0.003, textureWidth: window.innerWidth, textureHeight: window.innerHeight, - color: 0x888888 + color: 0x888888, + useDepthTexture: true, }); reflector.position.y = plane.position.y + .0001; reflector.rotation.x = -Math.PI / 2 From 2e79d4a387dc3109aaff6f6e3318b5d328cb2139 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Sun, 24 Jan 2021 11:47:28 +0800 Subject: [PATCH 090/103] fix the "jumpiness" of the reflection --- examples/jsm/postprocessing/SSRPass.js | 4 +++- examples/webgl_postprocessing_ssr.html | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index c6f1694043b5e2..97ae044bcf478a 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -15,6 +15,7 @@ import { UniformsUtils, UnsignedShortType, WebGLRenderTarget, + HalfFloatType, } from "../../../build/three.module.js"; import { Pass } from "../postprocessing/Pass.js"; import { SSRShader } from "../shaders/SSRShader.js"; @@ -145,7 +146,8 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers this.normalRenderTarget = new WebGLRenderTarget(this.width, this.height, { minFilter: NearestFilter, magFilter: NearestFilter, - format: RGBAFormat + format: RGBAFormat, + type: HalfFloatType, }); // metalness render target diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index d839cba2a7d808..446134b5581587 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -161,6 +161,7 @@ // controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true controls.target.set(0, 0.1, 0); controls.update() controls.enabled = params.isOrbitControls @@ -264,7 +265,9 @@ function render() { - if (!params.isOrbitControls) { + if(params.isOrbitControls){ + controls.update() + }else { const timer = Date.now() * 0.0003; camera.position.x = Math.sin(timer) * 0.5; From 4dcbe8c7d10194bec8adc0628340ca8dc1203b6d Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 25 Jan 2021 15:08:44 +0800 Subject: [PATCH 091/103] 1. Exclude Reflector from SSRPass if Reflector is on. 2. Increase reflector distanceAttenuation. 3. Change isOrbitControls to autoRotate. --- examples/jsm/objects/ReflectorForSSRPass.js | 2 +- examples/jsm/postprocessing/SSRPass.js | 50 ++++++++++++++------- examples/webgl_postprocessing_ssr.html | 25 +++++++---- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/examples/jsm/objects/ReflectorForSSRPass.js b/examples/jsm/objects/ReflectorForSSRPass.js index a3a2000f11165a..b905e410b1736e 100644 --- a/examples/jsm/objects/ReflectorForSSRPass.js +++ b/examples/jsm/objects/ReflectorForSSRPass.js @@ -273,7 +273,7 @@ Reflector.ReflectorShader = { ' vec4 base = texture2DProj( tDiffuse, vUv );', ' #ifdef useDepthTexture', ' vec4 depth = texture2DProj( tDepth, vUv );', - ' gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.-depth.r );', + ' gl_FragColor = vec4( blendOverlay( base.rgb, color ), pow(1.-depth.r,10./*temp*/) );', ' #else', ' gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );', ' #endif', diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 97ae044bcf478a..398e4da1bc520f 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -41,10 +41,28 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers this.maxDistance = SSRShader.uniforms.maxDistance.value; this.surfDist = SSRShader.uniforms.maxDistance.value; - this.selects = selects - this.isSelective = Array.isArray(this.selects) - - this.encoding = encoding + this.encoding = encoding + + this._selects = selects + this.isSelective = Array.isArray(this._selects) + Object.defineProperty(this, 'selects', { + get() { + return this._selects + }, + set(val) { + if (this._selects === val) return + this._selects = val + if (Array.isArray(val)) { + this.isSelective = true + this.ssrMaterial.defines.isSelective = true + this.ssrMaterial.needsUpdate = true + } else { + this.isSelective = false + this.ssrMaterial.defines.isSelective = false + this.ssrMaterial.needsUpdate = true + } + } + }) this._isBouncing = isBouncing Object.defineProperty(this, 'isBouncing', { @@ -152,13 +170,13 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers // metalness render target - if (this.isSelective) { + // if (this.isSelective) { this.metalnessRenderTarget = new WebGLRenderTarget(this.width, this.height, { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }); - } + // } @@ -198,11 +216,11 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers this.ssrMaterial.uniforms['tDiffuse'].value = this.beautyRenderTarget.texture; this.ssrMaterial.uniforms['tNormal'].value = this.normalRenderTarget.texture; - if (this.isSelective) { + // if (this.isSelective) { this.ssrMaterial.defines.isSelective = this.isSelective this.ssrMaterial.needsUpdate = true this.ssrMaterial.uniforms['tMetalness'].value = this.metalnessRenderTarget.texture; - } + // } this.ssrMaterial.uniforms['tDepth'].value = this.beautyRenderTarget.depthTexture; this.ssrMaterial.uniforms['cameraNear'].value = this.camera.near; this.ssrMaterial.uniforms['cameraFar'].value = this.camera.far; @@ -216,7 +234,7 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers this.normalMaterial = new MeshNormalMaterial({ morphTargets }); this.normalMaterial.blending = NoBlending; - if (this.isSelective) { + // if (this.isSelective) { // metalnessOn material this.metalnessOnMaterial = new MeshBasicMaterial({ @@ -228,7 +246,7 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers this.metalnessOffMaterial = new MeshBasicMaterial({ color: 'black' }); - } + // } // blur material @@ -311,7 +329,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.beautyRenderTarget.dispose(); this.prevRenderTarget.dispose(); this.normalRenderTarget.dispose(); - if (this.isSelective) this.metalnessRenderTarget.dispose(); + // if (this.isSelective) + this.metalnessRenderTarget.dispose(); this.ssrRenderTarget.dispose(); this.blurRenderTarget.dispose(); this.blurRenderTarget2.dispose(); @@ -320,10 +339,10 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { // dispose materials this.normalMaterial.dispose(); - if (this.isSelective) { + // if (this.isSelective) { this.metalnessOnMaterial.dispose(); this.metalnessOffMaterial.dispose(); - } + // } this.blurMaterial.dispose(); this.blurMaterial2.dispose(); this.copyMaterial.dispose(); @@ -551,7 +570,7 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.scene.traverseVisible(child => { child._SSRPassMaterialBack = child.material - if (this.selects.includes(child)) { + if (this._selects.includes(child)) { child.material = this.metalnessOnMaterial } else { child.material = this.metalnessOffMaterial @@ -581,7 +600,8 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.prevRenderTarget.setSize(width, height); this.ssrRenderTarget.setSize(width, height); this.normalRenderTarget.setSize(width, height); - if (this.isSelective) this.metalnessRenderTarget.setSize(width, height); + // if (this.isSelective) + this.metalnessRenderTarget.setSize(width, height); this.blurRenderTarget.setSize(width, height); this.blurRenderTarget2.setSize(width, height); // this.blurRenderTarget3.setSize(width, height); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 446134b5581587..e17243fd4616ff 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -41,7 +41,7 @@ let params = { enableSSR: true, - isOrbitControls: false, + autoRotate: true, isOtherMeshes: true, isReflector: false, } @@ -55,6 +55,7 @@ let camera, scene, renderer; let otherMeshes = [] let reflector + let selects=[] const container = document.querySelector('#container'); @@ -105,6 +106,7 @@ // mesh.castShadow = true; // mesh.receiveShadow = true; scene.add(mesh); + selects.push(mesh) // Release decoder resources. dracoLoader.dispose(); @@ -118,6 +120,7 @@ mesh.position.set(-.12, plane.position.y + .025, .015) scene.add(mesh) otherMeshes.push(mesh) + selects.push(mesh) } { const geometry = new THREE.IcosahedronBufferGeometry(.025, 4); @@ -126,6 +129,7 @@ mesh.position.set(-.05, plane.position.y + .025, .08) scene.add(mesh) otherMeshes.push(mesh) + selects.push(mesh) } { const geometry = new THREE.ConeBufferGeometry(.025, .05, 64); @@ -134,6 +138,7 @@ mesh.position.set(-.05, plane.position.y + .025, -.055) scene.add(mesh) otherMeshes.push(mesh) + selects.push(mesh) } { const geometry = new THREE.PlaneBufferGeometry(100, 100); @@ -164,7 +169,7 @@ controls.enableDamping = true controls.target.set(0, 0.1, 0); controls.update() - controls.enabled = params.isOrbitControls + controls.enabled = !params.autoRotate // STATS @@ -183,27 +188,31 @@ height: innerHeight, encoding: THREE.sRGBEncoding, isPerspectiveCamera: isPerspectiveCamera, + selects: params.isReflector ? selects : null, // morphTargets: true, }); + // window.ssrPass = ssrPass composer.addPass(ssrPass); // GUI gui = new GUI({ width: 400 }); gui.add(params, 'enableSSR').name('Enable SSR'); + gui.add(params, 'autoRotate').onChange(() => { + controls.enabled = !params.autoRotate + }) gui.add(ssrPass, 'isDistanceAttenuation'); ssrPass.maxDistance = .1 gui.add(ssrPass, 'maxDistance').min(0).max(1).step(.01); gui.add(params, 'isReflector').onChange(() => { if (params.isReflector) { reflector.visible = true + ssrPass.selects = selects } else { reflector.visible = false + ssrPass.selects = null } }) - gui.add(params, 'isOrbitControls').onChange(() => { - controls.enabled = params.isOrbitControls - }) gui.add(params, 'isOtherMeshes').onChange(() => { if (params.isOtherMeshes) { otherMeshes.forEach(mesh => mesh.visible = true) @@ -265,15 +274,15 @@ function render() { - if(params.isOrbitControls){ - controls.update() - }else { + if(params.autoRotate){ const timer = Date.now() * 0.0003; camera.position.x = Math.sin(timer) * 0.5; camera.position.y = 0.25; camera.position.z = Math.cos(timer) * 0.5; camera.lookAt(0, 0.1, 0); + }else { + controls.update() } if (params.enableSSR) { From 7e088220687dbd4a7e2b205686a0d1544e12a9b2 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 25 Jan 2021 21:34:55 +0800 Subject: [PATCH 092/103] Decrease the vertical offset between SSR and Reflector. --- examples/webgl_postprocessing_ssr.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index e17243fd4616ff..5f23c2402373c1 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -77,9 +77,10 @@ scene.fog = new THREE.Fog(0x443333, 1, 4); // Ground + const planeMaterial = new THREE.MeshPhongMaterial({ color: 0x999999, specular: 0x101010 }) const plane = new THREE.Mesh( new THREE.PlaneGeometry(8, 8), - new THREE.MeshPhongMaterial({ color: 0x999999, specular: 0x101010 }) + planeMaterial ); plane.rotation.x = - Math.PI / 2; plane.position.y = 0.0365; @@ -149,7 +150,7 @@ color: 0x888888, useDepthTexture: true, }); - reflector.position.y = plane.position.y + .0001; + reflector.position.y = plane.position.y; reflector.rotation.x = -Math.PI / 2 reflector.visible = params.isReflector scene.add(reflector); @@ -208,9 +209,11 @@ if (params.isReflector) { reflector.visible = true ssrPass.selects = selects + planeMaterial.depthWrite = false } else { reflector.visible = false ssrPass.selects = null + planeMaterial.depthWrite = true } }) gui.add(params, 'isOtherMeshes').onChange(() => { @@ -237,8 +240,8 @@ ssrPass.opacity = .8 gui.add(ssrPass, 'opacity').min(0).max(1); if (isPerspectiveCamera) { - ssrPass.surfDist = 0.0021 - gui.add(ssrPass, 'surfDist').min(0).max(.02).step(.0001); + ssrPass.surfDist = 0.0015 + gui.add(ssrPass, 'surfDist').min(0).max(.005).step(.0001); } else { ssrPass.surfDist = 2 gui.add(ssrPass, 'surfDist').min(0).max(7).step(.01); From 01588a564c74c3ea816d9949fc377fea15d09453 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Mon, 25 Jan 2021 23:00:58 +0800 Subject: [PATCH 093/103] Revert plane.depthWrite = false & Revert to reflector.position.y = plane.position.y + .0001; --- examples/webgl_postprocessing_ssr.html | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 5f23c2402373c1..e3e176e7a39188 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -77,10 +77,9 @@ scene.fog = new THREE.Fog(0x443333, 1, 4); // Ground - const planeMaterial = new THREE.MeshPhongMaterial({ color: 0x999999, specular: 0x101010 }) const plane = new THREE.Mesh( new THREE.PlaneGeometry(8, 8), - planeMaterial + new THREE.MeshPhongMaterial({ color: 0x999999, specular: 0x101010 }) ); plane.rotation.x = - Math.PI / 2; plane.position.y = 0.0365; @@ -150,7 +149,7 @@ color: 0x888888, useDepthTexture: true, }); - reflector.position.y = plane.position.y; + reflector.position.y = plane.position.y + .0001; reflector.rotation.x = -Math.PI / 2 reflector.visible = params.isReflector scene.add(reflector); @@ -209,11 +208,9 @@ if (params.isReflector) { reflector.visible = true ssrPass.selects = selects - planeMaterial.depthWrite = false } else { reflector.visible = false ssrPass.selects = null - planeMaterial.depthWrite = true } }) gui.add(params, 'isOtherMeshes').onChange(() => { From 2c56b95897feb5e2203aafdf75223f3a7469602c Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 26 Jan 2021 02:16:32 +0800 Subject: [PATCH 094/103] Remove the noise setting. --- examples/jsm/postprocessing/SSRPass.js | 15 --------------- examples/jsm/shaders/SSRShader.js | 8 -------- examples/webgl_postprocessing_ssr.html | 2 -- 3 files changed, 25 deletions(-) diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 398e4da1bc520f..39553383fe120b 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -123,20 +123,6 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers }) this.thickTolerance = SSRShader.uniforms.thickTolerance.value; - this._isNoise = SSRShader.defines.isNoise - Object.defineProperty(this, 'isNoise', { - get() { - return this._isNoise - }, - set(val) { - if (this._isNoise === val) return - this._isNoise = val - this.ssrMaterial.defines.isNoise = val - this.ssrMaterial.needsUpdate = true - } - }) - this.noiseIntensity = SSRShader.uniforms.noiseIntensity.value; - // beauty render target with depth buffer var depthTexture = new DepthTexture(); @@ -379,7 +365,6 @@ SSRPass.prototype = Object.assign(Object.create(Pass.prototype), { this.ssrMaterial.uniforms['maxDistance'].value = this.maxDistance; this.ssrMaterial.uniforms['surfDist'].value = this.surfDist; this.ssrMaterial.uniforms['thickTolerance'].value = this.thickTolerance - this.ssrMaterial.uniforms['noiseIntensity'].value = this.noiseIntensity this.renderPass(renderer, this.ssrMaterial, this.ssrRenderTarget); diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index e71253ef423130..942f99af92fe36 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -15,7 +15,6 @@ var SSRShader = { isDistanceAttenuation: true, isFresnel: true, isInfiniteThick: false, - isNoise: false, isSelective: false, }, @@ -35,7 +34,6 @@ var SSRShader = { "cameraRange": { value: 0 }, "surfDist": { value: .007 }, "thickTolerance": { value: .03 }, - "noiseIntensity": { value: .1 }, }, @@ -71,7 +69,6 @@ var SSRShader = { uniform mat4 cameraProjectionMatrix; uniform mat4 cameraInverseProjectionMatrix; uniform float thickTolerance; - uniform float noiseIntensity; #include float pointPlaneDistance(vec3 point,vec3 planePoint,vec3 planeNormal){ // https://mathworld.wolfram.com/Point-PlaneDistance.html @@ -134,11 +131,6 @@ var SSRShader = { vec3 viewNormal=getViewNormal( vUv ); - #ifdef isNoise - viewNormal+=(hash3(viewPosition.x+viewPosition.y+viewPosition.z)-.5)*noiseIntensity; - viewNormal=normalize(viewNormal); - #endif - #ifdef isPerspectiveCamera vec3 viewIncidenceDir=normalize(viewPosition); vec3 viewReflectDir=reflect(viewIncidenceDir,viewNormal); diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index e3e176e7a39188..48c5386ea25a1e 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -246,8 +246,6 @@ gui.add(ssrPass, 'isInfiniteThick'); gui.add(ssrPass, 'thickTolerance').min(0).max(.05).step(.0001); gui.add(ssrPass, 'isBlur'); - gui.add(ssrPass, 'isNoise'); - gui.add(ssrPass, 'noiseIntensity').min(0).max(.3).step(.01); } From 58c2812c813f09cf7fb3a364e2eb4c00f7f0d110 Mon Sep 17 00:00:00 2001 From: gonnavis Date: Tue, 26 Jan 2021 04:04:15 +0800 Subject: [PATCH 095/103] Use pointToLineDistance instead of viewReflectRayZ to calculate away, thus become stride irrelavent. --- examples/jsm/shaders/SSRShader.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 942f99af92fe36..43a3aee23d113f 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -70,6 +70,11 @@ var SSRShader = { uniform mat4 cameraInverseProjectionMatrix; uniform float thickTolerance; #include + float pointToLineDistance(vec3 x0, vec3 x1, vec3 x2) { + //x0: point, x1: linePointA, x2: linePointB + //https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html + return length(cross(x0-x1,x0-x2))/length(x2-x1); + } float pointPlaneDistance(vec3 point,vec3 planePoint,vec3 planeNormal){ // https://mathworld.wolfram.com/Point-PlaneDistance.html //// https://en.wikipedia.org/wiki/Plane_(geometry) @@ -178,20 +183,23 @@ var SSRShader = { float fresnel=(dot(viewIncidenceDir,viewReflectDir)+1.)/2.; #ifdef isPerspectiveCamera - // https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf - float recipVPZ=1./viewPosition.z; - float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ)); - // float sD=surfDist*cW; - float sD=surfDist*cW*(1.+pow(fresnel,20.)*9.); + #ifdef isInfiniteThick + // https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf + float recipVPZ=1./viewPosition.z; + float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ)); + #endif + float sD=surfDist*cW; #else - float viewReflectRayZ=viewPosition.z+s*(d1viewPosition.z-viewPosition.z); + #ifdef isInfiniteThick + float viewReflectRayZ=viewPosition.z+s*(d1viewPosition.z-viewPosition.z); + #endif float sD=surfDist; #endif #ifdef isInfiniteThick if(viewReflectRayZ+thickTolerance*clipW Date: Tue, 26 Jan 2021 12:47:15 +0800 Subject: [PATCH 096/103] Performance: perform pointToLineDistance only if viewReflectRayZ-sD<=vZ. --- examples/jsm/shaders/SSRShader.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 43a3aee23d113f..6eecb6632ff6c3 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -114,10 +114,6 @@ var SSRShader = { xy*=resolution;//screen return xy; } - vec3 hash3( float n ){ - // http://glslsandbox.com/e#61476.1 - return fract(sin(vec3(n,n+1.0,n+2.0))*vec3(43758.5453123,22578.1459123,19642.3490423)); - } void main(){ #ifdef isSelective float metalness=texture2D(tMetalness,vUv).r; @@ -180,21 +176,16 @@ var SSRShader = { float cW = cameraProjectionMatrix[2][3] * vZ+cameraProjectionMatrix[3][3]; vec3 vP=getViewPosition( uv, d, cW ); - float fresnel=(dot(viewIncidenceDir,viewReflectDir)+1.)/2.; - #ifdef isPerspectiveCamera - #ifdef isInfiniteThick - // https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf - float recipVPZ=1./viewPosition.z; - float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ)); - #endif + // https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf + float recipVPZ=1./viewPosition.z; + float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ)); float sD=surfDist*cW; #else - #ifdef isInfiniteThick - float viewReflectRayZ=viewPosition.z+s*(d1viewPosition.z-viewPosition.z); - #endif + float viewReflectRayZ=viewPosition.z+s*(d1viewPosition.z-viewPosition.z); float sD=surfDist; #endif + if(viewReflectRayZ-sD>vZ) continue; #ifdef isInfiniteThick if(viewReflectRayZ+thickTolerance*clipW Date: Tue, 26 Jan 2021 16:07:29 +0800 Subject: [PATCH 097/103] 1. Reduce the size of the reflector to prevent glitch caused by low precision. 2. reflectorRenderTarget resize. 3. Clean up. --- examples/jsm/shaders/SSRShader.js | 86 +++++++++++++------------- examples/webgl_postprocessing_ssr.html | 15 ++--- 2 files changed, 48 insertions(+), 53 deletions(-) diff --git a/examples/jsm/shaders/SSRShader.js b/examples/jsm/shaders/SSRShader.js index 6eecb6632ff6c3..d2ba9cd8e8aa73 100644 --- a/examples/jsm/shaders/SSRShader.js +++ b/examples/jsm/shaders/SSRShader.js @@ -37,21 +37,21 @@ var SSRShader = { }, - vertexShader: [ + vertexShader: /* glsl */` - "varying vec2 vUv;", + varying vec2 vUv; - "void main() {", + void main() { - " vUv = uv;", + vUv = uv; - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - "}" + } - ].join("\n"), + `, - fragmentShader: ` + fragmentShader: /* glsl */` // precision highp float; precision highp sampler2D; varying vec2 vUv; @@ -233,54 +233,54 @@ var SSRDepthShader = { }, - vertexShader: [ + vertexShader: /* glsl */` - "varying vec2 vUv;", + varying vec2 vUv; - "void main() {", + void main() { - " vUv = uv;", - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - "}" + } - ].join("\n"), + `, - fragmentShader: [ + fragmentShader: /* glsl */` - "uniform sampler2D tDepth;", + uniform sampler2D tDepth; - "uniform float cameraNear;", - "uniform float cameraFar;", + uniform float cameraNear; + uniform float cameraFar; - "varying vec2 vUv;", + varying vec2 vUv; - "#include ", + #include - "float getLinearDepth( const in vec2 uv ) {", + float getLinearDepth( const in vec2 uv ) { - " #if PERSPECTIVE_CAMERA == 1", + #if PERSPECTIVE_CAMERA == 1 - " float fragCoordZ = texture2D( tDepth, uv ).x;", - " float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );", - " return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );", + float fragCoordZ = texture2D( tDepth, uv ).x; + float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar ); + return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); - " #else", + #else - " return texture2D( tDepth, uv ).x;", + return texture2D( tDepth, uv ).x; - " #endif", + #endif - "}", + } - "void main() {", + void main() { - " float depth = getLinearDepth( vUv );", - " gl_FragColor = vec4( vec3( 1.0 - depth ), 1.0 );", + float depth = getLinearDepth( vUv ); + gl_FragColor = vec4( vec3( 1.0 - depth ), 1.0 ); - "}" + } - ].join("\n") + ` }; @@ -294,20 +294,20 @@ var SSRBlurShader = { }, - vertexShader: [ + vertexShader: /* glsl */` - "varying vec2 vUv;", + varying vec2 vUv; - "void main() {", + void main() { - " vUv = uv;", - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - "}" + } - ].join("\n"), + `, - fragmentShader: ` + fragmentShader: /* glsl */` uniform sampler2D tDiffuse; uniform vec2 resolution; diff --git a/examples/webgl_postprocessing_ssr.html b/examples/webgl_postprocessing_ssr.html index 48c5386ea25a1e..61e4e24073e158 100644 --- a/examples/webgl_postprocessing_ssr.html +++ b/examples/webgl_postprocessing_ssr.html @@ -17,14 +17,6 @@ SSRPass demo by Vis.
- - - - -