terrCellMaterial.cpp
Engine/source/terrain/terrCellMaterial.cpp
Public Variables
Public Functions
Detailed Description
Public Variables
S32 sgMaxTerrainMaterialsPerPass
Public Functions
_initSamplerNames()
AFTER_MODULE_INIT(MaterialManager )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "terrain/terrCellMaterial.h" 26 27 28#include "core/util/safeRelease.h" 29#include "terrain/terrData.h" 30#include "terrain/terrCell.h" 31#include "materials/materialFeatureTypes.h" 32#include "materials/materialManager.h" 33#include "terrain/terrFeatureTypes.h" 34#include "terrain/terrMaterial.h" 35#include "renderInstance/renderDeferredMgr.h" 36#include "shaderGen/shaderGen.h" 37#include "shaderGen/featureMgr.h" 38#include "scene/sceneRenderState.h" 39#include "materials/sceneData.h" 40#include "gfx/util/screenspace.h" 41#include "lighting/advanced/advancedLightBinManager.h" 42 43S32 sgMaxTerrainMaterialsPerPass = 32; 44 45AFTER_MODULE_INIT( MaterialManager ) 46{ 47 Con::NotifyDelegate callabck( &TerrainCellMaterial::_updateDefaultAnisotropy ); 48 Con::addVariableNotify( "$pref::Video::defaultAnisotropy", callabck ); 49} 50 51Vector<TerrainCellMaterial*> TerrainCellMaterial::smAllMaterials; 52 53Vector<String> _initSamplerNames() 54{ 55 Vector<String> samplerNames; 56 samplerNames.push_back("$baseTexMap"); 57 samplerNames.push_back("$layerTex"); 58 samplerNames.push_back("$lightMapTex"); 59 samplerNames.push_back("$lightInfoBuffer"); 60 samplerNames.push_back("$normalMapSampler"); 61 samplerNames.push_back("$detailMapSampler"); 62 samplerNames.push_back("$macroMapSampler"); 63 samplerNames.push_back("$ormMapSampler"); 64 65 return samplerNames; 66} 67 68 69const Vector<String> TerrainCellMaterial::mSamplerNames = _initSamplerNames(); 70 71TerrainCellMaterial::TerrainCellMaterial() 72 : mTerrain( NULL ), 73 mDeferredMat( NULL ), 74 mReflectMat( NULL ), 75 mShader( NULL ), 76 mCurrPass( 0 ), 77 mMaterials( 0 ) 78{ 79 smAllMaterials.push_back( this ); 80} 81 82TerrainCellMaterial::~TerrainCellMaterial() 83{ 84 SAFE_DELETE( mDeferredMat ); 85 SAFE_DELETE( mReflectMat ); 86 smAllMaterials.remove( this ); 87 88 T3D::for_each(mMaterialInfos.begin(), mMaterialInfos.end(), T3D::delete_pointer()); 89 mMaterialInfos.clear(); 90} 91 92void TerrainCellMaterial::_updateDefaultAnisotropy() 93{ 94 // TODO: We need to split the stateblock initialization 95 // from the shader constant lookup and pass setup in a 96 // future version of terrain materials. 97 // 98 // For now use some custom code in a horrible loop to 99 // change the anisotropy directly and fast. 100 // 101 102 const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy(); 103 104 Vector<TerrainCellMaterial*>::iterator iter = smAllMaterials.begin(); 105 for ( ; iter != smAllMaterials.end(); iter++ ) 106 { 107 // Start from the existing state block. 108 GFXStateBlockDesc desc = (*iter)->mStateBlock->getDesc(); 109 110 if ((*iter)->mDetailTexArrayConst->isValid()) 111 { 112 const S32 sampler = (*iter)->mDetailTexArrayConst->getSamplerRegister(); 113 114 if (maxAnisotropy > 1) 115 { 116 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 117 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 118 } 119 else 120 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 121 } 122 123 if ((*iter)->mMacroTexArrayConst->isValid()) 124 { 125 const S32 sampler = (*iter)->mMacroTexArrayConst->getSamplerRegister(); 126 127 if (maxAnisotropy > 1) 128 { 129 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 130 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 131 } 132 else 133 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 134 } 135 136 if ((*iter)->mNormalTexArrayConst->isValid()) 137 { 138 const S32 sampler = (*iter)->mNormalTexArrayConst->getSamplerRegister(); 139 140 if (maxAnisotropy > 1) 141 { 142 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 143 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 144 } 145 else 146 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 147 } 148 149 if ((*iter)->mOrmTexArrayConst->isValid()) 150 { 151 const S32 sampler = (*iter)->mOrmTexArrayConst->getSamplerRegister(); 152 153 if (maxAnisotropy > 1) 154 { 155 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 156 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 157 } 158 else 159 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 160 } 161 162 // Set the updated stateblock. 163 desc.setCullMode(GFXCullCCW); 164 (*iter)->mStateBlock = GFX->createStateBlock(desc); 165 166 //reflection 167 desc.setCullMode(GFXCullCW); 168 (*iter)->mReflectionStateBlock = GFX->createStateBlock(desc); 169 170 // Create the wireframe state blocks. 171 GFXStateBlockDesc wireframe(desc); 172 wireframe.fillMode = GFXFillWireframe; 173 wireframe.setCullMode(GFXCullCCW); 174 (*iter)->mWireframeStateBlock = GFX->createStateBlock(wireframe); 175 } 176 177} 178 179void TerrainCellMaterial::setTransformAndEye( const MatrixF &modelXfm, 180 const MatrixF &viewXfm, 181 const MatrixF &projectXfm, 182 F32 farPlane ) 183{ 184 PROFILE_SCOPE( TerrainCellMaterial_SetTransformAndEye ); 185 186 MatrixF modelViewProj = projectXfm * viewXfm * modelXfm; 187 188 MatrixF invViewXfm( viewXfm ); 189 invViewXfm.inverse(); 190 Point3F eyePos = invViewXfm.getPosition(); 191 192 MatrixF invModelXfm( modelXfm ); 193 invModelXfm.inverse(); 194 195 Point3F objEyePos = eyePos; 196 invModelXfm.mulP( objEyePos ); 197 198 VectorF vEye = invViewXfm.getForwardVector(); 199 vEye.normalize( 1.0f / farPlane ); 200 201 mConsts->setSafe(mModelViewProjConst, modelViewProj); 202 203 if (mViewToObjConst->isValid() || mWorldViewOnlyConst->isValid()) 204 { 205 MatrixF worldViewOnly = viewXfm * modelXfm; 206 207 mConsts->setSafe(mWorldViewOnlyConst, worldViewOnly); 208 209 if (mViewToObjConst->isValid()) 210 { 211 worldViewOnly.affineInverse(); 212 mConsts->set(mViewToObjConst, worldViewOnly); 213 } 214 } 215 216 mConsts->setSafe(mEyePosWorldConst, eyePos); 217 mConsts->setSafe(mEyePosConst, objEyePos); 218 mConsts->setSafe(mObjTransConst, modelXfm); 219 mConsts->setSafe(mWorldToObjConst, invModelXfm); 220 mConsts->setSafe(mVEyeConst, vEye); 221} 222 223TerrainCellMaterial* TerrainCellMaterial::getDeferredMat() 224{ 225 if ( !mDeferredMat ) 226 { 227 mDeferredMat = new TerrainCellMaterial(); 228 mDeferredMat->init( mTerrain, mMaterials, true, false, mMaterials == 0 ); 229 } 230 231 return mDeferredMat; 232} 233 234TerrainCellMaterial* TerrainCellMaterial::getReflectMat() 235{ 236 if ( !mReflectMat ) 237 { 238 mReflectMat = new TerrainCellMaterial(); 239 mReflectMat->init( mTerrain, mMaterials, false, true, true ); 240 } 241 242 return mReflectMat; 243} 244 245void TerrainCellMaterial::init( TerrainBlock *block, 246 U64 activeMaterials, 247 bool deferredMat, 248 bool reflectMat, 249 bool baseOnly ) 250{ 251 // This isn't allowed for now. 252 AssertFatal( !( deferredMat && reflectMat ), "TerrainCellMaterial::init - We shouldn't get deferred and reflection in the same material!" ); 253 254 mTerrain = block; 255 mMaterials = activeMaterials; 256 257 mMaterialInfos.clear(); 258 for ( U32 i = 0; i < 64; i++ ) 259 { 260 if ( !( mMaterials & ((U64)1 << i ) ) ) 261 continue; 262 263 TerrainMaterial *mat = block->getMaterial( i ); 264 265 MaterialInfo *info = new MaterialInfo(); 266 info->layerId = i; 267 info->mat = mat; 268 mMaterialInfos.push_back(info); 269 } 270 271 if (!_initShader(deferredMat, 272 reflectMat, 273 baseOnly)) 274 { 275 Con::errorf("TerrainCellMaterial::init - Failed to init shader!"); 276 277 T3D::for_each(mMaterialInfos.begin(), mMaterialInfos.end(), T3D::delete_pointer()); 278 mMaterialInfos.clear(); 279 return; 280 } 281 282 // If we have attached mats then update them too. 283 if ( mDeferredMat ) 284 mDeferredMat->init( mTerrain, mMaterials, true, false, baseOnly ); 285 if ( mReflectMat ) 286 mReflectMat->init( mTerrain, mMaterials, false, true, baseOnly ); 287} 288 289bool TerrainCellMaterial::_initShader(bool deferredMat, 290 bool reflectMat, 291 bool baseOnly) 292{ 293 if (GFX->getPixelShaderVersion() < 3.0f) 294 baseOnly = true; 295 296 // NOTE: At maximum we only try to combine sgMaxTerrainMaterialsPerPass materials 297 // into a single pass. This is sub-optimal for the simplest 298 // cases, but the most common case results in much fewer 299 // shader generation failures and permutations leading to 300 // faster load time and less hiccups during gameplay. 301 U32 matCount = getMin(sgMaxTerrainMaterialsPerPass, mMaterialInfos.size()); 302 303 Vector<GFXTexHandle> normalMaps; 304 305 // See if we're currently running under the 306 // basic lighting manager. 307 // 308 // TODO: This seems ugly... we should trigger 309 // features like this differently in the future. 310 // 311 bool useBLM = String::compare(LIGHTMGR->getId(), "BLM") == 0; 312 313 // Do we need to disable normal mapping? 314 const bool disableNormalMaps = MATMGR->getExclusionFeatures().hasFeature(MFT_NormalMap) || useBLM; 315 316 // How about parallax? 317 const bool disableParallaxMaps = GFX->getPixelShaderVersion() < 3.0f || 318 MATMGR->getExclusionFeatures().hasFeature(MFT_Parallax); 319 320 // Has advanced lightmap support been enabled for deferred. 321 bool advancedLightmapSupport = false; 322 if (deferredMat) 323 { 324 // This sucks... but it works. 325 AdvancedLightBinManager* lightBin; 326 if (Sim::findObject("AL_LightBinMgr", lightBin)) 327 advancedLightmapSupport = lightBin->MRTLightmapsDuringDeferred(); 328 } 329 330 // Loop till we create a valid shader! 331 while (true) 332 { 333 FeatureSet features; 334 features.addFeature(MFT_VertTransform); 335 features.addFeature(MFT_TerrainBaseMap); 336 337 if (deferredMat) 338 { 339 features.addFeature(MFT_EyeSpaceDepthOut); 340 features.addFeature(MFT_DeferredConditioner); 341 features.addFeature(MFT_isDeferred); 342 343 if (advancedLightmapSupport) 344 features.addFeature(MFT_RenderTarget3_Zero); 345 } 346 else 347 { 348 features.addFeature(MFT_RTLighting); 349 350 // The HDR feature is always added... it will compile out 351 // if HDR is not enabled in the engine. 352 features.addFeature(MFT_HDROut); 353 } 354 355 // Enable lightmaps and fogging if we're in BL. 356 if (reflectMat || useBLM) 357 { 358 features.addFeature(MFT_Fog); 359 features.addFeature(MFT_ForwardShading); 360 } 361 if (useBLM) 362 features.addFeature(MFT_TerrainLightMap); 363 364 normalMaps.clear(); 365 366 S32 featureIndex = 0; 367 368 // Now add all the material layer features. 369 for (U32 i = 0; i < matCount && !baseOnly; i++) 370 { 371 TerrainMaterial* mat = mMaterialInfos[i]->mat; 372 373 if (mat == NULL) 374 continue; 375 376 // We only include materials that 377 // have more than a base texture. 378 if (mat->getDetailSize() <= 0 || 379 mat->getDetailDistance() <= 0 || 380 mat->getDetailMap().isEmpty()) 381 continue; 382 383 // check for macro detail texture 384 if (!(mat->getMacroSize() <= 0 || mat->getMacroDistance() <= 0 || mat->getMacroMap().isEmpty())) 385 { 386 if (deferredMat) 387 features.addFeature(MFT_isDeferred, featureIndex); 388 features.addFeature(MFT_TerrainMacroMap, featureIndex); 389 } 390 391 if (deferredMat) 392 features.addFeature(MFT_isDeferred, featureIndex); 393 features.addFeature(MFT_TerrainDetailMap, featureIndex); 394 395 if (deferredMat) 396 { 397 if (!(mat->getORMConfigMap().isEmpty())) 398 { 399 features.addFeature(MFT_TerrainORMMap, featureIndex); 400 } 401 else 402 { 403 features.addFeature(MFT_DeferredTerrainBlankInfoMap, featureIndex); 404 } 405 } 406 407 if (mat->getInvertRoughness()) 408 features.addFeature(MFT_InvertRoughness, featureIndex); 409 410 normalMaps.increment(); 411 412 // Skip normal maps if we need to. 413 if (!disableNormalMaps && mat->getNormalMap().isNotEmpty()) 414 { 415 features.addFeature(MFT_TerrainNormalMap, featureIndex); 416 417 normalMaps.last().set(mat->getNormalMap(), 418 &GFXNormalMapProfile, "TerrainCellMaterial::_initShader() - NormalMap"); 419 420 GFXFormat normalFmt = normalMaps.last().getFormat(); 421 if (normalFmt == GFXFormatBC3) 422 features.addFeature(MFT_IsBC3nm, featureIndex); 423 else if (normalFmt == GFXFormatBC5) 424 features.addFeature(MFT_IsBC5nm, featureIndex); 425 426 // Do we need and can we do parallax mapping? 427 if (!disableParallaxMaps && 428 mat->getParallaxScale() > 0.0f && 429 !mat->useSideProjection()) 430 features.addFeature(MFT_TerrainParallaxMap, featureIndex); 431 } 432 433 // Is this layer got side projection? 434 if (mat->useSideProjection()) 435 features.addFeature(MFT_TerrainSideProject, featureIndex); 436 437 featureIndex++; 438 } 439 440 // New blending 441 if (matCount > 0 && !Con::getBoolVariable("$Terrain::LerpBlend", false)) 442 { 443 features.addFeature(MFT_TerrainHeightBlend); 444 } 445 446 MaterialFeatureData featureData; 447 featureData.features = features; 448 featureData.materialFeatures = features; 449 450 // Check to see how many vertex shader output 451 // registers we're gonna need. 452 U32 numTex = 0; 453 U32 numTexReg = 0; 454 for (U32 i = 0; i < features.getCount(); i++) 455 { 456 S32 index; 457 const FeatureType& type = features.getAt(i, &index); 458 ShaderFeature* sf = FEATUREMGR->getByType(type); 459 if (!sf) 460 continue; 461 462 sf->setProcessIndex(index); 463 ShaderFeature::Resources res = sf->getResources(featureData); 464 465 numTex += res.numTex; 466 numTexReg += res.numTexReg; 467 } 468 469 // Can we build the shader? 470 // 471 // NOTE: The 10 is sort of an abitrary SM 3.0 472 // limit. Its really supposed to be 11, but that 473 // always fails to compile so far. 474 // 475 if (numTex < GFX->getNumSamplers() && 476 numTexReg <= 10) 477 { 478 // NOTE: We really shouldn't be getting errors building the shaders, 479 // but we can generate more instructions than the ps_2_x will allow. 480 // 481 // There is no way to deal with this case that i know of other than 482 // letting the compile fail then recovering by trying to build it 483 // with fewer materials. 484 // 485 // We normally disable the shader error logging so that the user 486 // isn't fooled into thinking there is a real bug. That is until 487 // we get down to a single material. If a single material case 488 // fails it means it cannot generate any passes at all! 489 const bool logErrors = true;// matCount == 1; 490 GFXShader::setLogging(logErrors, true); 491 492 mShader = SHADERGEN->getShader(featureData, getGFXVertexFormat<TerrVertex>(), NULL, mSamplerNames); 493 } 494 495 // If we got a shader then we can continue. 496 if (mShader) 497 break; 498 499 // If the material count is already 1 then this 500 // is a real shader error... give up! 501 if (matCount <= 1) 502 return false; 503 504 // If we failed we next try half the input materials 505 // so that we can more quickly arrive at a valid shader. 506 matCount -= matCount / 2; 507 } 508 509 // Setup the constant buffer. 510 mConsts = mShader->allocConstBuffer(); 511 512 // Prepare the basic constants. 513 mModelViewProjConst = mShader->getShaderConstHandle("$modelview"); 514 mWorldViewOnlyConst = mShader->getShaderConstHandle("$worldViewOnly"); 515 mViewToObjConst = mShader->getShaderConstHandle("$viewToObj"); 516 mEyePosWorldConst = mShader->getShaderConstHandle("$eyePosWorld"); 517 mEyePosConst = mShader->getShaderConstHandle("$eyePos"); 518 mVEyeConst = mShader->getShaderConstHandle("$vEye"); 519 mLayerSizeConst = mShader->getShaderConstHandle("$layerSize"); 520 mObjTransConst = mShader->getShaderConstHandle("$objTrans"); 521 mWorldToObjConst = mShader->getShaderConstHandle("$worldToObj"); 522 mLightInfoBufferConst = mShader->getShaderConstHandle("$lightInfoBuffer"); 523 mBaseTexMapConst = mShader->getShaderConstHandle("$baseTexMap"); 524 mLayerTexConst = mShader->getShaderConstHandle("$layerTex"); 525 mFogDataConst = mShader->getShaderConstHandle("$fogData"); 526 mFogColorConst = mShader->getShaderConstHandle("$fogColor"); 527 mLightMapTexConst = mShader->getShaderConstHandle("$lightMapTex"); 528 mOneOverTerrainSizeConst = mShader->getShaderConstHandle("$oneOverTerrainSize"); 529 mSquareSizeConst = mShader->getShaderConstHandle("$squareSize"); 530 mBlendDepthConst = mShader->getShaderConstHandle("$baseBlendDepth"); 531 532 mLightParamsConst = mShader->getShaderConstHandle("$rtParamslightInfoBuffer"); 533 534 // Now prepare the basic stateblock. 535 GFXStateBlockDesc desc; 536 537 // We write to the zbuffer if this is a deferred 538 // material or if the deferred is disabled. 539 desc.setZReadWrite(true, !MATMGR->getDeferredEnabled() || 540 deferredMat || 541 reflectMat); 542 543 desc.samplersDefined = true; 544 if (mBaseTexMapConst->isValid()) 545 desc.samplers[mBaseTexMapConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); 546 547 if (mLayerTexConst->isValid()) 548 desc.samplers[mLayerTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); 549 550 if (mLightInfoBufferConst->isValid()) 551 desc.samplers[mLightInfoBufferConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); 552 553 if (mLightMapTexConst->isValid()) 554 desc.samplers[mLightMapTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); 555 556 const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy(); 557 558 mDetailInfoVArrayConst = mShader->getShaderConstHandle("$detailScaleAndFade"); 559 mDetailInfoPArrayConst = mShader->getShaderConstHandle("$detailIdStrengthParallax"); 560 mMacroInfoVArrayConst = mShader->getShaderConstHandle("$macroIdStrengthParallax"); 561 mMacroInfoPArrayConst = mShader->getShaderConstHandle("$macroIdStrengthParallax"); 562 563 mDetailTexArrayConst = mShader->getShaderConstHandle("$detailMapSampler"); 564 if (mDetailTexArrayConst->isValid()) 565 { 566 const S32 sampler = mDetailTexArrayConst->getSamplerRegister(); 567 568 desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); 569 desc.samplers[sampler].magFilter = GFXTextureFilterLinear; 570 desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; 571 572 if (maxAnisotropy > 1) 573 { 574 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 575 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 576 } 577 else 578 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 579 } 580 581 mMacroTexArrayConst = mShader->getShaderConstHandle("$macroMapSampler"); 582 if (mMacroTexArrayConst->isValid()) 583 { 584 const S32 sampler = mMacroTexArrayConst->getSamplerRegister(); 585 586 desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); 587 desc.samplers[sampler].magFilter = GFXTextureFilterLinear; 588 desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; 589 590 if (maxAnisotropy > 1) 591 { 592 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 593 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 594 } 595 else 596 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 597 } 598 599 mNormalTexArrayConst = mShader->getShaderConstHandle("$normalMapSampler"); 600 if (mNormalTexArrayConst->isValid()) 601 { 602 const S32 sampler = mNormalTexArrayConst->getSamplerRegister(); 603 604 desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); 605 desc.samplers[sampler].magFilter = GFXTextureFilterLinear; 606 desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; 607 608 if (maxAnisotropy > 1) 609 { 610 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 611 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 612 } 613 else 614 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 615 } 616 617 mOrmTexArrayConst = mShader->getShaderConstHandle("$ormMapSampler"); 618 if (mOrmTexArrayConst->isValid()) 619 { 620 GFXTextureProfile* profile = &GFXStaticTextureProfile; 621 622 const S32 sampler = mOrmTexArrayConst->getSamplerRegister(); 623 624 desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); 625 desc.samplers[sampler].magFilter = GFXTextureFilterLinear; 626 desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; 627 628 if (maxAnisotropy > 1) 629 { 630 desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; 631 desc.samplers[sampler].maxAnisotropy = maxAnisotropy; 632 } 633 else 634 desc.samplers[sampler].minFilter = GFXTextureFilterLinear; 635 } 636 637 for (U32 i = 0; i < matCount && !baseOnly; i++) 638 { 639 TerrainMaterial* mat = mMaterialInfos[i]->mat; 640 641 if (mat == NULL) 642 continue; 643 644 // We only include materials that 645 // have more than a base texture. 646 if (mat->getDetailSize() <= 0 || 647 mat->getDetailDistance() <= 0 || 648 mat->getDetailMap().isEmpty()) 649 continue; 650 651 mMaterialInfos[i]->mBlendDepthConst = mShader->getShaderConstHandle(avar("$blendDepth%d", i)); 652 mMaterialInfos[i]->mBlendContrastConst = mShader->getShaderConstHandle(avar("$blendContrast%d", i)); 653 } 654 655 // If we're doing deferred it requires some 656 // special stencil settings for it to work. 657 if ( deferredMat ) 658 desc.addDesc( RenderDeferredMgr::getOpaqueStenciWriteDesc( false ) ); 659 660 desc.setCullMode( GFXCullCCW ); 661 mStateBlock = GFX->createStateBlock(desc); 662 663 //reflection stateblock 664 desc.setCullMode( GFXCullCW ); 665 mReflectionStateBlock = GFX->createStateBlock(desc); 666 667 // Create the wireframe state blocks. 668 GFXStateBlockDesc wireframe( desc ); 669 wireframe.fillMode = GFXFillWireframe; 670 wireframe.setCullMode( GFXCullCCW ); 671 mWireframeStateBlock = GFX->createStateBlock( wireframe ); 672 673 return true; 674} 675 676void TerrainCellMaterial::_updateMaterialConsts( ) 677{ 678 PROFILE_SCOPE( TerrainCellMaterial_UpdateMaterialConsts ); 679 680 int detailMatCount = 0; 681 for (MaterialInfo* materialInfo : mMaterialInfos) 682 { 683 if (materialInfo == NULL) 684 continue; 685 686 TerrainMaterial* mat = materialInfo->mat; 687 688 if (mat == NULL) 689 continue; 690 691 // We only include materials that 692 // have more than a base texture. 693 if (mat->getDetailSize() <= 0 || 694 mat->getDetailDistance() <= 0 || 695 mat->getDetailMap().isEmpty()) 696 continue; 697 698 detailMatCount++; 699 } 700 701 if (detailMatCount == 0) 702 { 703 return; 704 } 705 706 AlignedArray<Point4F> detailInfoArray(detailMatCount, sizeof(Point4F)); 707 AlignedArray<Point4F> detailScaleAndFadeArray(detailMatCount, sizeof(Point4F)); 708 709 int detailIndex = 0; 710 for (MaterialInfo* matInfo : mMaterialInfos) 711 { 712 if (matInfo == NULL) 713 continue; 714 715 TerrainMaterial* mat = matInfo->mat; 716 717 if (mat == NULL) 718 continue; 719 720 // We only include materials that 721 // have more than a base texture. 722 if (mat->getDetailSize() <= 0 || 723 mat->getDetailDistance() <= 0 || 724 mat->getDetailMap().isEmpty()) 725 continue; 726 727 F32 detailSize = matInfo->mat->getDetailSize(); 728 F32 detailScale = 1.0f; 729 if ( !mIsZero( detailSize ) ) 730 detailScale = mTerrain->getWorldBlockSize() / detailSize; 731 732 // Scale the distance by the global scalar. 733 const F32 distance = mTerrain->smDetailScale * matInfo->mat->getDetailDistance(); 734 735 // NOTE: The negation of the y scale is to make up for 736 // my mistake early in development and passing the wrong 737 // y texture coord into the system. 738 // 739 // This negation fixes detail, normal, and parallax mapping 740 // without harming the layer id blending code. 741 // 742 // Eventually we should rework this to correct this little 743 // mistake, but there isn't really a hurry to. 744 // 745 Point4F detailScaleAndFade( detailScale, 746 -detailScale, 747 distance, 748 0 ); 749 750 if ( !mIsZero( distance ) ) 751 detailScaleAndFade.w = 1.0f / distance; 752 753 Point4F detailIdStrengthParallax( matInfo->layerId, 754 matInfo->mat->getDetailStrength(), 755 matInfo->mat->getParallaxScale(), 0 ); 756 757 detailScaleAndFadeArray[detailIndex] = detailScaleAndFade; 758 detailInfoArray[detailIndex] = detailIdStrengthParallax; 759 760 if (matInfo->mBlendDepthConst != NULL) 761 { 762 mConsts->setSafe(matInfo->mBlendDepthConst, matInfo->mat->getBlendDepth()); 763 } 764 765 if (matInfo->mBlendContrastConst != NULL) 766 { 767 mConsts->setSafe(matInfo->mBlendContrastConst, matInfo->mat->getBlendContrast()); 768 } 769 detailIndex++; 770 } 771 772 mConsts->setSafe(mDetailInfoVArrayConst, detailScaleAndFadeArray); 773 mConsts->setSafe(mDetailInfoPArrayConst, detailInfoArray); 774 775} 776 777bool TerrainCellMaterial::setupPass( const SceneRenderState *state, 778 const SceneData &sceneData ) 779{ 780 PROFILE_SCOPE( TerrainCellMaterial_SetupPass ); 781 782 if (mCurrPass > 0) 783 { 784 mCurrPass = 0; 785 return false; 786 } 787 788 mCurrPass++; 789 790 _updateMaterialConsts(); 791 792 if ( mBaseTexMapConst->isValid() ) 793 GFX->setTexture( mBaseTexMapConst->getSamplerRegister(), mTerrain->mBaseTex.getPointer() ); 794 795 if ( mLayerTexConst->isValid() ) 796 GFX->setTexture( mLayerTexConst->getSamplerRegister(), mTerrain->mLayerTex.getPointer() ); 797 798 if ( mLightMapTexConst->isValid() ) 799 GFX->setTexture( mLightMapTexConst->getSamplerRegister(), mTerrain->getLightMapTex() ); 800 801 if ( sceneData.wireframe ) 802 GFX->setStateBlock( mWireframeStateBlock ); 803 else if ( state->isReflectPass( )) 804 GFX->setStateBlock( mReflectionStateBlock ); 805 else 806 GFX->setStateBlock( mStateBlock ); 807 808 GFX->setShader( mShader ); 809 GFX->setShaderConstBuffer( mConsts ); 810 811 // Let the light manager prepare any light stuff it needs. 812 LIGHTMGR->setLightInfo( NULL, 813 NULL, 814 sceneData, 815 state, 816 0, 817 mConsts ); 818 819 if (mDetailTexArrayConst->isValid() && mTerrain->getDetailTextureArray().isValid()) 820 GFX->setTextureArray(mDetailTexArrayConst->getSamplerRegister(), mTerrain->getDetailTextureArray()); 821 if (mMacroTexArrayConst->isValid() && mTerrain->getMacroTextureArray().isValid()) 822 GFX->setTextureArray(mMacroTexArrayConst->getSamplerRegister(), mTerrain->getMacroTextureArray()); 823 if (mNormalTexArrayConst->isValid() && mTerrain->getNormalTextureArray().isValid()) 824 GFX->setTextureArray(mNormalTexArrayConst->getSamplerRegister(), mTerrain->getNormalTextureArray()); 825 if (mOrmTexArrayConst->isValid() && mTerrain->getOrmTextureArray().isValid()) 826 GFX->setTextureArray(mOrmTexArrayConst->getSamplerRegister(), mTerrain->getOrmTextureArray()); 827 828 mConsts->setSafe( mLayerSizeConst, (F32)mTerrain->mLayerTex.getWidth() ); 829 830 if ( mOneOverTerrainSizeConst->isValid() ) 831 { 832 F32 oneOverTerrainSize = 1.0f / mTerrain->getWorldBlockSize(); 833 mConsts->set( mOneOverTerrainSizeConst, oneOverTerrainSize ); 834 } 835 836 mConsts->setSafe( mSquareSizeConst, mTerrain->getSquareSize() ); 837 838 if ( mFogDataConst->isValid() ) 839 { 840 Point3F fogData; 841 fogData.x = sceneData.fogDensity; 842 fogData.y = sceneData.fogDensityOffset; 843 fogData.z = sceneData.fogHeightFalloff; 844 mConsts->set( mFogDataConst, fogData ); 845 } 846 847 if (String::isEmpty(Con::getVariable("$Terrain::BlendDepth"))) 848 { 849 mConsts->setSafe(mBlendDepthConst, 0.2f); 850 } 851 else 852 { 853 mConsts->setSafe(mBlendDepthConst, Con::getFloatVariable("$Terrain::BlendDepth")); 854 } 855 856 mConsts->setSafe( mFogColorConst, sceneData.fogColor ); 857 858 if ( mLightInfoBufferConst->isValid() && 859 mLightParamsConst->isValid() ) 860 { 861 if ( !mLightInfoTarget ) 862 mLightInfoTarget = NamedTexTarget::find( "diffuseLighting" ); 863 864 GFXTextureObject *texObject = mLightInfoTarget->getTexture(); 865 866 // TODO: Sometimes during reset of the light manager we get a 867 // NULL texture here. This is corrected on the next frame, but 868 // we should still investigate why that happens. 869 870 if ( texObject ) 871 { 872 GFX->setTexture( mLightInfoBufferConst->getSamplerRegister(), texObject ); 873 874 const Point3I &targetSz = texObject->getSize(); 875 const RectI &targetVp = mLightInfoTarget->getViewport(); 876 Point4F rtParams; 877 ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams); 878 mConsts->setSafe( mLightParamsConst, rtParams ); 879 } 880 } 881 882 return true; 883} 884 885BaseMatInstance* TerrainCellMaterial::getShadowMat() 886{ 887 // Find our material which has some settings 888 // defined on it in script. 889 Material *mat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" ); 890 891 // Create the material instance adding the feature which 892 // handles rendering terrain cut outs. 893 FeatureSet features = MATMGR->getDefaultFeatures(); 894 BaseMatInstance *matInst = mat->createMatInstance(); 895 if ( !matInst->init( features, getGFXVertexFormat<TerrVertex>() ) ) 896 { 897 delete matInst; 898 matInst = NULL; 899 } 900 901 return matInst; 902} 903 904