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