phoenix-firestorm/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl

158 lines
4.2 KiB
GLSL

/**
* @file class3/deferred/shadowUtil.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2007, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
uniform sampler2D shadowMap0;
uniform sampler2D shadowMap1;
uniform sampler2D shadowMap2;
uniform sampler2D shadowMap3;
uniform sampler2D shadowMap4;
uniform sampler2D shadowMap5;
uniform vec3 sun_dir;
uniform vec3 moon_dir;
uniform vec2 shadow_res;
uniform vec2 proj_shadow_res;
uniform mat4 shadow_matrix[6];
uniform vec4 shadow_clip;
uniform float shadow_bias;
uniform float spot_shadow_bias;
uniform float spot_shadow_offset;
float getDepth(vec2 screenpos);
vec3 getNorm(vec2 screenpos);
vec4 getPosition(vec2 pos_screen);
float ReduceLightBleeding(float p_max, float Amount)
{
return smoothstep(Amount, 1, p_max);
}
float ChebyshevUpperBound(vec2 m, float t, float min_v, float Amount)
{
float p = (t <= m.x) ? 1.0 : 0.0;
float v = m.y - (m.x*m.x);
v = max(v, min_v);
float d = t - m.x;
float p_max = v / (v + d*d);
p_max = ReduceLightBleeding(p_max, Amount);
return max(p, p_max);
}
vec4 computeMoments(float depth, float a)
{
float m1 = depth;
float dx = dFdx(depth);
float dy = dFdy(depth);
float m2 = m1*m1 + 0.25 * a * (dx*dx + dy*dy);
return vec4(m1, m2, a, max(dx, dy));
}
float vsmDirectionalSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix)
{
vec4 lpos = shadowMatrix * stc;
vec4 moments = texture2D(shadowMap, lpos.xy);
return ChebyshevUpperBound(moments.rg, depth - shadow_bias * 256.0f, 0.125, 0.9);
}
float vsmSpotSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix)
{
vec4 lpos = shadowMatrix * stc;
vec4 moments = texture2D(shadowMap, lpos.xy);
lpos.xyz /= lpos.w;
lpos.xy *= 0.5;
lpos.xy += 0.5;
return ChebyshevUpperBound(moments.rg, depth - spot_shadow_bias * 16.0f, 0.125, 0.9);
}
#if VSM_POINT_SHADOWS
float vsmPointSample(float lightDistance, vec3 lightDirection, samplerCube shadow_cube_map)
{
vec4 moments = textureCube(shadow_cube_map, light_direction);
return ChebyshevUpperBound(moments.rg, light_distance, 0.01, 0.25);
}
#endif
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen)
{
if (pos.z < -shadow_clip.w)
{
discard;
}
float depth = getDepth(pos_screen);
vec4 spos = vec4(pos,1.0);
vec4 near_split = shadow_clip*-0.75;
vec4 far_split = shadow_clip*-1.25;
float shadow = 0.0f;
float weight = 1.0;
if (spos.z < near_split.z)
{
shadow += vsmDirectionalSample(spos, depth, shadowMap3, shadow_matrix[3]);
weight += 1.0f;
}
if (spos.z < near_split.y)
{
shadow += vsmDirectionalSample(spos, depth, shadowMap2, shadow_matrix[2]);
weight += 1.0f;
}
if (spos.z < near_split.x)
{
shadow += vsmDirectionalSample(spos, depth, shadowMap1, shadow_matrix[1]);
weight += 1.0f;
}
if (spos.z > far_split.x)
{
shadow += vsmDirectionalSample(spos, depth, shadowMap0, shadow_matrix[0]);
weight += 1.0f;
}
shadow /= weight;
return shadow;
}
float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen)
{
if (pos.z < -shadow_clip.w)
{
discard;
}
float depth = getDepth(pos_screen);
pos += norm * spot_shadow_offset;
return vsmSpotSample(vec4(pos, 1.0), depth, (index == 0) ? shadowMap4 : shadowMap5, shadow_matrix[4 + index]);
}