WebGL PCSS Demo by Borington by Borington (itch.io)
OpenGL核心技术之如何改进Shadow Mapping技术-腾讯游戏学院 (qq.com)
- PCF(Percentage Closer Filtering)
- PCSS(Percentage Closer Soft Shadows)
- 传统的PCF每一次采样过滤耗费很大(每次都要遍历附近的几个点,虽然用了泊松分布,但还是不可避免),PCSS算法基本解决了该问题(通过动态计算采样范围,使用FindBlocker剔除非阴影点)
- 传统的PCF半影不够逼真…PCSS算法通过计算准确的半影范围解决了
顶点着色器
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aVertexTexCoord;
uniform mat4 uPMatrix;
uniform mat4 uMVMatrix;
uniform mat4 uShadowBiasMVP;
uniform mat3 uNMatrix;
uniform sampler2D uSampler;
uniform vec3 uLightPos;
varying float diffuse;
varying vec2 texCoord;
varying vec4 shadowPos;
void main(void) {
shadowPos = uShadowBiasMVP * vec4(aVertexPosition, 1.0); //灯光位置的mvp
//shadowCoord = shadowPos.xyz/shadowPos.w * 0.5 + 0.5;
vec4 mvPos = uMVMatrix* vec4(aVertexPosition, 1.0); //mv
gl_Position = uPMatrix * mvPos ; //projection
vec3 lightDirection = normalize(uLightPos - mvPos.xyz); //指向light
vec3 transformedNormal = normalize(uNMatrix * aVertexNormal); //逆转置矩阵
diffuse = max(dot(transformedNormal, lightDirection), 0.0); //
texCoord = aVertexTexCoord;
}
片元着色器
precision mediump float;
varying float diffuse;
varying vec2 texCoord;
uniform sampler2D uSampler;
uniform sampler2D uShadowSampler;
uniform int uShadowMapSize;
varying vec4 shadowPos;
//float texture2DCompare(sampler2D depths, vec2 uv, float compare){
// vec2 sample = texture2D(depths, uv).rg;
// float depth = (sample.r + sample.g/256.) + 0.01;
// return step(compare, depth);
//}
// compare是灯位置里面的z值
float PCF(sampler2D depths, vec2 size, vec2 uv, float compare) {
float result = 0.0;
float averageDepth = 0.0;
float counter = 0.0;
for(int x = -3; x <= 3; x++) {
for(int y = -3; y <= 3; y++) {
vec2 off = vec2(x, y)/size*3.;
float blockerDepth = texture2D(depths, uv+off).r + 0.005; //贴图里面的z值
counter += step(blockerDepth, compare);
averageDepth += blockerDepth*step(blockerDepth, compare);
}
}
if(counter <= 0.1) {
return 1.;
}
averageDepth = averageDepth/counter;
for(int x = -4; x <= 4; x++) {
for(int y = -4; y <= 4; y++) {
vec2 off = vec2(x, y)/size;
float penumbra_size = 50.*(compare - averageDepth)/5.;
//vec2 sample = texture2D(depths, uv+off*penumbra_size ).rg;
//float depth = (sample.r + sample.g/256.) + 0.005;
float depth = texture2D(depths, uv+off*penumbra_size ).r + 0.005;
result += step(compare, depth);
//result += penumbra_size;
}
}
return result/81.;
}
void main(void) {
vec3 shadowCoord = shadowPos.xyz/shadowPos.w * 0.5 + 0.5; //屏幕空间坐标
float shadow = PCF(uShadowSampler, vec2(uShadowMapSize, uShadowMapSize), shadowCoord.xy, shadowCoord.z);
//gl_FragColor = vec4(vec3(1., 1., 1.).rgb*(shadow + 0.1), 1.);
gl_FragColor = vec4(texture2D(uSampler, texCoord).rgb*(diffuse*shadow + 0.1), 1.);
}