提交 f4769083 编写于 作者: M mkkellogg

Point light shadow mapping now utilizes cube-to-2D projection, avoiding the...

Point light shadow mapping now utilizes cube-to-2D projection, avoiding the need for a samplerCube in the shader.
上级 8dfd933f
......@@ -75,12 +75,12 @@
pointLight.shadowCameraFar = 30;
pointLight.shadowDarkness = 0.5;
pointLight.shadowCameraVisible = true;
pointLight.shadowMapWidth = 1024;
pointLight.shadowMapWidth = 2048;
pointLight.shadowMapHeight = 1024;
pointLight.name = 'Point Light';
scene.add( pointLight );
dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
/*dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.position.set( 0, 50, 0 );
dirLight.castShadow = true;
dirLight.shadowCameraNear = 0.01;
......@@ -94,7 +94,7 @@
dirLight.shadowMapWidth = 1024;
dirLight.shadowMapHeight = 1024;
dirLight.name = 'Dir. Light';
//scene.add( dirLight );
scene.add( dirLight );*/
cubeMaterial = new THREE.MeshPhongMaterial( {
color: 0xff0000,
......@@ -128,7 +128,7 @@
var torusGeometry = new THREE.TorusKnotGeometry( 25, 8, 75, 20 );
torusKnot = new THREE.Mesh( torusGeometry, cubeMaterial );
torusKnot.scale.multiplyScalar( 1 / 18 );
torusKnot.position.y = 3;
torusKnot.position.set( -1, 3, -4 );
torusKnot.castShadow = true;
torusKnot.receiveShadow = true;
scene.add( torusKnot );
......@@ -185,6 +185,16 @@
wall.rotation.y = Math.PI / 2;
wall.rotation.z = Math.PI / 2;
/*wall = new THREE.Mesh( wallGeometry, wallMaterial );
wall.name = "front wall";
wall.scale.multiplyScalar( 3 );
wall.castShadow = false;
wall.receiveShadow = true;
scene.add( wall );
wall.position.set( 0, 10, 14 );
wall.rotation.y = Math.PI / 2;
wall.rotation.z = Math.PI / 2;*/
var sphereGeometry = new THREE.SphereGeometry( 1, 32, 32 );
var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
var sphere = new THREE.Mesh( sphereGeometry, material );
......@@ -206,7 +216,7 @@
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x000000 );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.BasicShadowMap;
renderer.shadowMap.type = THREE.PCFShadowMap;
// Mouse control
controls = new THREE.OrbitControls( camera, renderer.domElement );
......
......@@ -374,6 +374,16 @@ THREE.WebGLRenderer = function ( parameters ) {
};
this.getViewport = function ( dimensions ) {
dimensions.x = _viewportX;
dimensions.y = _viewportY;
dimensions.z = _viewportWidth;
dimensions.w = _viewportHeight;
};
this.setScissor = function ( x, y, width, height ) {
_gl.scissor(
......@@ -1965,30 +1975,26 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( ! light.castShadow ) continue;
if ( light instanceof THREE.PointLight || light instanceof THREE.SpotLight || light instanceof THREE.DirectionalLight ) {
if ( light instanceof THREE.PointLight || light instanceof THREE.SpotLight || light instanceof THREE.DirectionalLight ) {
if( light instanceof THREE.PointLight ){
uniforms.shadowCube.value[ j ] = light.shadowMap;
uniforms.shadowMap.value[ j ] = null;
if ( light instanceof THREE.PointLight ) {
// for point lights we set the sign of the shadowDarkness uniform to be negative
uniforms.shadowDarkness.value[ j ] = -light.shadowDarkness;
uniforms.shadowDarkness.value[ j ] = - light.shadowDarkness;
// when we have a point light, the 'shadowMatrix' uniform is used to store
// the inverse of the view matrix (camera.matrixWorld), so that we can get the
// the inverse of the view matrix (camera.matrixWorld), so that we can get the
// world-space position of the light in the shader.
uniforms.shadowMatrix.value[ j ] = camera.matrixWorld;
} else {
uniforms.shadowMap.value[ j ] = light.shadowMap;
uniforms.shadowCube.value[ j ] = null;
uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
}
}
uniforms.shadowMap.value[ j ] = light.shadowMap;
uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
uniforms.shadowBias.value[ j ] = light.shadowBias;
......@@ -2347,9 +2353,11 @@ THREE.WebGLRenderer = function ( parameters ) {
textureUnit = uniform._array[ i ];
if ( ! texture ) continue;
if ( texture instanceof THREE.CubeTexture ||
( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/
( texture.image instanceof Array && texture.image.length === 6 ) ) {
// CompressedTexture can have Array in image :/
setCubeTexture( texture, textureUnit );
......@@ -3153,10 +3161,10 @@ THREE.WebGLRenderer = function ( parameters ) {
}
if( isCube ){
if ( isCube ) {
var renderTargetProperties = properties.get( renderTarget );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, renderTargetProperties.__webglTexture , 0 );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, renderTargetProperties.__webglTexture, 0 );
}
......
......@@ -24,7 +24,9 @@
// for point lights, the uniform @vShadowCoord is re-purposed to hold
// the distance from the light to the world-space position of the fragment.
vec3 lightToPosition = vShadowCoord[ i ].xyz;
float cubeTexelSize = 1.0 / shadowMapSize[ i ].x;
float texelSizeX = 1.0 / shadowMapSize[ i ].x;
float texelSizeY = 1.0 / shadowMapSize[ i ].y;
vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;
float shadow = 0.0;
......@@ -49,16 +51,20 @@
if( isPointLight ) {
float cubeTexelSize = 1.0 / ( shadowMapSize[ i ].x * 0.25 );
vec3 baseDirection3D = normalize( lightToPosition );
vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeX, texelSizeY );
initGridSamplingDisk();
float diskRadius = 1.5;
float diskRadius = 1.25;
float numSamples = 1.0;
shadow = 0.0;
vec3 baseDirection = normalize( lightToPosition );
float curDistance = length( lightToPosition );
float dist = unpack1K( textureCube( shadowCube[ i ], baseDirection ) );
float dist = unpack1K( texture2D( shadowMap[ i ], baseDirection2D ) ) + 0.1;
if ( curDistance >= dist )
shadow += 1.0;
......@@ -66,15 +72,17 @@
for( int s = 0; s < 20; s++ ) {
vec3 offset = gridSamplingDisk[ s ] * diskRadius * cubeTexelSize;
dist = unpack1K( textureCube( shadowCube[ i ], vec3( baseDirection + offset ) ) );
vec3 adjustedBaseDirection3D = baseDirection3D + offset;
vec2 adjustedBaseDirection2D = cubeToUV( adjustedBaseDirection3D, texelSizeX, texelSizeY );
dist = unpack1K( texture2D( shadowMap[ i ], adjustedBaseDirection2D ) ) + 0.1;
if ( curDistance >= dist )
shadow += 1.0;
numSamples += 1.0;
}
shadow /= numSamples;
} else {
#endif
......@@ -86,30 +94,22 @@
/*
// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
// must enroll loop manually
for ( float y = -1.25; y <= 1.25; y += 1.25 )
for ( float x = -1.25; x <= 1.25; x += 1.25 ) {
vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );
// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup
//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );
float fDepth = unpackDepth( rgbaDepth );
if ( fDepth < shadowCoord.z )
shadow += 1.0;
}
shadow /= 9.0;
*/
const float shadowDelta = 1.0 / 9.0;
float xPixelOffset = 1.0 / shadowMapSize[ i ].x;
float yPixelOffset = 1.0 / shadowMapSize[ i ].y;
float xPixelOffset = texelSizeX;
float yPixelOffset = texelSizeY;
float dx0 = -1.25 * xPixelOffset;
float dy0 = -1.25 * yPixelOffset;
......@@ -150,40 +150,46 @@
#endif
shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );
#elif defined( SHADOWMAP_TYPE_PCF_SOFT )
#if defined(POINT_LIGHT_SHADOWS)
#if defined(POINT_LIGHT_SHADOWS)
if( isPointLight ) {
float cubeTexelSize = 1.0 / ( shadowMapSize[ i ].x * 0.25 );
vec3 baseDirection3D = normalize( lightToPosition );
vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeX, texelSizeY );
initGridSamplingDisk();
float diskRadius = 2.5;
float diskRadius = 2.25;
float numSamples = 1.0;
shadow = 0.0;
vec3 baseDirection = normalize( lightToPosition );
float curDistance = length( lightToPosition );
float dist = unpack1K( textureCube( shadowCube[ i ], baseDirection ) );
float dist = unpack1K( texture2D( shadowMap[ i ], baseDirection2D ) ) + 0.1;
if ( curDistance >= dist )
shadow += 1.0;
// evaluate each sampling direction
for( int s = 0; s < 20; s++ ) {
vec3 offset = gridSamplingDisk[ s ] * diskRadius * cubeTexelSize;
dist = unpack1K( textureCube( shadowCube[ i ], vec3( baseDirection + offset ) ) );
vec3 adjustedBaseDirection3D = baseDirection3D + offset;
vec2 adjustedBaseDirection2D = cubeToUV( adjustedBaseDirection3D, texelSizeX, texelSizeY );
dist = unpack1K( texture2D( shadowMap[ i ], adjustedBaseDirection2D ) ) + 0.1;
if ( curDistance >= dist )
shadow += 1.0;
numSamples += 1.0;
}
shadow /= numSamples;
} else {
} else {
#endif
......@@ -191,8 +197,8 @@
// (9 pixel kernel)
// http://fabiensanglard.net/shadowmappingPCF/
float xPixelOffset = 1.0 / shadowMapSize[ i ].x;
float yPixelOffset = 1.0 / shadowMapSize[ i ].y;
float xPixelOffset = texelSizeX;
float yPixelOffset = texelSizeY;
float dx0 = -1.0 * xPixelOffset;
float dy0 = -1.0 * yPixelOffset;
......@@ -247,17 +253,19 @@
#if defined(POINT_LIGHT_SHADOWS)
if( isPointLight ) {
if( isPointLight ) {
vec3 baseDirection3D = normalize( lightToPosition );
vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeX, texelSizeY );
vec4 data = texture2D( shadowMap[ i ], baseDirection2D );
float dist = unpack1K( data ) + 0.1;
if ( length( lightToPosition ) >= dist)
shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
vec4 data = textureCube( shadowCube[ i ], normalize( lightToPosition ) );
float dist = unpack1K( data );
if ( length( lightToPosition ) >= dist)
shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
} else {
#endif
vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );
float fDepth = unpackDepth( rgbaDepth );
......
......@@ -18,19 +18,6 @@
#if defined(POINT_LIGHT_SHADOWS)
uniform samplerCube shadowCube[ MAX_SHADOWS ];
vec4 pack1K ( float depth ) {
depth /= 1000.0;
const vec4 bitSh = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
const vec4 bitMsk = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );
vec4 res = fract( depth * bitSh );
res -= res.xxyz * bitMsk;
return res;
}
float unpack1K ( vec4 color ) {
const vec4 bitSh = vec4( 1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0 );
......@@ -38,6 +25,72 @@
}
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 );
// Size of a square in UV space:
const vec2 TexSquareSize = 1.0 / Squares;
// UV space offset of the center of the center square of the cross:
const vec2 TexCoordOffs = TexSquareSize * ( 0.5 + Center );
// Factors to scale square space (-1..+1 per square) to UV space:
const vec2 TexSquareScale = TexSquareSize * 0.5;
// Just less than a texel in square space when divided by resolution:
const float TexEps = 1.5; // = min(Squares.x, Squares.y) - 0.5;
vec3 absV = abs( v );
vec3 sgnV = sign( v );
// Intersect unit cube
float scale = 1.0 / max( absV.x, max( absV.y, absV.z ) );
v *= scale;
absV *= scale;
// Determine gate factors
// 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 ) );
// 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;
// Unwrap
// start with xy coordinates
vec2 planar = v.xy;
// 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;
// unwrap left / right, top / bottom
planar.x += gate.x * ( sgnV.x + v.z * sgnV.x );
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 );
// adjust to UV space
return TexCoordOffs + planar * TexSquareScale;
}
vec3 gridSamplingDisk[ 20 ];
bool gridSamplingInitialized = false;
......@@ -46,7 +99,7 @@
if( gridSamplingInitialized ){
return;
}
gridSamplingDisk[0] = vec3(1, 1, 1);
......
#ifdef USE_SHADOWMAP uniform float shadowDarkness[ MAX_SHADOWS ]; uniform mat4 shadowMatrix[ MAX_SHADOWS ]; varying vec4 vShadowCoord[ MAX_SHADOWS ]; #endif
\ No newline at end of file
#ifdef USE_SHADOWMAP
uniform float shadowDarkness[ MAX_SHADOWS ];
uniform mat4 shadowMatrix[ MAX_SHADOWS ];
varying vec4 vShadowCoord[ MAX_SHADOWS ];
#endif
\ No newline at end of file
#ifdef USE_SHADOWMAP for( int i = 0; i < MAX_SHADOWS; i ++ ) { #if defined(POINT_LIGHT_SHADOWS) // if shadowDarkness[ i ] < 0.0, that means we have a point light with a cube // shadow map if( shadowDarkness[ i ] < 0.0 ){ // When we have a point light, the @shadowMatrix uniform is used to store // the inverse of the view matrix, so that we can get the world-space // position of the light. vec4 lightPositionWorld = ( shadowMatrix[ i ] * vec4( pointLightPosition[ i ], 1.0 )); vec4 distanceToLight = worldPosition - lightPositionWorld; distanceToLight.w = 1.0; // We also repurpose vShadowCoord to hold the distance in world space from the // light to the vertex. This value will be interpolated correctly in the fragment shader. vShadowCoord[ i ] = distanceToLight; } else { vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; } #else vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; #endif } #endif
\ No newline at end of file
#ifdef USE_SHADOWMAP
for( int i = 0; i < MAX_SHADOWS; i ++ ) {
#if defined(POINT_LIGHT_SHADOWS)
// if shadowDarkness[ i ] < 0.0, that means we have a point light with a cube
// shadow map
if( shadowDarkness[ i ] < 0.0 ) {
// When we have a point light, the @shadowMatrix uniform is used to store
// the inverse of the view matrix, so that we can get the world-space
// position of the light.
vec4 lightPositionWorld = ( shadowMatrix[ i ] * vec4( pointLightPosition[ i ], 1.0 ) );
vec4 distanceToLight = worldPosition - lightPositionWorld;
distanceToLight.w = 1.0;
// We also repurpose vShadowCoord to hold the distance in world space from the
// light to the vertex. This value will be interpolated correctly in the fragment shader.
vShadowCoord[ i ] = distanceToLight;
} else {
vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;
}
#else
vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;
#endif
}
#endif
\ No newline at end of file
......@@ -842,7 +842,7 @@ THREE.ShaderLib = {
uniforms: {
"lightPos": { type: "v3", value: new THREE.Vector3(0,0,0) }
"lightPos": { type: "v3", value: new THREE.Vector3( 0, 0, 0 ) }
},
......@@ -867,7 +867,7 @@ THREE.ShaderLib = {
"}"
].join("\n"),
].join( "\n" ),
fragmentShader: [
......@@ -885,8 +885,8 @@ THREE.ShaderLib = {
" res -= res.xxyz * bitMsk;",
" return res; ",
"}",
"}",
"float unpack1K ( vec4 color ) {",
" const vec4 bitSh = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
......@@ -900,8 +900,9 @@ THREE.ShaderLib = {
"}"
].join("\n")
].join( "\n" )
}
};
......@@ -117,15 +117,13 @@ THREE.UniformsLib = {
shadowmap: {
"shadowCube": { type: "tv", value: [] },
"shadowMap": { type: "tv", value: [] },
"shadowMapSize": { type: "v2v", value: [] },
"shadowBias" : { type: "fv1", value: [] },
"shadowDarkness": { type: "fv1", value: [] },
"shadowMatrix" : { type: "m4v", value: [] },
"shadowMatrix" : { type: "m4v", value: [] }
}
......
......@@ -21,13 +21,16 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
_distanceMaterial, _distanceMaterialMorph, _distanceMaterialSkin, _distanceMaterialMorphSkin;
var cubeDirections = [new THREE.Vector3(1,0,0), new THREE.Vector3(-1,0,0), new THREE.Vector3(0,1,0),
new THREE.Vector3(0,-1,0), new THREE.Vector3(0,0,1), new THREE.Vector3(0,0,-1)];
var cubeDirections = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( - 1, 0, 0 ), new THREE.Vector3( 0, 0, 1 ),
new THREE.Vector3( 0, 0, - 1 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, - 1, 0 ) ];
var cubeUps = [new THREE.Vector3(0,-1,0), new THREE.Vector3(0,-1,0), new THREE.Vector3(0,0,1),
new THREE.Vector3(0,0,-1), new THREE.Vector3(0,-1,0), new THREE.Vector3(0,-1,0)];
var cubeUps = [ new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ),
new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 0, 0, - 1 ) ];
var _vector4 = new THREE.Vector4();
var cube2DViewPorts = [ new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(),
new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4() ];
var _vector4 = new THREE.Vector4();
// init
......@@ -118,7 +121,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
this.render = function ( scene ) {
var faceCount, isCube;
var faceCount, isPointLight;
if ( scope.enabled === false ) return;
if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
......@@ -152,12 +155,28 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
if ( light instanceof THREE.PointLight ) {
faceCount = 6;
isCube = true;
isPointLight = true;
var vpWidth = light.shadowMapWidth / 4.0;
var vpHeight = light.shadowMapHeight / 2.0;
// positive X
cube2DViewPorts[ 0 ].set( vpWidth * 2, 0, vpWidth, vpHeight );
// negative X
cube2DViewPorts[ 1 ].set( 0, 0, vpWidth, vpHeight );
// positive Z
cube2DViewPorts[ 2 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
// negative Z
cube2DViewPorts[ 3 ].set( vpWidth, 0, vpWidth, vpHeight );
// positive Y
cube2DViewPorts[ 4 ].set( 0, vpHeight, vpWidth, vpHeight );
// negative Y
cube2DViewPorts[ 5 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
} else {
faceCount = 1;
isCube = false;
isPointLight = false;
}
......@@ -167,7 +186,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var shadowFilter = THREE.LinearFilter;
if ( scope.type === THREE.PCFSoftShadowMap ) {
if ( scope.type === THREE.PCFSoftShadowMap || light instanceof THREE.PointLight ) {
shadowFilter = THREE.NearestFilter;
......@@ -175,17 +194,8 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
if ( isCube ) {
light.shadowMap = new THREE.WebGLRenderTargetCube( light.shadowMapWidth, light.shadowMapWidth, pars );
light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapWidth );
} else {
light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
}
light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
light.shadowMatrix = new THREE.Matrix4();
......@@ -203,7 +213,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
} else {
light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );
light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, 1.0, light.shadowCameraNear, light.shadowCameraFar );
}
......@@ -225,27 +235,34 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var shadowCamera = light.shadowCamera;
_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
shadowCamera.position.copy( _lightPositionWorld);
shadowCamera.position.copy( _lightPositionWorld );
// save the existing viewport so it can be restored later
_renderer.getViewport( _vector4 );
_renderer.setRenderTarget( shadowMap );
_renderer.clear();
// render shadow map for each cube face (if omni-directional) or
// run a single pass if not
for ( var face = 0; face < faceCount; face++ ){
if( isCube ){
for ( var face = 0; face < faceCount; face ++ ) {
if ( isPointLight ) {
_lookTarget.copy( shadowCamera.position );
_lookTarget.add( cubeDirections[face] );
shadowCamera.up.copy( cubeUps[face] );
shadowCamera.lookAt( _lookTarget );
shadowMap.activeCubeFace = face;
_lookTarget.add( cubeDirections[ face ] );
shadowCamera.up.copy( cubeUps[ face ] );
shadowCamera.lookAt( _lookTarget );
var vpDimensions = cube2DViewPorts[ face ];
_renderer.setViewport( vpDimensions.x, vpDimensions.y, vpDimensions.z, vpDimensions.w );
} else {
_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
shadowCamera.lookAt( _lookTarget );
}
}
shadowCamera.updateMatrixWorld();
shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
......@@ -270,17 +287,13 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
_frustum.setFromMatrix( _projScreenMatrix );
// render shadow map
_renderer.setRenderTarget( shadowMap );
_renderer.clear();
// set object matrices & frustum culling
_renderList.length = 0;
projectObject( scene, shadowCamera );
// render shadow map
// render regular objects
for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) {
......@@ -301,8 +314,8 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
if ( groupMaterial.visible === true ) {
var depthMaterial = getDepthMaterial( object, groupMaterial, isCube, _lightPositionWorld );
_renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial , object, group );
var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
_renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, group );
}
......@@ -310,7 +323,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
} else {
var depthMaterial = getDepthMaterial( object, material, isCube, _lightPosition);
var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
_renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, null );
}
......@@ -318,6 +331,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
}
}
}
// restore GL state
......@@ -334,13 +348,15 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
}
_renderer.setViewport( _vector4.x, _vector4.y, _vector4.z, _vector4.w );
_renderer.resetGLState();
scope.needsUpdate = false;
};
function getDepthMaterial( object, material, isCube, lightPositionWorld) {
function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {
var geometry = object.geometry;
......@@ -350,27 +366,29 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var newMaterial;
var depthMaterial = _depthMaterial;
var depthMaterialMorph = _depthMaterialMorph;
var depthMaterialSkin = _depthMaterialSkin;
var depthMaterialMorph = _depthMaterialMorph;
var depthMaterialSkin = _depthMaterialSkin;
var depthMaterialMorphSkin = _depthMaterialMorphSkin;
if ( isCube ){
if ( isPointLight ) {
depthMaterial = _distanceMaterial;
depthMaterialMorph = _distanceMaterialMorph;
depthMaterialSkin = _distanceMaterialSkin;
depthMaterialMorph = _distanceMaterialMorph;
depthMaterialSkin = _distanceMaterialSkin;
depthMaterialMorphSkin = _distanceMaterialMorphSkin;
}
if ( object.customDepthMaterial || object.customDistanceMaterial ) {
if ( isCube ){
if ( isPointLight ) {
newMaterial = object.customDistanceMaterial;
} else {
newMaterial = object.customDepthMaterial;
}
} else if ( useSkinning ) {
......@@ -391,12 +409,14 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
newMaterial.wireframe = material.wireframe;
newMaterial.wireframeLinewidth = material.wireframeLinewidth;
if ( isCube ){
if ( isPointLight ) {
if( newMaterial.uniforms.lightPos ){
if ( newMaterial.uniforms.lightPos ) {
newMaterial.uniforms.lightPos.value.copy( lightPositionWorld );
}
}
return newMaterial;
......@@ -414,6 +434,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var material = object.material;
if ( material.visible === true ) {
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
_renderList.push( object );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册