1/*
2 Copyright (c) 2013 yvt
3
4 This file is part of OpenSpades.
5
6 OpenSpades is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 OpenSpades is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OpenSpades.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22#define USE_COARSE_SHADOWMAP 1
23#define DEBUG_TRACECOUNT 0
24
25uniform sampler2D colorTexture;
26uniform sampler2D depthTexture;
27uniform sampler2D shadowMapTexture;
28#if USE_COARSE_SHADOWMAP
29uniform sampler2D coarseShadowMapTexture;
30#endif
31uniform vec2 zNearFar;
32
33uniform vec3 fogColor;
34uniform float fogDistance;
35
36varying vec2 texCoord;
37varying vec3 viewTan;
38varying vec3 viewDir;
39varying vec3 shadowOrigin;
40varying vec3 shadowRayDirection;
41
42
43float decodeDepth(float w, float near, float far){
44	return far * near / mix(far, near, w);
45}
46
47float depthAt(vec2 pt){
48	float w = texture2D(depthTexture, pt).x;
49	return decodeDepth(w, zNearFar.x, zNearFar.y);
50}
51
52float fogDensFunc(float time) {
53	return time;// * time;
54}
55
56void main() {
57
58	// raytrace
59
60	float voxelDistanceFactor = length(shadowRayDirection) /
61	length(viewTan);
62	voxelDistanceFactor *= length(viewDir.xy) / length(viewDir); // remove vertical fog
63
64	float screenDepth = depthAt(texCoord);
65	float screenDistance = screenDepth * length(viewTan);
66	screenDistance = min(screenDistance, fogDistance);
67	float screenVoxelDistance = screenDistance * voxelDistanceFactor;
68
69	const vec2 voxels = vec2(512.);
70	const vec2 voxelSize = 1. / voxels;
71	float fogDistanceTime = fogDistance * voxelDistanceFactor;
72	float zMaxTime = min(screenVoxelDistance, fogDistanceTime);
73	float maxTime = zMaxTime;
74	float ceilTime = 10000000000.;
75
76	vec3 startPos = shadowOrigin;
77	//vec2 dir = vec2(1., 4.);
78	vec3 dir = shadowRayDirection.xyz; //dirVec;
79	if(length(dir.xy) < .0001) dir.xy = vec2(0.0001);
80	if(dir.x == 0.) dir.x = .00001;
81	if(dir.y == 0.) dir.y = .00001;
82	dir = normalize(dir);
83
84	if(dir.z < -0.000001) {
85		ceilTime = -startPos.z / dir.z - 0.0001;
86		maxTime = min(maxTime, ceilTime);
87	}
88
89	vec2 dirSign = sign(dir.xy);
90	vec2 dirSign2 = dirSign * .5 + .5; // 0, 1
91	vec2 dirSign3 = dirSign * .5 - .5; // -1, 0
92
93	float time = 0.;
94	float total = 0.;
95
96	if(startPos.z > (63. / 255.) && dir.z < 0.) {
97		// fog pass for mirror scene
98		time = ((63. / 255.) - startPos.z) / dir.z;
99		total += fogDensFunc(time);
100		startPos += time * dir;
101	}
102
103	vec3 pos = startPos + dir * 0.0001;
104	vec2 voxelIndex = floor(pos.xy);
105	if(pos.xy == voxelIndex) {
106		// exact coord doesn't work well
107		pos += 0.001;
108	}
109	vec2 nextVoxelIndex = voxelIndex + dirSign;
110	vec2 nextVoxelIndex2 = voxelIndex + dirSign2;
111	vec2 timePerVoxel = 1. / dir.xy;
112	vec2 timePerVoxelAbs = abs(timePerVoxel);
113	vec2 timeToNextVoxel = (nextVoxelIndex2 - pos.xy) * timePerVoxel;
114
115	if(ceilTime <= 0.) {
116		// camera is above ceil, and
117		// ray never goes below ceil
118		total = fogDensFunc(zMaxTime);
119	}else{
120#if USE_COARSE_SHADOWMAP
121#if DEBUG_TRACECOUNT
122		float traceCount = 0.;
123#define TRACE()	traceCount += 1.
124#else
125#define TRACE()
126#endif
127
128		const float coarseLevel = 8.;
129		const float coarseLevelInv = 1. / coarseLevel;
130
131		const vec2 coarseVoxels = voxels / coarseLevel;
132		const vec2 coarseVoxelSize = voxelSize * coarseLevel;
133
134		vec3 coarseDir = dir * vec3(coarseLevelInv, coarseLevelInv, 1.);
135		vec3 coarsePos = pos * vec3(coarseLevelInv, coarseLevelInv, 1.);
136		vec2 coarseVoxelIndex = floor(coarsePos.xy);
137		if(coarsePos.xy == coarseVoxelIndex) {
138			// exact coord doesn't work well
139			coarsePos += 0.0001;
140		}
141		vec2 coarseNextVoxelIndex = coarseVoxelIndex + dirSign;
142		vec2 coarseNextVoxelIndex2 = coarseVoxelIndex + dirSign2;
143		vec2 coarseTimePerVoxel = timePerVoxel * coarseLevel;
144		vec2 coarseTimePerVoxelAbs = timePerVoxelAbs * coarseLevel;
145		vec2 coarseTimeToNextVoxel = (coarseNextVoxelIndex2 - coarsePos.xy) * coarseTimePerVoxel;
146
147
148		for(int i = 0; i < 64; i++) {
149			float diffTime;
150			TRACE();
151			vec2 coarseVal = texture2D(coarseShadowMapTexture,
152								  coarseVoxelIndex * coarseVoxelSize).xy;
153			diffTime = min(coarseTimeToNextVoxel.x, coarseTimeToNextVoxel.y);
154
155			float nextTime = min(time + diffTime, maxTime);
156			float limitedDiffTime = nextTime - time;
157
158			vec2 passingZ = vec2(coarsePos.z);
159			passingZ.y += limitedDiffTime * coarseDir.z;
160
161			bvec2 stat = bvec2(min(passingZ.x, passingZ.y) > coarseVal.y,
162							   max(passingZ.x, passingZ.y) < coarseVal.x);
163
164			vec2 oldCoarseVoxelIndex = coarseVoxelIndex;
165			vec3 nextCoarsePos = coarsePos + diffTime * coarseDir;
166			// advance coarse ray
167			if(coarseTimeToNextVoxel.x < coarseTimeToNextVoxel.y) {
168				coarseVoxelIndex.x += dirSign.x;
169				//nextCoarsePos.x = coarseVoxelIndex.x - dirSign3.x;
170
171				coarseTimeToNextVoxel.y -= diffTime;
172				coarseTimeToNextVoxel.x = coarseTimePerVoxelAbs.x;
173			}else{
174				coarseVoxelIndex.y += dirSign.y;
175				//nextCoarsePos.y = coarseVoxelIndex.y - dirSign3.y;
176
177				coarseTimeToNextVoxel.x -= diffTime;
178				coarseTimeToNextVoxel.y = coarseTimePerVoxelAbs.y;
179			}
180
181
182			if(any(stat)) {
183				if(stat.y) {
184					// always in light
185					float diffDens = fogDensFunc(nextTime) - fogDensFunc(time);
186					total += diffDens;
187				}
188				time = nextTime;
189				diffTime = limitedDiffTime;
190			}else if(limitedDiffTime < 0.000000001){
191				// no advance in this coarse voxel
192				time = nextTime;
193				diffTime = limitedDiffTime;
194			}else{
195				// do detail tracing
196
197				pos = coarsePos * vec3(coarseLevel, coarseLevel, 1.);
198				voxelIndex = floor(pos.xy);
199				if(pos.xy == voxelIndex) {
200					// exact coord doesn't work well
201					pos += 0.001;
202				}
203				nextVoxelIndex = voxelIndex + dirSign;
204				nextVoxelIndex2 = voxelIndex + dirSign2;
205				timeToNextVoxel = (nextVoxelIndex2 - pos.xy) * timePerVoxel;
206
207				for(int j = 0; j < 64; j++){
208					TRACE();
209					float val = texture2D(shadowMapTexture, voxelIndex * voxelSize).w;
210					val = step(pos.z, val);
211
212					diffTime = min(timeToNextVoxel.x, timeToNextVoxel.y);
213					if(timeToNextVoxel.x < timeToNextVoxel.y) {
214						voxelIndex.x += dirSign.x;
215
216						timeToNextVoxel.y -= diffTime;
217						timeToNextVoxel.x = timePerVoxelAbs.x;
218					}else{
219						voxelIndex.y += dirSign.y;
220
221						timeToNextVoxel.x -= diffTime;
222						timeToNextVoxel.y = timePerVoxelAbs.y;
223					}
224
225					pos += dir * diffTime;
226
227					float nextTime = min(time + diffTime, maxTime);
228					float diffDens = fogDensFunc(nextTime) - fogDensFunc(time);
229					diffTime = nextTime - time;
230					time = nextTime;
231
232					total += val * diffDens;
233
234					if(time >= maxTime) {
235						break;
236					}
237
238					// if goes another coarse voxel,
239					// return to coarse ray tracing
240					if(floor((voxelIndex.xy + .5) * coarseLevelInv) !=
241					   oldCoarseVoxelIndex)
242						break;
243				}
244
245				// --- detail tracing ends here
246			}
247
248
249			if(time >= maxTime) {
250				if(nextTime >= ceilTime) {
251					float diffDens = fogDensFunc(zMaxTime) - fogDensFunc(time);;
252					total += max(diffDens, 0.);
253				}
254				break;
255			}
256
257			coarsePos = nextCoarsePos;
258		}
259
260#if DEBUG_TRACECOUNT
261		traceCount /= 8.;
262		if(traceCount < 1.) {
263			gl_FragColor = mix(vec4(0., 0., 0., 1.),
264							   vec4(1., 0., 0., 1.),
265							   traceCount);
266			return;
267		}else if(traceCount < 2.) {
268			gl_FragColor = mix(vec4(1., 0., 0., 1.),
269							   vec4(1., 1., 0., 1.),
270							   traceCount - 1.);
271			return;
272		}else if(traceCount < 3.) {
273			gl_FragColor = mix(vec4(1., 1., 0., 1.),
274							   vec4(0., 1., 0., 1.),
275							   traceCount - 2.);
276			return;
277		}else if(traceCount < 4.) {
278			gl_FragColor = mix(vec4(0., 1., 0., 1.),
279							   vec4(0., 1., 1., 1.),
280							   traceCount - 3.);
281			return;
282		}else if(traceCount < 5.) {
283			gl_FragColor = mix(vec4(0., 1., 1., 1.),
284							   vec4(0., 0., 1., 1.),
285							   traceCount - 4.);
286			return;
287		}else if(traceCount < 6.) {
288			gl_FragColor = mix(vec4(0., 0., 1., 1.),
289							   vec4(1., 0., 1., 1.),
290							   traceCount - 5.);
291			return;
292		}else if(traceCount < 7.) {
293			gl_FragColor = mix(vec4(1., 0., 1., 1.),
294							   vec4(1., 1., 1., 1.),
295							   traceCount - 6.);
296			return;
297		}else {
298			gl_FragColor = vec4(1., 1., 1., 1.);
299			return;
300		}
301#endif
302
303#else // USE_COARSE_SHADOWMAP
304
305#warning Non-coarse routine doesnt support water reflection
306		for(int i = 0; i < 512; i++){
307			float diffTime;
308
309			float val = texture2D(shadowMapTexture, voxelIndex * voxelSize).w;
310			val = step(pos.z, val);
311
312			diffTime = min(timeToNextVoxel.x, timeToNextVoxel.y);
313			if(timeToNextVoxel.x < timeToNextVoxel.y) {
314				//diffTime = timeToNextVoxel.x;
315				voxelIndex.x += dirSign.x;
316				//pos += dirVoxel * diffTime;
317				//pos.x = voxelIndex.x;
318
319				timeToNextVoxel.y -= diffTime;
320				timeToNextVoxel.x = timePerVoxelAbs.x;
321			}else{
322				//diffTime = timeToNextVoxel.y;
323				voxelIndex.y += dirSign.y;
324				//pos += dirVoxel * diffTime;
325				//pos.y = voxelIndex.y;
326
327				timeToNextVoxel.x -= diffTime;
328				timeToNextVoxel.y = timePerVoxelAbs.y;
329			}
330
331			pos += dir * diffTime;
332
333			float nextTime = min(time + diffTime, maxTime);
334			float diffDens = fogDensFunc(nextTime) - fogDensFunc(time);
335			diffTime = nextTime - time;
336			time = nextTime;
337
338
339			total += val * diffDens;
340
341			if(diffTime <= 0.) {
342				if(nextTime >= ceilTime) {
343					diffDens = fogDensFunc(zMaxTime) - fogDensFunc(time);;
344					total += val * max(diffDens, 0.);
345				}
346				break;
347			}
348		}
349#endif
350	}
351
352	total = mix(total, fogDensFunc(zMaxTime), 0.04);
353	total /= fogDensFunc(fogDistanceTime);
354
355	// add gradient
356	vec3 sunDir = normalize(vec3(0., -1., -1.));
357	float bright = dot(sunDir, normalize(viewDir));
358	total *= .8 + bright * 0.3;
359	bright = exp2(bright * 16. - 15.);
360	total *= bright + 1.;
361
362	gl_FragColor = texture2D(colorTexture, texCoord);
363#if !LINEAR_FRAMEBUFFER
364	gl_FragColor.xyz *= gl_FragColor.xyz; // linearize
365#endif
366
367	gl_FragColor.xyz += total * fogColor;
368
369#if !LINEAR_FRAMEBUFFER
370	gl_FragColor.xyz = sqrt(gl_FragColor.xyz);
371#endif
372}
373
374