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 };