From a7eed9d638082b6dacfddd96f7b39d76118686fb Mon Sep 17 00:00:00 2001 From: mkkellogg Date: Thu, 24 Sep 2015 20:58:27 -0700 Subject: [PATCH] Updated cubeToUV() to a reduced-instruction version with minimal branching, and updated near plane values for shadow map cameras to be at least 1. --- examples/webgl_shadowmap_omnidirectional.html | 561 +++++++++--------- examples/webgl_shadowmap_viewer.html | 4 +- src/lights/PointLight.js | 4 +- .../ShaderChunk/shadowmap_pars_fragment.glsl | 84 ++- src/renderers/webgl/WebGLShadowMap.js | 31 +- 5 files changed, 345 insertions(+), 339 deletions(-) diff --git a/examples/webgl_shadowmap_omnidirectional.html b/examples/webgl_shadowmap_omnidirectional.html index dc808cdf28..9783d85fe0 100644 --- a/examples/webgl_shadowmap_omnidirectional.html +++ b/examples/webgl_shadowmap_omnidirectional.html @@ -1,280 +1,281 @@ - - - - - three.js webgl - Omni-directional Shadow map viewer example - - - - -
- three.js - Omni-directional Shadow map viewer example by mkkellogg -
- - - - - - - - + + + + + three.js webgl - Omni-directional Shadow map viewer example + + + + +
+ three.js - Omni-directional Shadow map viewer example by mkkellogg +
+ + + + + + + + diff --git a/examples/webgl_shadowmap_viewer.html b/examples/webgl_shadowmap_viewer.html index 0aba881f9c..f62a7c4cc7 100644 --- a/examples/webgl_shadowmap_viewer.html +++ b/examples/webgl_shadowmap_viewer.html @@ -65,7 +65,7 @@ function initScene() { - camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.01, 1000 ); + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 ); camera.position.set( 0, 15, 35 ); scene = new THREE.Scene(); @@ -89,7 +89,7 @@ dirLight = new THREE.DirectionalLight( 0xffffff, 1 ); dirLight.position.set( 0, 10, 0 ); dirLight.castShadow = true; - dirLight.shadowCameraNear = 0.01; + dirLight.shadowCameraNear = 1; dirLight.shadowCameraFar = 10; dirLight.shadowCameraRight = 15; dirLight.shadowCameraLeft = -15; diff --git a/src/lights/PointLight.js b/src/lights/PointLight.js index 319bc47910..8d12bce2ed 100644 --- a/src/lights/PointLight.js +++ b/src/lights/PointLight.js @@ -18,8 +18,8 @@ THREE.PointLight = function ( color, intensity, distance, decay ) { // - this.shadowCameraNear = 0; - this.shadowCameraFar = 5000; + this.shadowCameraNear = 1; + this.shadowCameraFar = 500; this.shadowCameraFov = 90; this.shadowCameraVisible = false; diff --git a/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl index 4be1ddca16..498ee4ebd3 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl @@ -28,10 +28,10 @@ /** * cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D * vector suitable for 2D texture mapping. This code uses the following layout for the - * 2D texture: - * - * Y y + * 2D texture: + * * xzXZ + * y Y * * Y - Positive y direction * y - Negative y direction @@ -40,73 +40,61 @@ * Z - Positive z direction * z - Negative z direction * - * Alternate code for different layouts, more compact code arrangement, and seam - * skipping can be found here: https://gist.github.com/tschw/da10c43c467ce8afd0c4 + * Alternate code for a horizontal cross layout can be found here: + * https://gist.github.com/tschw/da10c43c467ce8afd0c4 */ vec2 cubeToUV( vec3 v, float texelSizeX, float texelSizeY ) { - // Horizontal cross layout: - const vec2 Squares = vec2( 4.0, 2.0 ); - const vec2 Center = vec2( 1.0, 0.0 ); + // Number of texels to avoid at the edge of each square - // Size of a square in UV space: - const vec2 TexSquareSize = 1.0 / Squares; + vec3 absV = abs( v ); - // UV space offset of the center of the center square of the cross: - const vec2 TexCoordOffs = TexSquareSize * ( 0.5 + Center ); + // Intersect unit cube - // Factors to scale square space (-1..+1 per square) to UV space: - const vec2 TexSquareScale = TexSquareSize * 0.5; + float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); + absV *= scaleToCube; - // Just less than a texel in square space when divided by resolution: - const float TexEps = 1.5; // = min(Squares.x, Squares.y) - 0.5; + // Apply scale to avoid seams - vec3 absV = abs( v ); - vec3 sgnV = sign( v ); + // two texels less per square (one texel will do for NEAREST) + v *= scaleToCube * ( 1.0 - 4.0 * texelSizeY ); - // Intersect unit cube + // Unwrap - float scale = 1.0 / max( absV.x, max( absV.y, absV.z ) ); + // space: -1 ... 1 range for each square + // + // #X## dim := ( 4 , 2 ) + // # # center := ( 1 , 1 ) - v *= scale; - absV *= scale; + vec2 planar = v.xy; - // Determine gate factors + float almostATexel = 1.5 * texelSizeY; + float almostOne = 1.0 - almostATexel; - // gate.? is one when on left / right, bottom / top, back - float eps = TexEps * texelSizeY; - vec3 gate = step( 1.0 - eps, vec3( absV.xy, v.z ) ); + if ( absV.z >= almostOne ) { - // prefer any square over bottom / top - float notX = 1. - gate.x; - float notZ = 1. - gate.z; - gate.y *= notX * notZ; - // prefer back over side - gate.x *= notZ; + if ( v.z > 0.0 ) + planar.x = 4.0 - v.x; - // Unwrap + } else if ( absV.x >= almostOne ) { - // start with xy coordinates - vec2 planar = v.xy; + float signX = sign( v.x ); + planar.x = v.z * signX + 2.0 * signX; - // stop at the last texel (can use a factor of 1.0 for NEAREST) - float yTexelSize = 2.0 * Squares.y * texelSizeY; - float yAdjusted = planar.y * ( 1.0 - yTexelSize ); - planar.y = yAdjusted; - planar.y -= gate.y * yAdjusted; + } else if ( absV.y >= almostOne ) { - // unwrap left / right, top / bottom - planar.x += gate.x * ( sgnV.x + v.z * sgnV.x ); + float signY = sign( v.y ); + planar.x = v.x + 2.0 * signY + 2.0; + planar.y = v.z * signY - 2.0; - planar.x += gate.y * ( -sgnV.y * 2.0 ); - planar.y += gate.y * ( 2.0 + ( v.z * sgnV.y ) ); + } - // unwrap back - planar.x += gate.z * ( 4.0 - 2.0 * planar.x ); + // Transform to UV space - // adjust to UV space - return TexCoordOffs + planar * TexSquareScale; + // scale := 0.5 / dim + // translate := ( center + 0.5 ) / dim + return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); } diff --git a/src/renderers/webgl/WebGLShadowMap.js b/src/renderers/webgl/WebGLShadowMap.js index 821a5e904e..0b31d8e816 100644 --- a/src/renderers/webgl/WebGLShadowMap.js +++ b/src/renderers/webgl/WebGLShadowMap.js @@ -160,18 +160,35 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { var vpWidth = light.shadowMapWidth / 4.0; var vpHeight = light.shadowMapHeight / 2.0; + /* + * + * These viewports map a cube-map onto a 2D texture with the + * following orientation: + * + * xzXZ + * y Y + * + * Y - Positive y direction + * y - Negative y direction + * X - Positive x direction + * x - Negative x direction + * Z - Positive z direction + * z - Negative z direction + * + */ + // positive X - cube2DViewPorts[ 0 ].set( vpWidth * 2, 0, vpWidth, vpHeight ); + cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); // negative X - cube2DViewPorts[ 1 ].set( 0, 0, vpWidth, vpHeight ); + cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); // positive Z - cube2DViewPorts[ 2 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); + cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); // negative Z - cube2DViewPorts[ 3 ].set( vpWidth, 0, vpWidth, vpHeight ); + cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); // positive Y - cube2DViewPorts[ 4 ].set( 0, vpHeight, vpWidth, vpHeight ); + cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); // negative Y - cube2DViewPorts[ 5 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); + cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); } else { @@ -186,7 +203,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { var shadowFilter = THREE.LinearFilter; - if ( scope.type === THREE.PCFSoftShadowMap || light instanceof THREE.PointLight ) { + if ( scope.type === THREE.PCFSoftShadowMap) { shadowFilter = THREE.NearestFilter; -- GitLab