fteqw/engine/shaders/glsl/lpp_light.glsl

59 lines
1.7 KiB
GLSL

//this shader is a light shader. ideally drawn with a quad covering the entire region
//the output is contribution from this light (which will be additively blended)
//you can blame Electro for much of the maths in here.
//fixme: no fog
varying vec4 tf;
#ifdef VERTEX_SHADER
void main()
{
tf = ftetransform();
gl_Position = tf;
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0;
uniform vec3 l_lightposition;
uniform mat4 m_invviewprojection;
uniform vec3 l_lightcolour;
uniform float l_lightradius;
vec3 calcLightWorldPos(vec2 screenPos, float depth)
{
vec4 pos;
pos.x = screenPos.x;
pos.y = screenPos.y;
pos.z = depth;
pos.w = 1.0;
pos = m_invviewprojection * pos;
return pos.xyz / pos.w;
}
void main ()
{
vec3 lightColour = l_lightcolour.rgb;
float lightIntensity = 1.0;
float lightAttenuation = l_lightradius; // fixme: just use the light radius for now, use better near/far att math separately once working
float radiusFar = l_lightradius;
float radiusNear = l_lightradius*0.5;
vec2 fc;
fc = tf.xy / tf.w;
vec4 data = texture2D(s_t0, (1.0 + fc) / 2.0);
float depth = data.a;
vec3 norm = data.xyz;
/* calc where the wall that generated this sample came from */
vec3 worldPos = calcLightWorldPos(fc, depth);
/*calc diffuse lighting term*/
vec3 lightDir = l_lightposition - worldPos;
float zdiff = 1.0 - clamp(length(lightDir) / lightAttenuation, 0.0, 1.0);
float atten = (radiusFar * zdiff) / (radiusFar - radiusNear);
atten = pow(atten, 2.0);
lightDir = normalize(lightDir);
float nDotL = dot(norm, lightDir) * atten;
float lightDiffuse = max(0.0, nDotL);
gl_FragColor = vec4(lightDiffuse * (lightColour * lightIntensity), 1.0);
}
#endif