1 /** 2 * Lighting pass shader for Directional Lights 3 */ 4 module dash.graphics.shaders.glsl.directionallight; 5 import dash.graphics.shaders.glsl; 6 7 package: 8 9 /// Takes in a clip-space quad and creates a ray from camera to each vertex, which is interpolated during pass-through 10 immutable string directionallightVS = glslVersion ~ q{ 11 layout(location = 0) in vec3 vPosition_s; 12 layout(location = 1) in vec2 vUV; 13 14 uniform mat4 invProj; 15 16 out vec4 fPosition_s; 17 out vec2 fUV; 18 out vec3 fViewRay; 19 20 void main( void ) 21 { 22 fPosition_s = vec4( vPosition_s, 1.0f ); 23 gl_Position = fPosition_s; 24 25 vec3 position_v = ( invProj * vec4( vPosition_s, 1.0f ) ).xyz; 26 // This is the ray clamped to depth 1, and it'll just be moved & interpolated in the XY 27 fViewRay = vec3( position_v.xy / position_v.z, 1.0f ); 28 fUV = vUV; 29 } 30 }; 31 32 /// Calculates diffuse and specular lights from the full-screen directional light, 33 /// using the view ray to reconstruct pixel position 34 immutable string directionallightFS = glslVersion ~ q{ 35 struct DirectionalLight 36 { 37 vec3 color; 38 vec3 direction; 39 float shadowless; 40 }; 41 42 in vec4 fPosition_s; 43 in vec2 fUV; 44 in vec3 fViewRay; 45 46 // g-buffer outputs 47 uniform sampler2D diffuseTexture; 48 uniform sampler2D normalTexture; 49 uniform sampler2D depthTexture; 50 51 // shadow map values 52 uniform sampler2D shadowMap; 53 uniform mat4 lightProjView; 54 uniform mat4 cameraView; 55 56 uniform DirectionalLight light; 57 58 // A pair of constants for reconstructing the linear Z 59 // [ (-Far * Near ) / ( Far - Near ), Far / ( Far - Near ) ] 60 uniform vec2 projectionConstants; 61 62 // https://stackoverflow.com/questions/9222217/how-does-the-fragment-shader-know-what-variable-to-use-for-the-color-of-a-pixel 63 layout( location = 0 ) out vec4 color; 64 65 // Function for decoding normals 66 vec3 decode( vec2 enc ) 67 { 68 float t = ( ( enc.x * enc.x ) + ( enc.y * enc.y ) ) / 4; 69 float ti = sqrt( 1 - t ); 70 return vec3( ti * enc.x, ti * enc.y, -1 + t * 2 ); 71 } 72 73 float shadowValue(vec3 pos) 74 { 75 mat4 toShadowMap_s = lightProjView * inverse(cameraView); 76 vec4 lightSpacePos = toShadowMap_s * vec4( pos, 1 ); 77 lightSpacePos = lightSpacePos / lightSpacePos.w; 78 79 vec2 shadowCoords = (lightSpacePos.xy * 0.5) + vec2( 0.5, 0.5 ); 80 81 float depthValue = texture( shadowMap, shadowCoords ).x - 0.0001; 82 83 return float( (lightSpacePos.z * .5 + .5 ) < depthValue ); 84 } 85 86 void main( void ) 87 { 88 vec3 textureColor = texture( diffuseTexture, fUV ).xyz; 89 float specularIntensity = texture( diffuseTexture, fUV ).w; 90 vec3 normal_v = texture( normalTexture, fUV ).xyz; 91 vec3 lightDir_v = -normalize( light.direction ); 92 93 // Reconstruct position from Depth 94 float depth = texture( depthTexture, fUV ).x; 95 float linearDepth = projectionConstants.x / ( projectionConstants.y - depth ); 96 vec3 position_v = fViewRay * linearDepth; 97 98 99 // Diffuse lighting calculations 100 float diffuseScale = clamp( dot( normal_v, lightDir_v ), 0, 1 ); 101 102 // Specular lighting calculations 103 // Usually in these you see an "eyeDirection" variable, but in view space that is our position 104 float specularScale = clamp( dot( normalize( position_v ), reflect( lightDir_v, normal_v ) ), 0, 1 ); 105 106 vec3 diffuse = ( diffuseScale * light.color ) * textureColor; 107 // "8" is the reflectiveness 108 // textureColor.w is the shininess 109 // specularIntensity is the light's contribution 110 vec3 specular = ( pow( specularScale, 8 ) * light.color * specularIntensity); 111 112 color = max( light.shadowless , shadowValue(position_v) ) * vec4( ( diffuse + specular ), 1.0f ); 113 } 114 };