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