Last active
May 11, 2020 04:50
-
-
Save qoh/6729709 to your computer and use it in GitHub Desktop.
Replace shaders/renderCsm_frag.glsl with this and re-apply your shader settings.
Read notes in the code before complaining.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 120 | |
#extension GL_EXT_texture_array : require | |
#extension GL_EXT_texture_array : enable | |
// NOTE: this is a development release - expect tons of bugs | |
// this /will/ decrease your fps roughly (soft_distance*2/soft_stepsize+1)³ times, | |
// depends on cost of individual operations | |
// soft_distance is the space to spread out shadow blurring samples over | |
// soft_stepsize controls how close each sample is | |
const float soft_distance = 0.05f; | |
const float soft_stepsize = 0.025f; | |
// Varying. | |
varying vec4 vPos; | |
varying vec3 worldNormal; | |
varying vec3 worldPos; | |
// Global directional light uniforms. | |
uniform vec4 dirLightDir; | |
uniform vec4 dirLightColor; | |
uniform vec4 dirLightAmbient; | |
uniform vec4 dirShadowColor; | |
// Misc uniforms. | |
uniform vec3 camPos; | |
uniform mat4 obj2World; | |
uniform mat4 world2Cam; | |
uniform int isParticle; | |
uniform int doColorMultiply; | |
uniform int glow; | |
uniform sampler2DArray stex; | |
uniform sampler2D tex; | |
// Surface calculations, including specular power. | |
varying vec2 texCoord; | |
vec4 viewDelta; | |
float specular; | |
float NdotL; | |
vec3 reflectVec; | |
void calculateSurface(vec4 color, inout vec4 albedo) | |
{ | |
viewDelta.xyz = worldPos - camPos; | |
viewDelta.w = length(viewDelta.xyz); | |
viewDelta.xyz = -normalize(viewDelta.xyz); | |
vec4 texAlbedo = texture2D(tex, texCoord); | |
albedo.rgb = mix(color.rgb, texAlbedo.rgb, texAlbedo.a); | |
if(doColorMultiply == 1) | |
albedo *= gl_Color; | |
albedo.a = color.a; | |
NdotL = max(dot(worldNormal, dirLightDir.xyz), 0.0f); | |
reflectVec = normalize(reflect(-dirLightDir.xyz, worldNormal)); | |
specular = pow(max(dot(reflectVec, viewDelta.xyz), 0.0f), 12.0f) * length(texAlbedo.rgb); | |
//albedo.rgb = normalize(viewDelta.xyz); | |
} | |
// Fogging. | |
uniform vec4 fogBaseColor; | |
uniform vec4 fogConsts; | |
uniform sampler2D fogTex; | |
varying vec2 fogCoords; | |
void applyFog(inout vec4 albedo) | |
{ | |
// Calculate fog. | |
vec4 fogColor = texture2D(fogTex, fogCoords) * fogBaseColor; | |
// Blend it. | |
albedo = mix(albedo, fogColor, fogColor.a); | |
} | |
// Shadowing | |
uniform vec4 far_d; | |
uniform vec2 texSize; // x - size, y - 1/size | |
uniform vec4 zScale; | |
uniform int shadowSplitCount; | |
void calculateShadowCoords(in vec3 offset, inout vec4 shadow_coordA, inout vec4 shadow_coordB, out float blend) | |
{ | |
vec4 rPos = vPos + vec4(offset, 0.0f); | |
int index = 3; | |
// NOTE: fudgeKey controls the shadow acne <-> peter panning factor | |
// make this as precise as possible, a too low or too high value /will/ be terribly ugly | |
// default value is 0.1f, tested values are 0.55f, 0.175f (seems good for now) | |
float fudgeKey = 0.175f; | |
float fudgeFactorA = 0.0f; | |
float fudgeFactorB = 0.0f; | |
fudgeFactorA = 4.0f * fudgeKey / zScale.w; | |
fudgeFactorB = 4.0f * fudgeKey / zScale.w; | |
blend = 0.0f; | |
// find the appropriate depth map to look up in based on the depth of this fragment | |
if(rPos.y < far_d.x) | |
{ | |
index = 0; | |
if(shadowSplitCount > 1) | |
blend = clamp( (rPos.y - (far_d.x * 0.9f)) / (far_d.x * 0.1f), 0.0f, 1.0f); | |
fudgeFactorA = fudgeKey / zScale.x; | |
fudgeFactorB = 2.0f * fudgeKey / zScale.y; | |
} | |
else if(rPos.y < far_d.y) | |
{ | |
index = 1; | |
if(shadowSplitCount > 2) | |
blend = clamp( (rPos.y - (far_d.y * 0.9f)) / (far_d.x * 0.1f), 0.0f, 1.0f); | |
fudgeFactorA = 2.0f * fudgeKey / zScale.y; | |
fudgeFactorB = 3.0f * fudgeKey / zScale.z; | |
} | |
else if(rPos.y < far_d.z) | |
{ | |
index = 2; | |
if(shadowSplitCount > 3) | |
blend = clamp( (rPos.y - (far_d.z * 0.9f)) / (far_d.x * 0.1f), 0.0f, 1.0f); | |
fudgeFactorA = 3.0f * fudgeKey / zScale.z; | |
fudgeFactorB = 4.0f * fudgeKey / zScale.w; | |
} | |
// transform this fragment's position from view space to scaled light clip space | |
// such that the xy coordinates are in [0;1] | |
// note there is no need to divide by w for orthogonal light sources | |
shadow_coordA = gl_TextureMatrix[index]*rPos; | |
shadow_coordA.w = shadow_coordA.z - fudgeFactorA; // Figure the input coordinate for PCF sampling if appropriate. | |
shadow_coordA.z = float(index); // Encode the layer to sample. | |
//don't have to set second shadow coord if we're not blending | |
if(blend > 0.0f) | |
{ | |
shadow_coordB = gl_TextureMatrix[index + 1]*rPos; | |
shadow_coordB.w = shadow_coordB.z - fudgeFactorB; | |
shadow_coordB.z = float(index + 1); | |
} | |
} | |
// Point lighting | |
uniform vec4 pointLightPos0; | |
uniform vec4 pointLightColor0; | |
uniform float pointLightRadius0; | |
uniform vec4 pointLightPos1; | |
uniform vec4 pointLightColor1; | |
uniform float pointLightRadius1; | |
uniform vec4 pointLightPos2; | |
uniform vec4 pointLightColor2; | |
uniform float pointLightRadius2; | |
uniform vec4 pointLightPos3; | |
uniform vec4 pointLightColor3; | |
uniform float pointLightRadius3; | |
uniform vec4 pointLightPos4; | |
uniform vec4 pointLightColor4; | |
uniform float pointLightRadius4; | |
uniform vec4 pointLightPos5; | |
uniform vec4 pointLightColor5; | |
uniform float pointLightRadius5; | |
uniform vec4 pointLightPos6; | |
uniform vec4 pointLightColor6; | |
uniform float pointLightRadius6; | |
uniform vec4 pointLightPos7; | |
uniform vec4 pointLightColor7; | |
uniform float pointLightRadius7; | |
vec4 accumulatePointLights() | |
{ | |
vec4 pointLightTotal = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
vec3 lightDelta = vec3(0.0f, 0.0f, 0.0f); | |
float lightDot = 0.0f; | |
float ratio = 0.0f; | |
// Calculate effects of the 8 point lights. | |
lightDelta = worldPos.xyz - pointLightPos0.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius0); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor0.xyz; | |
lightDelta = worldPos.xyz - pointLightPos1.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius1); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor1.xyz; | |
lightDelta = worldPos.xyz - pointLightPos2.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius2); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor2.xyz; | |
lightDelta = worldPos.xyz - pointLightPos3.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius3); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor3.xyz; | |
lightDelta = worldPos.xyz - pointLightPos4.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius4); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor4.xyz; | |
lightDelta = worldPos.xyz - pointLightPos5.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius5); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor5.xyz; | |
lightDelta = worldPos.xyz - pointLightPos6.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius6); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor6.xyz; | |
lightDelta = worldPos.xyz - pointLightPos7.xyz; | |
lightDot = max(dot(-normalize(lightDelta), worldNormal), 0.0f); | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius7); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * lightDot * pointLightColor7.xyz; | |
return pointLightTotal; | |
} | |
vec4 accumulateParticlePointLights() | |
{ | |
vec4 pointLightTotal = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
vec3 lightDelta = vec3(0.0f, 0.0f, 0.0f); | |
float ratio = 0.0f; | |
// Calculate effects of the 8 point lights. | |
lightDelta = worldPos.xyz - pointLightPos0.xyz; | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius0); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * pointLightColor0.xyz; | |
lightDelta = worldPos.xyz - pointLightPos1.xyz; | |
ratio = 1.0f - (length(lightDelta) / pointLightRadius1); | |
ratio = ratio * ratio * ratio * 0.4f; | |
ratio = max(ratio, 0.0f); | |
pointLightTotal.xyz += ratio * pointLightColor1.xyz; | |
return pointLightTotal; | |
} | |
// Combine specular and direct lighting terms. | |
// note: if we make combinedColor "out" only, it throws a potentially uninitialized value warning, so we've made it inout | |
void applyLighting(inout vec4 combinedColor, vec4 albedo, float occlusionFactor) | |
{ | |
//large normal means glowing object | |
if(glow == 1 || (worldNormal.x + worldNormal.y + worldNormal.z) > 2.0f) | |
{ | |
combinedColor = albedo; | |
return; | |
} | |
vec4 dirLightSpecular = occlusionFactor * specular * dirLightColor; | |
dirLightSpecular *= 0.5f; //arbitrary adjustment | |
vec4 dirLightDirect = ((NdotL * dirLightColor) * occlusionFactor) + (dirLightAmbient * occlusionFactor) + (dirShadowColor * (1.0f - occlusionFactor)); | |
if(NdotL <= 0.04f) | |
{ | |
dirLightDirect = dirShadowColor; | |
dirLightSpecular = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
} | |
else if(NdotL <= 0.1) | |
{ | |
float val = (NdotL - 0.04f) / (0.1f - 0.04f); | |
dirLightDirect = (dirLightDirect * val) + (dirShadowColor * (1.0f - val)); | |
dirLightSpecular = dirLightSpecular * val; | |
} | |
dirLightDirect += accumulatePointLights(); | |
dirLightSpecular.a = length(dirLightSpecular.rgb); | |
dirLightDirect.a *= min(occlusionFactor + 0.75f, 1.0f); | |
combinedColor.rgb = dirLightDirect.rgb * albedo.rgb; | |
combinedColor.a = albedo.a; | |
combinedColor += dirLightSpecular; | |
} | |
float doShadowCoef(vec3 offset) { | |
float blend = 0.0f; | |
vec4 shadow_coordA = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
vec4 shadow_coordB = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
calculateShadowCoords(offset, shadow_coordA, shadow_coordB, blend); | |
float shadowA = texture2DArray(stex, shadow_coordA.xyz).x; // get the stored depth | |
float diffA = shadowA - shadow_coordA.w; // get the difference of the stored depth and the distance of this fragment to the light | |
if(diffA > 0.0f) | |
diffA = 1.0f; | |
else | |
diffA = 0.0f; | |
if(blend > 0.0f) | |
{ | |
float shadowB = texture2DArray(stex, shadow_coordB.xyz).x; // get the stored depth | |
float diffB = shadowB - shadow_coordB.w; // get the difference of the stored depth and the distance of this fragment to the light | |
if(diffB > 0.0f) | |
diffB = 1.0f; | |
else | |
diffB = 0.0f; | |
float total = (diffB * blend) + (diffA * (1.0f - blend)); | |
total = clamp(total, 0.0f, 1.0f); | |
return total; | |
} | |
else | |
{ | |
return diffA; | |
} | |
} | |
float shadowCoef() | |
{ | |
// NOTE: uncomment to completely disable soft shadows | |
// return doShadowCoef(vec3(0.0f, 0.0f, 0.0f)); | |
float total = 0.0f; | |
int samples = 0; | |
for (float x = -soft_distance; x <= soft_distance; x += soft_stepsize) { | |
for (float y = -soft_distance; y <= soft_distance; y += soft_stepsize) { | |
for (float z = -soft_distance; z <= soft_distance; z += soft_stepsize) { | |
total += doShadowCoef(vec3(x, y, z)); | |
samples += 1; | |
} | |
} | |
} | |
return total / samples; | |
} | |
void main() | |
{ | |
vec4 albedo = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
calculateSurface(gl_Color, albedo); | |
float occlusionFactor = 0.0f; | |
if(NdotL > -0.01f) | |
{ | |
if(shadowSplitCount <= 0) | |
occlusionFactor = 1.0f; | |
else | |
occlusionFactor = shadowCoef(); | |
} | |
// Apply lighting and fog. | |
vec4 fragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f); | |
if(isParticle == 1) | |
{ | |
vec4 texAlbedo = texture2D(tex, texCoord); | |
vec4 dirLightDirect = (dirLightColor * occlusionFactor) + (dirLightAmbient * occlusionFactor) + (dirShadowColor * (1.0f - occlusionFactor)); | |
vec4 plt = accumulateParticlePointLights(); | |
vec4 lightTotal = dirLightDirect + plt; | |
lightTotal.x = clamp(lightTotal.x, 0.0f, 1.2f); | |
lightTotal.y = clamp(lightTotal.y, 0.0f, 1.2f); | |
lightTotal.z = clamp(lightTotal.z, 0.0f, 1.2f); | |
fragColor = texAlbedo * gl_Color * lightTotal; | |
applyFog(fragColor); | |
fragColor.a = texAlbedo.a * gl_Color.a; | |
} | |
else | |
{ | |
applyLighting(fragColor, albedo, occlusionFactor); | |
applyFog(fragColor); | |
} | |
// Uncomment to viz depth in B. | |
//fragColor.z = vPos.y * 0.01f; | |
gl_FragColor = fragColor; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment