提交 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 ) {
if ( object.receiveShadow && ! material._shadowPass ) {
refreshUniformsShadow( m_uniforms, lights );
refreshUniformsShadow( m_uniforms, lights, camera );
}
......@@ -1953,7 +1953,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
function refreshUniformsShadow ( uniforms, lights ) {
function refreshUniformsShadow ( uniforms, lights, camera ) {
if ( uniforms.shadowMatrix ) {
......@@ -1971,28 +1971,27 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.shadowCube.value[ j ] = light.shadowMap;
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 {
uniforms.shadowMap.value[ j ] = light.shadowMap;
uniforms.isShadowCube.value[ j ] = 0;
uniforms.shadowCube.value[ j ] = null;
uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
}
uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
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 ++;
}
......
......@@ -3,3 +3,9 @@
varying vec3 vWorldPosition;
#endif
#if MAX_POINT_LIGHTS > 0
uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];
#endif
......@@ -13,11 +13,19 @@
vec3 shadowColor = vec3( 1.0 );
for( int i = 0; i < MAX_SHADOWS; i ++ ) {
vec3 lightToPosition = vWPosition[ i ].xyz - shadowLightPosition[ i ];
vec3 lightToFragment = normalize( lightToPosition );
float distanceToLight = length( lightToPosition );
int currentIsCube = isShadowCube[ i ];
// to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine
// whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light)
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;
vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;
float shadow = 0.0;
......@@ -31,14 +39,14 @@
bool frustumTest = all( frustumTestVec );
if ( frustumTest || currentIsCube == 1) {
if ( frustumTest || isPointLight ) {
shadowCoord.z += shadowBias[ i ];
#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 {
// Percentage-close filtering
......@@ -106,13 +114,13 @@
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 )
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 {
......@@ -165,15 +173,15 @@
shadow = dot( shadowValues, vec4( 1.0 ) );
}
shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );
shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );
#else
if( currentIsCube == 1 ){
if( isPointLight ){
float dist = getCubeMapFloat( shadowCube[ i ], lightToFragment );
if ( distanceToLight >= dist)
shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );
float dist = getCubeShadowMapFloat( i, normalize( lightToPosition ) );
if ( length( lightToPosition ) >= dist)
shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
} else {
......@@ -184,11 +192,11 @@
// 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
// shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );
// shadowColor = min( shadowColor, vec3( realShadowDarkness ) );
}
#endif
......
#ifdef USE_SHADOWMAP
uniform int isShadowCube[ MAX_SHADOWS ];
uniform samplerCube shadowCube[ MAX_SHADOWS ];
uniform sampler2D shadowMap[ MAX_SHADOWS ];
uniform vec2 shadowMapSize[ MAX_SHADOWS ];
......@@ -8,10 +7,7 @@
uniform float shadowDarkness[ MAX_SHADOWS ];
uniform float shadowBias[ MAX_SHADOWS ];
uniform vec3 shadowLightPosition[ MAX_SHADOWS ];
varying vec4 vShadowCoord[ MAX_SHADOWS ];
varying vec4 vWPosition[ MAX_SHADOWS ];
float unpackDepth( const in vec4 rgba_depth ) {
......@@ -21,25 +17,25 @@
}
vec4 pack1K (float depth) {
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);
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) {
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);
return dot(color, bitSh) * 1000.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;
}
vec3 gridSamplingDisk[20];
vec3 gridSamplingDisk[ 20 ];
int gridSamplingInitialized = 0;
void initGridSamplingDisk(){
......@@ -67,17 +63,35 @@
}
float getCubeMapFloat(in samplerCube cube, in vec3 baseDirection){
float getCubeShadowMapFloat( const in int cubeIndex, in vec3 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;
}
}
vec4 data = textureCube(cube, baseDirection);
float dist = unpack1K( data );
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();
gridSamplingInitialized = 1;
......@@ -89,17 +103,17 @@
float numSamples = 0.0;
float shadowFactor = 0.0;
float dist = getCubeMapFloat(cube, baseDirection);
if ( curDistance >= dist)
float dist = getCubeShadowMapFloat( cubeIndex, baseDirection );
if ( curDistance >= dist )
shadowFactor += 1.0;
numSamples += 1.0;
// evaluate each sampling direction
for(int i=0; i<20; i++){
for( int i = 0; i < 20; i++ ){
vec3 offset = gridSamplingDisk[i] * diskRadius * texSize;
dist = getCubeMapFloat(cube, vec3(baseDirection + offset));
if ( curDistance >= dist)
vec3 offset = gridSamplingDisk[ i ] * diskRadius * texSize;
dist = getCubeShadowMapFloat( cubeIndex, vec3( baseDirection + offset ) );
if ( curDistance >= dist )
shadowFactor += 1.0;
numSamples += 1.0;
......@@ -107,6 +121,7 @@
shadowFactor /= numSamples;
return shadowFactor;
}
#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
\ 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 ++ ) { vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; vWPosition[ i ] = worldPosition; } #endif
\ No newline at end of file
#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
......
......@@ -856,21 +856,14 @@ THREE.ShaderLib = {
"void main() {",
"#ifdef USE_SKINNING",
" vWorldPosition = modelMatrix * skinned;",
"#else",
" vWorldPosition = modelMatrix * vec4( position, 1.0 );",
"#endif",
THREE.ShaderChunk[ "skinbase_vertex" ],
THREE.ShaderChunk[ "begin_vertex" ],
THREE.ShaderChunk[ "morphtarget_vertex" ],
THREE.ShaderChunk[ "skinning_vertex" ],
THREE.ShaderChunk[ "project_vertex" ],
THREE.ShaderChunk[ "worldpos_vertex" ],
"vWorldPosition = worldPosition;",
"}"
......
......@@ -117,7 +117,6 @@ THREE.UniformsLib = {
shadowmap: {
"isShadowCube": { type: "iv1", value: [] },
"shadowCube": { type: "tv", value: [] },
"shadowMap": { type: "tv", value: [] },
......@@ -127,7 +126,6 @@ THREE.UniformsLib = {
"shadowDarkness": { type: "fv1", value: [] },
"shadowMatrix" : { type: "m4v", value: [] },
"shadowLightPosition" : { type: "fv", value: [] }
}
......
......@@ -14,7 +14,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
_max = new THREE.Vector3(),
_lookTarget = new THREE.Vector3(),
_lightPosition = new THREE.Vector3(),
_lightPositionWorld = new THREE.Vector3(),
_renderList = [];
......@@ -224,8 +224,8 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
var shadowMatrix = light.shadowMatrix;
var shadowCamera = light.shadowCamera;
_lightPosition.setFromMatrixPosition( light.matrixWorld );
shadowCamera.position.copy( _lightPosition);
_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
shadowCamera.position.copy( _lightPositionWorld);
// render shadow map for each cube face (if omni-directional) or
// run a single pass if not
......@@ -306,7 +306,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
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 );
}
......@@ -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;
......@@ -400,7 +400,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
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.
先完成此消息的编辑!
想要评论请 注册