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