1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreTerrainMaterialGeneratorA.h" 29 #include "OgreTerrain.h" 30 #include "OgreHighLevelGpuProgramManager.h" 31 #include "OgreRoot.h" 32 #include "OgreShadowCameraSetupPSSM.h" 33 34 namespace Ogre 35 { 36 //--------------------------------------------------------------------- 37 //--------------------------------------------------------------------- 38 HighLevelGpuProgramPtr createVertexProgram(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt)39 TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::createVertexProgram( 40 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) 41 { 42 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); 43 String progName = getVertexProgramName(prof, terrain, tt); 44 45 HighLevelGpuProgramPtr ret = mgr.getByName(progName); 46 if (ret.isNull()) 47 { 48 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 49 "glsl", GPT_VERTEX_PROGRAM); 50 } 51 else 52 { 53 ret->unload(); 54 } 55 56 return ret; 57 } 58 //--------------------------------------------------------------------- 59 HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt)60 TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::createFragmentProgram( 61 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) 62 { 63 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); 64 String progName = getFragmentProgramName(prof, terrain, tt); 65 66 HighLevelGpuProgramPtr ret = mgr.getByName(progName); 67 if (ret.isNull()) 68 { 69 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 70 "glsl", GPT_FRAGMENT_PROGRAM); 71 } 72 else 73 { 74 ret->unload(); 75 } 76 77 return ret; 78 } 79 80 //--------------------------------------------------------------------- generateVpHeader(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)81 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateVpHeader(const SM2Profile* prof, const Terrain* terrain, 82 TechniqueType tt, StringUtil::StrStreamType& outStream) 83 { 84 outStream << "#version " << Root::getSingleton().getRenderSystem()->getNativeShadingLanguageVersion() << "\n"; 85 86 bool compression = terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP; 87 if (compression) 88 { 89 outStream << 90 "in vec2 posIndex;\n" 91 "in float height;\n"; 92 } 93 else 94 { 95 outStream << 96 "in vec4 position;\n" 97 "in vec2 uv0;\n"; 98 } 99 if (tt != RENDER_COMPOSITE_MAP) 100 outStream << "in vec2 delta;\n"; // lodDelta, lodThreshold 101 102 outStream << 103 "uniform mat4 worldMatrix;\n" 104 "uniform mat4 viewProjMatrix;\n" 105 "uniform vec2 lodMorph;\n"; // morph amount, morph LOD target 106 107 if (compression) 108 { 109 outStream << 110 "uniform mat4 posIndexToObjectSpace;\n" 111 "uniform float baseUVScale;\n"; 112 } 113 // uv multipliers 114 uint maxLayers = prof->getMaxLayers(terrain); 115 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount())); 116 uint numUVMultipliers = (numLayers / 4); 117 if (numLayers % 4) 118 ++numUVMultipliers; 119 for (uint i = 0; i < numUVMultipliers; ++i) 120 outStream << "uniform vec4 uvMul_" << i << ";\n"; 121 122 outStream << 123 "out vec4 oPosObj;\n"; 124 125 uint texCoordSet = 1; 126 outStream << 127 "out vec4 oUVMisc; // xy = uv, z = camDepth\n"; 128 129 // layer UV's premultiplied, packed as xy/zw 130 uint numUVSets = numLayers / 2; 131 if (numLayers % 2) 132 ++numUVSets; 133 if (tt != LOW_LOD) 134 { 135 for (uint i = 0; i < numUVSets; ++i) 136 { 137 outStream << 138 "out vec4 layerUV" << i << ";\n"; 139 } 140 } 141 142 if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP) 143 { 144 outStream << "out vec2 lodInfo;\n"; 145 } 146 147 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; 148 if (fog) 149 { 150 outStream << 151 "uniform vec4 fogParams;\n" 152 "out float fogVal;\n"; 153 } 154 155 if (prof->isShadowingEnabled(tt, terrain)) 156 { 157 texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream); 158 } 159 160 // check we haven't exceeded texture coordinates 161 if (texCoordSet > 8) 162 { 163 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 164 "Requested options require too many texture coordinate sets! Try reducing the number of layers.", 165 __FUNCTION__); 166 } 167 168 outStream << "void main(void) {\n"; 169 if (compression) 170 { 171 outStream << 172 " vec4 position = posIndexToObjectSpace * vec4(posIndex, height, 1);\n" 173 " vec2 uv0 = vec2(posIndex.x * baseUVScale, 1.0 - (posIndex.y * baseUVScale));\n"; 174 } 175 outStream << 176 " vec4 worldPos = worldMatrix * position;\n" 177 " oPosObj = position;\n"; 178 179 if (tt != RENDER_COMPOSITE_MAP) 180 { 181 // determine whether to apply the LOD morph to this vertex 182 // we store the deltas against all vertices so we only want to apply 183 // the morph to the ones which would disappear. The target LOD which is 184 // being morphed to is stored in lodMorph.y, and the LOD at which 185 // the vertex should be morphed is stored in uv.w. If we subtract 186 // the former from the latter, and arrange to only morph if the 187 // result is negative (it will only be -1 in fact, since after that 188 // the vertex will never be indexed), we will achieve our aim. 189 // sign(vertexLOD - targetLOD) == -1 is to morph 190 outStream << 191 " float toMorph = -min(0.0, sign(delta.y - lodMorph.y));\n"; 192 // this will either be 1 (morph) or 0 (don't morph) 193 if (prof->getParent()->getDebugLevel()) 194 { 195 // x == LOD level (-1 since value is target level, we want to display actual) 196 outStream << " lodInfo.x = (lodMorph.y - 1) / " << terrain->getNumLodLevels() << ";\n"; 197 // y == LOD morph 198 outStream << " lodInfo.y = toMorph * lodMorph.x;\n"; 199 } 200 201 // morph 202 switch (terrain->getAlignment()) 203 { 204 case Terrain::ALIGN_X_Y: 205 outStream << " worldPos.z += delta.x * toMorph * lodMorph.x;\n"; 206 break; 207 case Terrain::ALIGN_X_Z: 208 outStream << " worldPos.y += delta.x * toMorph * lodMorph.x;\n"; 209 break; 210 case Terrain::ALIGN_Y_Z: 211 outStream << " worldPos.x += delta.x * toMorph * lodMorph.x;\n"; 212 break; 213 }; 214 } 215 216 // generate UVs 217 if (tt != LOW_LOD) 218 { 219 for (uint i = 0; i < numUVSets; ++i) 220 { 221 uint layer = i * 2; 222 uint uvMulIdx = layer / 4; 223 224 outStream << 225 " layerUV" << i << ".xy = " << " uv0.xy * uvMul_" << uvMulIdx << "." << getChannel(layer) << ";\n"; 226 outStream << 227 " layerUV" << i << ".zw = " << " uv0.xy * uvMul_" << uvMulIdx << "." << getChannel(layer+1) << ";\n"; 228 } 229 } 230 } 231 //--------------------------------------------------------------------- generateFpHeader(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)232 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateFpHeader(const SM2Profile* prof, const Terrain* terrain, 233 TechniqueType tt, StringUtil::StrStreamType& outStream) 234 { 235 // Main header 236 outStream << 237 // helpers 238 "#version " << Root::getSingleton().getRenderSystem()->getNativeShadingLanguageVersion() << "\n" 239 "vec4 expand(vec4 v)\n" 240 "{\n" 241 " return v * 2.0 - 1.0;\n" 242 "}\n\n" 243 // From http://substance.io/zauner/porting-vvvv-hlsl-shaders-to-vvvvjs 244 "vec4 lit(float NdotL, float NdotH, float m) {\n" 245 " float ambient = 1.0;\n" 246 " float diffuse = max(0.0, NdotL);\n" 247 " float specular = step(0.0, NdotL) * max(NdotH, 0.0);\n" 248 " return vec4(ambient, diffuse, specular, 1.0);\n" 249 "}\n\n"; 250 251 if (prof->isShadowingEnabled(tt, terrain)) 252 generateFpDynamicShadowsHelpers(prof, terrain, tt, outStream); 253 254 outStream << "in vec4 oPosObj;\n" 255 "in vec4 oUVMisc;\n" 256 "out vec4 fragColour;\n"; 257 258 uint texCoordSet = 1; 259 260 // UV's premultiplied, packed as xy/zw 261 uint maxLayers = prof->getMaxLayers(terrain); 262 uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); 263 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount())); 264 uint numUVSets = numLayers / 2; 265 if (numLayers % 2) 266 ++numUVSets; 267 if (tt != LOW_LOD) 268 { 269 for (uint i = 0; i < numUVSets; ++i) 270 { 271 outStream << 272 "in vec4 layerUV" << i << ";\n"; 273 } 274 } 275 if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP) 276 { 277 outStream << "in vec2 lodInfo;\n"; 278 } 279 280 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; 281 if (fog) 282 { 283 outStream << 284 "uniform vec3 fogColour;\n" 285 "in float fogVal;\n"; 286 } 287 288 uint currentSamplerIdx = 0; 289 290 outStream << 291 // Only 1 light supported in this version 292 // deferred shading profile / generator later, ok? :) 293 "uniform vec4 lightPosObjSpace;\n" 294 "uniform vec3 lightDiffuseColour;\n" 295 "uniform vec3 lightSpecularColour;\n" 296 "uniform vec3 eyePosObjSpace;\n" 297 "uniform vec4 ambient;\n" 298 // pack scale, bias and specular 299 "uniform vec4 scaleBiasSpecular;\n"; 300 301 if (tt == LOW_LOD) 302 { 303 // single composite map covers all the others below 304 outStream << 305 "uniform sampler2D compositeMap;\n"; 306 } 307 else 308 { 309 outStream << 310 "uniform sampler2D globalNormal;\n"; 311 312 if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled()) 313 { 314 outStream << "uniform sampler2D globalColourMap;\n"; 315 } 316 if (prof->isLightmapEnabled()) 317 { 318 outStream << "uniform sampler2D lightMap;\n"; 319 } 320 // Blend textures - sampler definitions 321 for (uint i = 0; i < numBlendTextures; ++i) 322 { 323 outStream << "uniform sampler2D blendTex" << i << ";\n"; 324 } 325 326 // Layer textures - sampler definitions & UV multipliers 327 for (uint i = 0; i < numLayers; ++i) 328 { 329 outStream << "uniform sampler2D difftex" << i << ";\n"; 330 outStream << "uniform sampler2D normtex" << i << ";\n"; 331 } 332 } 333 334 if (prof->isShadowingEnabled(tt, terrain)) 335 { 336 generateFpDynamicShadowsParams(&texCoordSet, ¤tSamplerIdx, prof, terrain, tt, outStream); 337 } 338 339 // check we haven't exceeded samplers 340 if (currentSamplerIdx > 16) 341 { 342 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 343 "Requested options require too many texture samplers! Try reducing the number of layers.", 344 __FUNCTION__); 345 } 346 347 outStream << "void main(void) {\n" 348 " float shadow = 1.0;\n" 349 " vec2 uv = oUVMisc.xy;\n" 350 // base colour 351 " fragColour = vec4(0,0,0,1);\n"; 352 353 if (tt != LOW_LOD) 354 { 355 outStream << 356 // global normal 357 " vec3 normal = expand(texture(globalNormal, uv)).rgb;\n"; 358 } 359 360 outStream << 361 " vec3 lightDir = \n" 362 " lightPosObjSpace.xyz - (oPosObj.xyz * lightPosObjSpace.w);\n" 363 " vec3 eyeDir = eyePosObjSpace - oPosObj.xyz;\n" 364 365 // set up accumulation areas 366 " vec3 diffuse = vec3(0,0,0);\n" 367 " float specular = 0.0;\n"; 368 369 if (tt == LOW_LOD) 370 { 371 // we just do a single calculation from composite map 372 outStream << 373 " vec4 composite = texture(compositeMap, uv);\n" 374 " diffuse = composite.rgb;\n"; 375 // TODO - specular; we'll need normals for this! 376 } 377 else 378 { 379 // set up the blend values 380 for (uint i = 0; i < numBlendTextures; ++i) 381 { 382 outStream << " vec4 blendTexVal" << i << " = texture(blendTex" << i << ", uv);\n"; 383 } 384 385 if (prof->isLayerNormalMappingEnabled()) 386 { 387 // derive the tangent space basis 388 // we do this in the pixel shader because we don't have per-vertex normals 389 // because of the LOD, we use a normal map 390 // tangent is always +x or -z in object space depending on alignment 391 switch(terrain->getAlignment()) 392 { 393 case Terrain::ALIGN_X_Y: 394 case Terrain::ALIGN_X_Z: 395 outStream << " vec3 tangent = vec3(1, 0, 0);\n"; 396 break; 397 case Terrain::ALIGN_Y_Z: 398 outStream << " vec3 tangent = vec3(0, 0, -1);\n"; 399 break; 400 }; 401 402 outStream << " vec3 binormal = normalize(cross(tangent, normal));\n"; 403 // note, now we need to re-cross to derive tangent again because it wasn't orthonormal 404 outStream << " tangent = normalize(cross(normal, binormal));\n"; 405 // derive final matrix 406 outStream << " mat3 TBN = mat3(tangent, binormal, normal);\n"; 407 408 // set up lighting result placeholders for interpolation 409 outStream << " vec4 litRes, litResLayer;\n"; 410 outStream << " vec3 TSlightDir, TSeyeDir, TShalfAngle, TSnormal;\n"; 411 if (prof->isLayerParallaxMappingEnabled()) 412 outStream << " float displacement;\n"; 413 // move 414 outStream << " TSlightDir = normalize(TBN * lightDir);\n"; 415 outStream << " TSeyeDir = normalize(TBN * eyeDir);\n"; 416 } 417 else 418 { 419 // simple per-pixel lighting with no normal mapping 420 outStream << " lightDir = normalize(lightDir);\n"; 421 outStream << " eyeDir = normalize(eyeDir);\n"; 422 outStream << " vec3 halfAngle = normalize(lightDir + eyeDir);\n"; 423 outStream << " vec4 litRes = lit(dot(normal, lightDir), dot(normal, halfAngle), scaleBiasSpecular.z);\n"; 424 } 425 } 426 } 427 //--------------------------------------------------------------------- generateVpLayer(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,uint layer,StringUtil::StrStreamType & outStream)428 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateVpLayer(const SM2Profile* prof, const Terrain* terrain, 429 TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) 430 { 431 // nothing to do 432 } 433 //--------------------------------------------------------------------- generateFpLayer(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,uint layer,StringUtil::StrStreamType & outStream)434 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateFpLayer(const SM2Profile* prof, const Terrain* terrain, 435 TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) 436 { 437 uint uvIdx = layer / 2; 438 String uvChannels = (layer % 2) ? ".zw" : ".xy"; 439 uint blendIdx = (layer-1) / 4; 440 String blendChannel = getChannel(layer-1); 441 String blendWeightStr = String("blendTexVal") + StringConverter::toString(blendIdx) + "." + blendChannel; 442 443 // generate early-out conditional 444 /* Disable - causing some issues even when trying to force the use of texldd 445 if (layer && prof->_isSM3Available()) 446 outStream << " if (" << blendWeightStr << " > 0.0003)\n { \n"; 447 */ 448 449 // generate UV 450 outStream << " vec2 uv" << layer << " = layerUV" << uvIdx << uvChannels << ";\n"; 451 452 // calculate lighting here if normal mapping 453 if (prof->isLayerNormalMappingEnabled()) 454 { 455 if (prof->isLayerParallaxMappingEnabled() && tt != RENDER_COMPOSITE_MAP) 456 { 457 // modify UV - note we have to sample an extra time 458 outStream << " displacement = texture(normtex" << layer << ", uv" << layer << ").a\n" 459 " * scaleBiasSpecular.x + scaleBiasSpecular.y;\n"; 460 outStream << " uv" << layer << " += TSeyeDir.xy * displacement;\n"; 461 } 462 463 // access TS normal map 464 outStream << " TSnormal = expand(texture(normtex" << layer << ", uv" << layer << ")).rgb;\n"; 465 outStream << " TShalfAngle = normalize(TSlightDir + TSeyeDir);\n"; 466 outStream << " litResLayer = lit(dot(TSnormal, TSlightDir), dot(TSnormal, TShalfAngle), scaleBiasSpecular.z);\n"; 467 if (!layer) 468 outStream << " litRes = litResLayer;\n"; 469 else 470 outStream << " litRes = mix(litRes, litResLayer, " << blendWeightStr << ");\n"; 471 472 } 473 474 // sample diffuse texture 475 outStream << " vec4 diffuseSpecTex" << layer 476 << " = texture(difftex" << layer << ", uv" << layer << ");\n"; 477 478 // apply to common 479 if (!layer) 480 { 481 outStream << " diffuse = diffuseSpecTex0.rgb;\n"; 482 if (prof->isLayerSpecularMappingEnabled()) 483 outStream << " specular = diffuseSpecTex0.a;\n"; 484 } 485 else 486 { 487 outStream << " diffuse = mix(diffuse, diffuseSpecTex" << layer 488 << ".rgb, " << blendWeightStr << ");\n"; 489 if (prof->isLayerSpecularMappingEnabled()) 490 outStream << " specular = mix(specular, diffuseSpecTex" << layer 491 << ".a, " << blendWeightStr << ");\n"; 492 } 493 494 // End early-out 495 /* Disable - causing some issues even when trying to force the use of texldd 496 if (layer && prof->_isSM3Available()) 497 outStream << " } // early-out blend value\n"; 498 */ 499 } 500 //--------------------------------------------------------------------- generateVpFooter(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)501 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateVpFooter(const SM2Profile* prof, const Terrain* terrain, 502 TechniqueType tt, StringUtil::StrStreamType& outStream) 503 { 504 outStream << 505 " gl_Position = viewProjMatrix * worldPos;\n" 506 " oUVMisc.xy = uv0.xy;\n"; 507 508 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; 509 if (fog) 510 { 511 if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) 512 { 513 outStream << 514 " fogVal = clamp((gl_Position.z - fogParams.y) * fogParams.w, 0.0, 1.0);\n"; 515 } 516 else 517 { 518 outStream << 519 " fogVal = 1.0 - clamp(1.0 / (exp(gl_Position.z * fogParams.x)), 0.0, 1.0);\n"; 520 } 521 } 522 523 if (prof->isShadowingEnabled(tt, terrain)) 524 generateVpDynamicShadows(prof, terrain, tt, outStream); 525 526 outStream << "}\n"; 527 } 528 //--------------------------------------------------------------------- generateFpFooter(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)529 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateFpFooter(const SM2Profile* prof, const Terrain* terrain, 530 TechniqueType tt, StringUtil::StrStreamType& outStream) 531 { 532 if (tt == LOW_LOD) 533 { 534 if (prof->isShadowingEnabled(tt, terrain)) 535 { 536 generateFpDynamicShadows(prof, terrain, tt, outStream); 537 outStream << 538 " fragColour.rgb = diffuse * rtshadow;\n"; 539 } 540 else 541 { 542 outStream << 543 " fragColour.rgb = diffuse;\n"; 544 } 545 } 546 else 547 { 548 if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled()) 549 { 550 // sample colour map and apply to diffuse 551 outStream << " diffuse *= texture(globalColourMap, uv).rgb;\n"; 552 } 553 if (prof->isLightmapEnabled()) 554 { 555 // sample lightmap 556 outStream << " shadow = texture(lightMap, uv).r;\n"; 557 } 558 559 if (prof->isShadowingEnabled(tt, terrain)) 560 { 561 generateFpDynamicShadows(prof, terrain, tt, outStream); 562 } 563 564 // diffuse lighting 565 outStream << " fragColour.rgb += ambient.rgb * diffuse + litRes.y * lightDiffuseColour * diffuse * shadow;\n"; 566 567 // specular default 568 if (!prof->isLayerSpecularMappingEnabled()) 569 outStream << " specular = 1.0;\n"; 570 571 if (tt == RENDER_COMPOSITE_MAP) 572 { 573 // Lighting embedded in alpha 574 outStream << 575 " fragColour.a = shadow;\n"; 576 } 577 else 578 { 579 // Apply specular 580 outStream << " fragColour.rgb += litRes.z * lightSpecularColour * specular * shadow;\n"; 581 582 if (prof->getParent()->getDebugLevel()) 583 { 584 outStream << " fragColour.rg += lodInfo.xy;\n"; 585 } 586 } 587 } 588 589 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; 590 if (fog) 591 { 592 outStream << " fragColour.rgb = mix(fragColour.rgb, fogColour, fogVal);\n"; 593 } 594 595 // Final return 596 outStream << "}\n"; 597 } 598 //--------------------------------------------------------------------- generateFpDynamicShadowsHelpers(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)599 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateFpDynamicShadowsHelpers(const SM2Profile* prof, const Terrain* terrain, 600 TechniqueType tt, StringUtil::StrStreamType& outStream) 601 { 602 // TODO make filtering configurable 603 outStream << 604 "// Simple PCF \n" 605 "// Number of samples in one dimension (square for total samples) \n" 606 "#define NUM_SHADOW_SAMPLES_1D 2.0 \n" 607 "#define SHADOW_FILTER_SCALE 1 \n" 608 609 "#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n" 610 611 "vec4 offsetSample(vec4 uv, vec2 offset, float invMapSize) \n" 612 "{ \n" 613 " return vec4(uv.xy + offset * invMapSize * uv.w, uv.z, uv.w); \n" 614 "} \n"; 615 616 if (prof->getReceiveDynamicShadowsDepth()) 617 { 618 outStream << 619 "float calcDepthShadow(sampler2D shadowMap, vec4 uv, float invShadowMapSize) \n" 620 "{ \n" 621 " // 4-sample PCF \n" 622 623 " float shadow = 0.0; \n" 624 " float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n" 625 " for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n" 626 " for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n" 627 " { \n" 628 " vec4 newUV = offsetSample(uv, vec2(x, y), invShadowMapSize);\n" 629 " // manually project and assign derivatives \n" 630 " // to avoid gradient issues inside loops \n" 631 " float depth = textureProjGrad(shadowMap, newUV.xyw, vec2(1.0), vec2(1.0)).x; \n" 632 " if (depth >= 1 || depth >= uv.z)\n" 633 " shadow += 1.0;\n" 634 " } \n" 635 636 " shadow /= SHADOW_SAMPLES; \n" 637 " return shadow; \n" 638 "} \n"; 639 } 640 else 641 { 642 outStream << 643 "float calcSimpleShadow(sampler2D shadowMap, vec4 shadowMapPos) \n" 644 "{ \n" 645 " return textureProj(shadowMap, shadowMapPos).x; \n" 646 "} \n"; 647 } 648 649 if (prof->getReceiveDynamicShadowsPSSM()) 650 { 651 uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); 652 653 if (prof->getReceiveDynamicShadowsDepth()) 654 { 655 outStream << 656 "float calcPSSMDepthShadow("; 657 } 658 else 659 { 660 outStream << 661 "float calcPSSMSimpleShadow("; 662 } 663 664 outStream << "\n "; 665 for (uint i = 0; i < numTextures; ++i) 666 outStream << "sampler2D shadowMap" << i << ", "; 667 outStream << "\n "; 668 for (uint i = 0; i < numTextures; ++i) 669 outStream << "vec4 lsPos" << i << ", "; 670 if (prof->getReceiveDynamicShadowsDepth()) 671 { 672 outStream << "\n "; 673 for (uint i = 0; i < numTextures; ++i) 674 outStream << "float invShadowmapSize" << i << ", "; 675 } 676 outStream << "\n" 677 " vec4 pssmSplitPoints, float camDepth) \n" 678 " { \n" 679 " float shadow; \n" 680 " // calculate shadow \n"; 681 682 for (uint i = 0; i < numTextures; ++i) 683 { 684 if (!i) 685 outStream << " if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n"; 686 else if (i < numTextures - 1) 687 outStream << " else if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n"; 688 else 689 outStream << " else \n"; 690 691 outStream << 692 " { \n"; 693 if (prof->getReceiveDynamicShadowsDepth()) 694 { 695 outStream << 696 " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << "); \n"; 697 } 698 else 699 { 700 outStream << 701 " shadow = calcSimpleShadow(shadowMap" << i << ", lsPos" << i << "); \n"; 702 } 703 outStream << " } \n"; 704 } 705 706 outStream << 707 " return shadow; \n" 708 "} \n\n\n"; 709 } 710 } 711 //--------------------------------------------------------------------- generateVpDynamicShadowsParams(uint texCoord,const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)712 uint TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateVpDynamicShadowsParams(uint texCoord, const SM2Profile* prof, 713 const Terrain* terrain, TechniqueType tt, 714 StringUtil::StrStreamType& outStream) 715 { 716 // out semantics & params 717 uint numTextures = 1; 718 if (prof->getReceiveDynamicShadowsPSSM()) 719 { 720 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); 721 } 722 for (uint i = 0; i < numTextures; ++i) 723 { 724 outStream << 725 " out vec4 oLightSpacePos" << i << ";\n" << 726 " uniform mat4 texViewProjMatrix" << i << ";\n"; 727 if (prof->getReceiveDynamicShadowsDepth()) 728 { 729 outStream << 730 " uniform vec4 depthRange" << i << "; // x = min, y = max, z = range, w = 1/range \n"; 731 } 732 } 733 734 return texCoord; 735 } 736 //--------------------------------------------------------------------- generateVpDynamicShadows(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)737 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateVpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, 738 TechniqueType tt, StringUtil::StrStreamType& outStream) 739 { 740 uint numTextures = 1; 741 if (prof->getReceiveDynamicShadowsPSSM()) 742 { 743 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); 744 } 745 746 // Calculate the position of vertex in light space 747 for (uint i = 0; i < numTextures; ++i) 748 { 749 outStream << 750 " oLightSpacePos" << i << " = texViewProjMatrix" << i << " * worldPos; \n"; 751 if (prof->getReceiveDynamicShadowsDepth()) 752 { 753 // make linear 754 outStream << 755 "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n"; 756 } 757 } 758 759 if (prof->getReceiveDynamicShadowsPSSM()) 760 { 761 outStream << 762 " // pass cam depth\n" 763 " oUVMisc.z = gl_Position.z;\n"; 764 } 765 } 766 //--------------------------------------------------------------------- generateFpDynamicShadowsParams(uint * texCoord,uint * sampler,const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)767 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateFpDynamicShadowsParams(uint* texCoord, uint* sampler, 768 const SM2Profile* prof, const Terrain* terrain, 769 TechniqueType tt, StringUtil::StrStreamType& outStream) 770 { 771 if (tt == HIGH_LOD) 772 mShadowSamplerStartHi = *sampler; 773 else if (tt == LOW_LOD) 774 mShadowSamplerStartLo = *sampler; 775 776 // in semantics & params 777 uint numTextures = 1; 778 if (prof->getReceiveDynamicShadowsPSSM()) 779 { 780 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); 781 outStream << 782 "uniform vec4 pssmSplitPoints;\n"; 783 } 784 for (uint i = 0; i < numTextures; ++i) 785 { 786 outStream << 787 "in vec4 oLightSpacePos" << i << ";\n" << 788 "uniform sampler2D shadowMap" << i << ";\n"; 789 *sampler = *sampler + 1; 790 *texCoord = *texCoord + 1; 791 if (prof->getReceiveDynamicShadowsDepth()) 792 { 793 outStream << 794 "uniform float inverseShadowmapSize" << i << ";\n"; 795 } 796 } 797 } 798 //--------------------------------------------------------------------- generateFpDynamicShadows(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)799 void TerrainMaterialGeneratorA::SM2Profile::ShaderHelperGLSL::generateFpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, 800 TechniqueType tt, StringUtil::StrStreamType& outStream) 801 { 802 if (prof->getReceiveDynamicShadowsPSSM()) 803 { 804 uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); 805 outStream << 806 " float camDepth = oUVMisc.z;\n"; 807 808 if (prof->getReceiveDynamicShadowsDepth()) 809 { 810 outStream << 811 " float rtshadow = calcPSSMDepthShadow("; 812 } 813 else 814 { 815 outStream << 816 " float rtshadow = calcPSSMSimpleShadow("; 817 } 818 for (uint i = 0; i < numTextures; ++i) 819 outStream << "shadowMap" << i << ", "; 820 outStream << "\n "; 821 822 for (uint i = 0; i < numTextures; ++i) 823 outStream << "oLightSpacePos" << i << ", "; 824 if (prof->getReceiveDynamicShadowsDepth()) 825 { 826 outStream << "\n "; 827 for (uint i = 0; i < numTextures; ++i) 828 outStream << "inverseShadowmapSize" << i << ", "; 829 } 830 outStream << "\n" << 831 " pssmSplitPoints, camDepth);\n"; 832 } 833 else 834 { 835 if (prof->getReceiveDynamicShadowsDepth()) 836 { 837 outStream << 838 " float rtshadow = calcDepthShadow(shadowMap0, oLightSpacePos0, inverseShadowmapSize0);"; 839 } 840 else 841 { 842 outStream << 843 " float rtshadow = calcSimpleShadow(shadowMap0, oLightSpacePos0);"; 844 } 845 } 846 847 outStream << 848 " shadow = min(shadow, rtshadow);\n"; 849 } 850 851 } 852