126 lines
3.5 KiB
GLSL
126 lines
3.5 KiB
GLSL
|
#version 110
|
||
|
/*
|
||
|
* This file follow the Stackoverflow content license: CC BY-SA 4.0,
|
||
|
* since it's based on Prashanth N Udupa's work: https://stackoverflow.com/questions/35134270/how-to-use-qopenglframebufferobject-for-shadow-mapping
|
||
|
*/
|
||
|
struct directional_light
|
||
|
{
|
||
|
vec3 direction;
|
||
|
vec3 eye;
|
||
|
vec4 ambient;
|
||
|
vec4 diffuse;
|
||
|
vec4 specular;
|
||
|
};
|
||
|
|
||
|
struct material_properties
|
||
|
{
|
||
|
vec4 ambient;
|
||
|
vec4 diffuse;
|
||
|
vec4 specular;
|
||
|
float specularPower;
|
||
|
float opacity;
|
||
|
float brightness;
|
||
|
};
|
||
|
|
||
|
uniform directional_light qt_Light;
|
||
|
uniform material_properties qt_Material;
|
||
|
uniform sampler2D qt_ShadowMap;
|
||
|
uniform bool qt_ShadowEnabled;
|
||
|
|
||
|
varying vec4 v_Normal;
|
||
|
varying vec4 v_ShadowPosition;
|
||
|
|
||
|
const float c_zNear = 0.1;
|
||
|
const float c_ZFar = 1000.0;
|
||
|
const float c_zero = 0.0;
|
||
|
const float c_one = 1.0;
|
||
|
const float c_half = 0.5;
|
||
|
const float textureSize = 2048.0;
|
||
|
const vec2 texelSize = 1.0 / vec2(textureSize,textureSize);
|
||
|
|
||
|
vec4 evaluateLightMaterialColor(in vec4 normal)
|
||
|
{
|
||
|
// Start with black color
|
||
|
vec3 finalColor = vec3(c_zero, c_zero, c_zero);
|
||
|
|
||
|
// Upgrade black color to the base ambient color
|
||
|
finalColor += qt_Light.ambient.rgb * qt_Material.ambient.rgb;
|
||
|
|
||
|
// Add diffuse component to it
|
||
|
vec4 lightDir = vec4( normalize(qt_Light.direction), 0.0 );
|
||
|
float diffuseFactor = max( c_zero, dot(lightDir, normal) );
|
||
|
if(diffuseFactor > c_zero)
|
||
|
{
|
||
|
finalColor += qt_Light.diffuse.rgb *
|
||
|
qt_Material.diffuse.rgb *
|
||
|
diffuseFactor *
|
||
|
qt_Material.brightness;
|
||
|
}
|
||
|
|
||
|
// Add specular component to it
|
||
|
const vec3 blackColor = vec3(c_zero, c_zero, c_zero);
|
||
|
if( !(qt_Material.specular.rgb == blackColor || qt_Light.specular.rgb == blackColor || qt_Material.specularPower == c_zero) )
|
||
|
{
|
||
|
vec4 viewDir = vec4( normalize(qt_Light.eye), 0.0 );
|
||
|
vec4 reflectionVec = reflect(lightDir, normal);
|
||
|
float specularFactor = max( c_zero, dot(reflectionVec, -viewDir) );
|
||
|
if(specularFactor > c_zero)
|
||
|
{
|
||
|
specularFactor = pow( specularFactor, qt_Material.specularPower );
|
||
|
finalColor += qt_Light.specular.rgb *
|
||
|
qt_Material.specular.rgb *
|
||
|
specularFactor;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// All done!
|
||
|
return vec4( finalColor, qt_Material.opacity );
|
||
|
}
|
||
|
|
||
|
|
||
|
float linearizeDepth(float depth)
|
||
|
{
|
||
|
float z = depth * 2.0 - 1.0; // Back to NDC
|
||
|
return (2.0 * c_zNear * c_ZFar) / (c_ZFar + c_zNear - z * (c_ZFar - c_zNear));
|
||
|
}
|
||
|
|
||
|
float evaluateShadow(in vec4 shadowPos)
|
||
|
{
|
||
|
vec3 shadowCoords = shadowPos.xyz / shadowPos.w;
|
||
|
shadowCoords = shadowCoords * c_half + c_half;
|
||
|
if(shadowCoords.z > c_one)
|
||
|
return c_one;
|
||
|
|
||
|
float currentDepth = shadowPos.z;
|
||
|
|
||
|
float shadow = c_zero;
|
||
|
const int sampleRange = 2;
|
||
|
const float nrSamples = (2.0*float(sampleRange) + 1.0)*(2.0*float(sampleRange) + 1.0);
|
||
|
for(int x=-sampleRange; x<=sampleRange; x++)
|
||
|
{
|
||
|
for(int y=-sampleRange; y<=sampleRange; y++)
|
||
|
{
|
||
|
vec2 pcfCoords = shadowCoords.xy + vec2(x,y)*texelSize;
|
||
|
float pcfDepth = linearizeDepth( texture2D(qt_ShadowMap, pcfCoords).r );
|
||
|
shadow += (currentDepth < pcfDepth) ? c_one : c_half;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
shadow /= nrSamples;
|
||
|
|
||
|
return shadow;
|
||
|
}
|
||
|
|
||
|
void main(void)
|
||
|
{
|
||
|
vec4 lmColor = evaluateLightMaterialColor(v_Normal);
|
||
|
if(qt_ShadowEnabled == true)
|
||
|
{
|
||
|
float shadow = evaluateShadow(v_ShadowPosition);
|
||
|
gl_FragColor = vec4(lmColor.xyz * shadow, qt_Material.opacity);
|
||
|
}
|
||
|
else
|
||
|
gl_FragColor = lmColor;
|
||
|
}
|
||
|
|