提交 5964cb9b 编写于 作者: M Mark Kellogg 提交者: mkkellogg

Updated point-light shadow mapping code to be more efficient with uniforms and varyings.

上级 ebe6e299
...@@ -1701,7 +1701,7 @@ THREE.WebGLRenderer = function ( parameters ) { ...@@ -1701,7 +1701,7 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( object.receiveShadow && ! material._shadowPass ) { if ( object.receiveShadow && ! material._shadowPass ) {
refreshUniformsShadow( m_uniforms, lights ); refreshUniformsShadow( m_uniforms, lights, camera );
} }
...@@ -1953,7 +1953,7 @@ THREE.WebGLRenderer = function ( parameters ) { ...@@ -1953,7 +1953,7 @@ THREE.WebGLRenderer = function ( parameters ) {
} }
function refreshUniformsShadow ( uniforms, lights ) { function refreshUniformsShadow ( uniforms, lights, camera ) {
if ( uniforms.shadowMatrix ) { if ( uniforms.shadowMatrix ) {
...@@ -1971,28 +1971,27 @@ THREE.WebGLRenderer = function ( parameters ) { ...@@ -1971,28 +1971,27 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.shadowCube.value[ j ] = light.shadowMap; uniforms.shadowCube.value[ j ] = light.shadowMap;
uniforms.shadowMap.value[ j ] = null; uniforms.shadowMap.value[ j ] = null;
uniforms.isShadowCube.value[ j ] = 1;
// for point lights we set the sign of the shadowDarkness uniform to be negative
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
// world-space position of the light in the shader.
uniforms.shadowMatrix.value[ j ] = camera.matrixWorld;
} else { } else {
uniforms.shadowMap.value[ j ] = light.shadowMap; uniforms.shadowMap.value[ j ] = light.shadowMap;
uniforms.isShadowCube.value[ j ] = 0;
uniforms.shadowCube.value[ j ] = null; uniforms.shadowCube.value[ j ] = null;
uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
} }
uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
uniforms.shadowBias.value[ j ] = light.shadowBias; uniforms.shadowBias.value[ j ] = light.shadowBias;
_vector3.setFromMatrixPosition( light.matrixWorld );
uniforms.shadowLightPosition.value[ j * 3 ] = _vector3.x;
uniforms.shadowLightPosition.value[ j * 3 + 1 ] = _vector3.y;
uniforms.shadowLightPosition.value[ j * 3 + 2 ] = _vector3.z;
j ++; j ++;
} }
......
...@@ -3,3 +3,9 @@ ...@@ -3,3 +3,9 @@
varying vec3 vWorldPosition; varying vec3 vWorldPosition;
#endif #endif
#if MAX_POINT_LIGHTS > 0
uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];
#endif
...@@ -13,16 +13,24 @@ ...@@ -13,16 +13,24 @@
vec3 shadowColor = vec3( 1.0 ); vec3 shadowColor = vec3( 1.0 );
for( int i = 0; i < MAX_SHADOWS; i ++ ) { for( int i = 0; i < MAX_SHADOWS; i ++ ) {
vec3 lightToPosition = vWPosition[ i ].xyz - shadowLightPosition[ i ];
vec3 lightToFragment = normalize( lightToPosition ); // to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine
float distanceToLight = length( lightToPosition ); // whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light)
int currentIsCube = isShadowCube[ i ]; bool isPointLight = shadowDarkness[ i ] < 0.0;
// get the real shadow darkness
float realShadowDarkness = abs( shadowDarkness[ i ] );
// 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 cubeTexelSize = 1.0 / shadowMapSize[ i ].x;
vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w; vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;
float shadow = 0.0; float shadow = 0.0;
// if ( something && something ) breaks ATI OpenGL shader compiler // if ( something && something ) breaks ATI OpenGL shader compiler
// if ( all( something, something ) ) using this instead // if ( all( something, something ) ) using this instead
bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
bool inFrustum = all( inFrustumVec ); bool inFrustum = all( inFrustumVec );
...@@ -31,14 +39,14 @@ ...@@ -31,14 +39,14 @@
bool frustumTest = all( frustumTestVec ); bool frustumTest = all( frustumTestVec );
if ( frustumTest || currentIsCube == 1) { if ( frustumTest || isPointLight ) {
shadowCoord.z += shadowBias[ i ]; shadowCoord.z += shadowBias[ i ];
#if defined( SHADOWMAP_TYPE_PCF ) #if defined( SHADOWMAP_TYPE_PCF )
if( currentIsCube == 1 ){ if( isPointLight ){
shadow = sampleCubeShadowMapPCF( shadowCube[ i ], lightToFragment, distanceToLight, cubeTexelSize, 1.5); shadow = sampleCubeShadowMapPCF( i, normalize( lightToPosition ), length( lightToPosition ), cubeTexelSize, 1.5);
} else { } else {
// Percentage-close filtering // Percentage-close filtering
...@@ -106,13 +114,13 @@ ...@@ -106,13 +114,13 @@
if ( fDepth < shadowCoord.z ) shadow += shadowDelta; if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
} }
shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) ); shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );
#elif defined( SHADOWMAP_TYPE_PCF_SOFT ) #elif defined( SHADOWMAP_TYPE_PCF_SOFT )
if( currentIsCube == 1 ){ if( isPointLight ){
shadow = sampleCubeShadowMapPCF( shadowCube[ i ], lightToFragment, distanceToLight, cubeTexelSize, 2.5 ); shadow = sampleCubeShadowMapPCF( i, normalize( lightToPosition ), length( lightToPosition ), cubeTexelSize, 2.5 );
} else { } else {
...@@ -165,15 +173,15 @@ ...@@ -165,15 +173,15 @@
shadow = dot( shadowValues, vec4( 1.0 ) ); shadow = dot( shadowValues, vec4( 1.0 ) );
} }
shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) ); shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );
#else #else
if( currentIsCube == 1 ){ if( isPointLight ){
float dist = getCubeMapFloat( shadowCube[ i ], lightToFragment ); float dist = getCubeShadowMapFloat( i, normalize( lightToPosition ) );
if ( distanceToLight >= dist) if ( length( lightToPosition ) >= dist)
shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] ); shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
} else { } else {
...@@ -184,11 +192,11 @@ ...@@ -184,11 +192,11 @@
// spot with multiple shadows is darker // spot with multiple shadows is darker
shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] ); shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
// spot with multiple shadows has the same color as single shadow spot // spot with multiple shadows has the same color as single shadow spot
// shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) ); // shadowColor = min( shadowColor, vec3( realShadowDarkness ) );
} }
#endif #endif
......
#ifdef USE_SHADOWMAP #ifdef USE_SHADOWMAP
uniform int isShadowCube[ MAX_SHADOWS ];
uniform samplerCube shadowCube[ MAX_SHADOWS ]; uniform samplerCube shadowCube[ MAX_SHADOWS ];
uniform sampler2D shadowMap[ MAX_SHADOWS ]; uniform sampler2D shadowMap[ MAX_SHADOWS ];
uniform vec2 shadowMapSize[ MAX_SHADOWS ]; uniform vec2 shadowMapSize[ MAX_SHADOWS ];
...@@ -8,10 +7,7 @@ ...@@ -8,10 +7,7 @@
uniform float shadowDarkness[ MAX_SHADOWS ]; uniform float shadowDarkness[ MAX_SHADOWS ];
uniform float shadowBias[ MAX_SHADOWS ]; uniform float shadowBias[ MAX_SHADOWS ];
uniform vec3 shadowLightPosition[ MAX_SHADOWS ];
varying vec4 vShadowCoord[ MAX_SHADOWS ]; varying vec4 vShadowCoord[ MAX_SHADOWS ];
varying vec4 vWPosition[ MAX_SHADOWS ];
float unpackDepth( const in vec4 rgba_depth ) { float unpackDepth( const in vec4 rgba_depth ) {
...@@ -21,25 +17,25 @@ ...@@ -21,25 +17,25 @@
} }
vec4 pack1K (float depth) { vec4 pack1K ( float depth ) {
depth /= 1000.0; depth /= 1000.0;
const vec4 bitSh = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.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); const vec4 bitMsk = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );
vec4 res = fract(depth * bitSh); vec4 res = fract( depth * bitSh );
res -= res.xxyz * bitMsk; res -= res.xxyz * bitMsk;
return res; return res;
} }
float unpack1K (vec4 color) { 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); const vec4 bitSh = vec4( 1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0 );
return dot(color, bitSh) * 1000.0; return dot( color, bitSh ) * 1000.0;
} }
vec3 gridSamplingDisk[20]; vec3 gridSamplingDisk[ 20 ];
int gridSamplingInitialized = 0; int gridSamplingInitialized = 0;
void initGridSamplingDisk(){ void initGridSamplingDisk(){
...@@ -67,17 +63,35 @@ ...@@ -67,17 +63,35 @@
} }
float getCubeMapFloat(in samplerCube cube, in vec3 baseDirection){ float getCubeShadowMapFloat( const in int cubeIndex, in vec3 baseDirection ){
vec4 data = textureCube(cube, baseDirection); vec4 data = vec4( 0, 0, 0, 0 );
// This loop may seem silly and unnecessary, but we can't use @cubeIndex to access @shadowCube
// directly, since its bounds are unknown to the compiler. The compiler
// knows the bounds of the loop variable 'i' so we CAN use that to index
// into @shadowCube. The alternative to this is to send the samplerCube directly
// to this function as a parameter, but come drivers don't allow that.
for( int i = 0; i < MAX_SHADOWS; i++ ) {
if( i == cubeIndex ){
data = textureCube(shadowCube[ i ], baseDirection);
break;
}
}
float dist = unpack1K( data ); float dist = unpack1K( data );
return dist; return dist;
} }
float sampleCubeShadowMapPCF(in samplerCube cube, in vec3 baseDirection, in float curDistance, in float texSize, float softness){ float sampleCubeShadowMapPCF( const in int cubeIndex, in vec3 baseDirection, in float curDistance, in float texSize, float softness ){
if( gridSamplingInitialized == 0){ if( gridSamplingInitialized == 0 ){
initGridSamplingDisk(); initGridSamplingDisk();
gridSamplingInitialized = 1; gridSamplingInitialized = 1;
...@@ -89,17 +103,17 @@ ...@@ -89,17 +103,17 @@
float numSamples = 0.0; float numSamples = 0.0;
float shadowFactor = 0.0; float shadowFactor = 0.0;
float dist = getCubeMapFloat(cube, baseDirection); float dist = getCubeShadowMapFloat( cubeIndex, baseDirection );
if ( curDistance >= dist) if ( curDistance >= dist )
shadowFactor += 1.0; shadowFactor += 1.0;
numSamples += 1.0; numSamples += 1.0;
// evaluate each sampling direction // evaluate each sampling direction
for(int i=0; i<20; i++){ for( int i = 0; i < 20; i++ ){
vec3 offset = gridSamplingDisk[i] * diskRadius * texSize; vec3 offset = gridSamplingDisk[ i ] * diskRadius * texSize;
dist = getCubeMapFloat(cube, vec3(baseDirection + offset)); dist = getCubeShadowMapFloat( cubeIndex, vec3( baseDirection + offset ) );
if ( curDistance >= dist) if ( curDistance >= dist )
shadowFactor += 1.0; shadowFactor += 1.0;
numSamples += 1.0; numSamples += 1.0;
...@@ -107,6 +121,7 @@ ...@@ -107,6 +121,7 @@
shadowFactor /= numSamples; shadowFactor /= numSamples;
return shadowFactor; return shadowFactor;
} }
#endif #endif
\ No newline at end of file
#ifdef USE_SHADOWMAP varying vec4 vShadowCoord[ MAX_SHADOWS ]; varying vec4 vWPosition[ MAX_SHADOWS ]; uniform mat4 shadowMatrix[ MAX_SHADOWS ]; uniform vec3 shadowLightPosition[ MAX_SHADOWS ]; #endif #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 \ No newline at end of file
......
#ifdef USE_SHADOWMAP for( int i = 0; i < MAX_SHADOWS; i ++ ) { vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; vWPosition[ i ] = worldPosition; } #endif #ifdef USE_SHADOWMAP for( int i = 0; i < MAX_SHADOWS; i ++ ) { #if MAX_POINT_LIGHTS > 0 // 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 \ No newline at end of file
......
...@@ -856,21 +856,14 @@ THREE.ShaderLib = { ...@@ -856,21 +856,14 @@ THREE.ShaderLib = {
"void main() {", "void main() {",
"#ifdef USE_SKINNING",
" vWorldPosition = modelMatrix * skinned;",
"#else",
" vWorldPosition = modelMatrix * vec4( position, 1.0 );",
"#endif",
THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ],
THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "begin_vertex" ],
THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ],
THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ],
THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "project_vertex" ],
THREE.ShaderChunk[ "worldpos_vertex" ],
"vWorldPosition = worldPosition;",
"}" "}"
......
...@@ -117,7 +117,6 @@ THREE.UniformsLib = { ...@@ -117,7 +117,6 @@ THREE.UniformsLib = {
shadowmap: { shadowmap: {
"isShadowCube": { type: "iv1", value: [] },
"shadowCube": { type: "tv", value: [] }, "shadowCube": { type: "tv", value: [] },
"shadowMap": { type: "tv", value: [] }, "shadowMap": { type: "tv", value: [] },
...@@ -127,7 +126,6 @@ THREE.UniformsLib = { ...@@ -127,7 +126,6 @@ THREE.UniformsLib = {
"shadowDarkness": { type: "fv1", value: [] }, "shadowDarkness": { type: "fv1", value: [] },
"shadowMatrix" : { type: "m4v", value: [] }, "shadowMatrix" : { type: "m4v", value: [] },
"shadowLightPosition" : { type: "fv", value: [] }
} }
......
...@@ -14,7 +14,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { ...@@ -14,7 +14,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
_max = new THREE.Vector3(), _max = new THREE.Vector3(),
_lookTarget = new THREE.Vector3(), _lookTarget = new THREE.Vector3(),
_lightPosition = new THREE.Vector3(), _lightPositionWorld = new THREE.Vector3(),
_renderList = []; _renderList = [];
...@@ -224,8 +224,8 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { ...@@ -224,8 +224,8 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var shadowMatrix = light.shadowMatrix; var shadowMatrix = light.shadowMatrix;
var shadowCamera = light.shadowCamera; var shadowCamera = light.shadowCamera;
_lightPosition.setFromMatrixPosition( light.matrixWorld ); _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
shadowCamera.position.copy( _lightPosition); shadowCamera.position.copy( _lightPositionWorld);
// render shadow map for each cube face (if omni-directional) or // render shadow map for each cube face (if omni-directional) or
// run a single pass if not // run a single pass if not
...@@ -306,7 +306,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { ...@@ -306,7 +306,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
if ( groupMaterial.visible === true ) { if ( groupMaterial.visible === true ) {
var depthMaterial = getDepthMaterial( object, groupMaterial, isCube, _lightPosition ); var depthMaterial = getDepthMaterial( object, groupMaterial, isCube, _lightPositionWorld );
_renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial , object, group ); _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial , object, group );
} }
...@@ -345,7 +345,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { ...@@ -345,7 +345,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
}; };
function getDepthMaterial( object, material, isCube, lightPosition) { function getDepthMaterial( object, material, isCube, lightPositionWorld) {
var geometry = object.geometry; var geometry = object.geometry;
...@@ -400,7 +400,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { ...@@ -400,7 +400,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
if( newMaterial.uniforms.lightPos ){ if( newMaterial.uniforms.lightPos ){
newMaterial.uniforms.lightPos.value.copy( lightPosition ); newMaterial.uniforms.lightPos.value.copy( lightPositionWorld );
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册