1
2#include "lighting.sdr"
3
4#include "shadows.sdr"
5
6in vec3 beamVec;
7in vec3 lightPosition;
8out vec4 fragOut0;
9
10uniform sampler2D ColorBuffer;
11uniform sampler2D NormalBuffer;
12uniform sampler2D PositionBuffer;
13uniform sampler2D SpecBuffer;
14uniform sampler2DArray shadow_map;
15
16layout (std140) uniform globalDeferredData {
17	mat4 shadow_mv_matrix;
18	mat4 shadow_proj_matrix[4];
19
20	mat4 inv_view_matrix;
21
22	float veryneardist;
23	float neardist;
24	float middist;
25	float fardist;
26
27	float invScreenWidth;
28	float invScreenHeight;
29};
30
31layout (std140) uniform lightData {
32	vec3 diffuseLightColor;
33	float coneAngle;
34
35	vec3 specLightColor;
36	float coneInnerAngle;
37
38	vec3 coneDir;
39	bool dualCone;
40
41	vec3 scale;
42	float lightRadius;
43
44	vec3 lightDir;
45	int lightType;
46
47	bool enable_shadows;
48};
49
50void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
51{
52	if (lightType == LT_DIRECTIONAL) {
53		lightDir = normalize(lightPosition);
54		attenuation = 1.0;
55	} else {
56		// Positional light source
57		lightDir = lightPosition - position.xyz;
58		float dist = length(lightDir);
59		attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
60
61		if(dist > lightRadius && lightType != LT_TUBE) {
62			discard;
63		}
64
65		if (lightType == LT_TUBE) {  // Tube light
66			float beamLength = length(beamVec);
67			vec3 beamDir = beamVec / beamLength;
68			//The actual 'lighting element' is shorter than the light volume cylinder
69			//To compensate the light is moved forward along the beam one radius and the length shortened
70			//this allows room for clean falloff of the light past the ends of beams.
71			vec3 adjustedLightPos = lightPosition - (beamDir * lightRadius);
72			beamLength = beamLength - (lightRadius * 2.0);
73			//adjustments having been made, lightdir needs recalculating
74			lightDir = adjustedLightPos - position.xyz;
75			// Get nearest point on line
76			float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
77			// Move back from the endpoint of the beam along the beam by the distance we calculated
78			vec3 nearest = adjustedLightPos - beamDir * neardist;
79			lightDir = nearest - position.xyz;
80			dist = length(lightDir);
81			if(dist > lightRadius) {
82				discard;
83			}
84			attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
85		} else if (lightType == LT_CONE) {
86			float coneDot = dot(normalize(-lightDir), coneDir);
87			if(dualCone) {
88				if(abs(coneDot) < coneAngle) {
89					discard;
90				} else {
91					attenuation *= smoothstep(coneAngle, coneInnerAngle, abs(coneDot));
92				}
93			} else {
94				if (coneDot < coneAngle) {
95					discard;
96				} else {
97					attenuation *= smoothstep(coneAngle, coneInnerAngle, coneDot);
98				}
99			}
100		}
101
102		lightDir = normalize(lightDir);
103	}
104}
105
106void main()
107{
108	vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
109	vec3 position = texture(PositionBuffer, screenPos).xyz;
110
111	if(abs(dot(position, position)) < 0.1)
112		discard;
113
114	vec3 color = texture(ColorBuffer, screenPos).rgb;
115	vec4 normalData = texture(NormalBuffer, screenPos);
116	vec4 specColor = texture(SpecBuffer, screenPos);
117	// The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer
118	vec3 normal = normalize(normalData.xyz);
119	float gloss = normalData.a;
120	float fresnel = specColor.a;
121	vec3 eyeDir = normalize(-position);
122
123	vec3 lightDir;
124	float attenuation;
125
126	GetLightInfo(position, lightDir, attenuation);
127
128	if (enable_shadows) {
129		vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
130		vec4 fragShadowUV[4];
131		fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
132		fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
133		fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
134		fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
135
136		attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
137								neardist, veryneardist);
138	}
139
140	vec3 halfVec = normalize(lightDir + eyeDir);
141	float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
142	vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);
143	fragmentColor.rgb += computeLighting(specColor.rgb, lightDir, normal.xyz, halfVec, eyeDir, gloss, fresnel, NdotL).rgb * specLightColor * attenuation;
144	fragOut0 = max(fragmentColor, vec4(0.0));
145}
146