terrFeatureGLSL.cpp
Engine/source/terrain/glsl/terrFeatureGLSL.cpp
Public Variables
Detailed Description
Public Variables
MODULE_END
MODULE_INIT
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/glsl/terrFeatureGLSL.h" 26 27#include "terrain/terrFeatureTypes.h" 28#include "materials/materialFeatureTypes.h" 29#include "materials/materialFeatureData.h" 30#include "materials/processedMaterial.h" 31#include "gfx/gfxDevice.h" 32#include "shaderGen/langElement.h" 33#include "shaderGen/shaderOp.h" 34#include "shaderGen/featureMgr.h" 35#include "shaderGen/shaderGen.h" 36#include "core/module.h" 37 38namespace 39{ 40 void register_glsl_shader_features_for_terrain(GFXAdapterType type) 41 { 42 if(type != OpenGL) 43 return; 44 45 FEATUREMGR->registerFeature( MFT_TerrainBaseMap, new TerrainBaseMapFeatGLSL ); 46 FEATUREMGR->registerFeature( MFT_TerrainParallaxMap, new NamedFeatureGLSL( "Terrain Parallax Texture" ) ); 47 FEATUREMGR->registerFeature( MFT_TerrainDetailMap, new TerrainDetailMapFeatGLSL ); 48 FEATUREMGR->registerFeature( MFT_TerrainNormalMap, new TerrainNormalMapFeatGLSL ); 49 FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new TerrainMacroMapFeatGLSL ); 50 FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatGLSL ); 51 FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureGLSL( "Terrain Side Projection" ) ); 52 FEATUREMGR->registerFeature( MFT_TerrainAdditive, new TerrainAdditiveFeatGLSL ); 53 FEATUREMGR->registerFeature( MFT_DeferredTerrainBaseMap, new TerrainBaseMapFeatGLSL ); 54 FEATUREMGR->registerFeature( MFT_DeferredTerrainMacroMap, new TerrainMacroMapFeatGLSL ); 55 FEATUREMGR->registerFeature( MFT_DeferredTerrainDetailMap, new TerrainDetailMapFeatGLSL ); 56 FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatGLSL ); 57 } 58 59}; 60 61MODULE_BEGIN( TerrainFeatGLSL ) 62 63 MODULE_INIT_AFTER( ShaderGen ) 64 65 MODULE_INIT 66 { 67 SHADERGEN->getFeatureInitSignal().notify(®ister_glsl_shader_features_for_terrain); 68 } 69 70MODULE_END; 71 72 73TerrainFeatGLSL::TerrainFeatGLSL() 74 : mTorqueDep( "shaders/common/gl/torque.glsl" ) 75 { 76 addDependency( &mTorqueDep ); 77 } 78 79Var* TerrainFeatGLSL::_getUniformVar( const char *name, const char *type, ConstantSortPosition csp ) 80{ 81 Var *theVar = (Var*)LangElement::find( name ); 82 if ( !theVar ) 83 { 84 theVar = new Var; 85 theVar->setType( type ); 86 theVar->setName( name ); 87 theVar->uniform = true; 88 theVar->constSortPos = csp; 89 } 90 91 return theVar; 92} 93 94Var* TerrainFeatGLSL::_getInDetailCoord( Vector<ShaderComponent*> &componentList ) 95{ 96 String name( String::ToString( "detCoord%d", getProcessIndex() ) ); 97 Var *inDet = (Var*)LangElement::find( name ); 98 99 if ( !inDet ) 100 { 101 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 102 103 inDet = connectComp->getElement( RT_TEXCOORD ); 104 inDet->setName( name ); 105 inDet->setStructName( "IN" ); 106 inDet->setType( "vec4" ); 107 inDet->mapsToSampler = true; 108 } 109 110 return inDet; 111} 112 113Var* TerrainFeatGLSL::_getInMacroCoord( Vector<ShaderComponent*> &componentList ) 114{ 115 String name( String::ToString( "macroCoord%d", getProcessIndex() ) ); 116 Var *inDet = (Var*)LangElement::find( name ); 117 118 if ( !inDet ) 119 { 120 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 121 122 inDet = connectComp->getElement( RT_TEXCOORD ); 123 inDet->setName( name ); 124 inDet->setStructName( "IN" ); 125 inDet->setType( "vec4" ); 126 inDet->mapsToSampler = true; 127 } 128 129 return inDet; 130} 131 132Var* TerrainFeatGLSL::_getNormalMapTex() 133{ 134 String name( String::ToString( "normalMap%d", getProcessIndex() ) ); 135 Var *normalMap = (Var*)LangElement::find( name ); 136 137 if ( !normalMap ) 138 { 139 normalMap = new Var; 140 normalMap->setType( "sampler2D" ); 141 normalMap->setName( name ); 142 normalMap->uniform = true; 143 normalMap->sampler = true; 144 normalMap->constNum = Var::getTexUnitNum(); 145 } 146 147 return normalMap; 148} 149 150Var* TerrainFeatGLSL::_getDetailIdStrengthParallax() 151{ 152 String name( String::ToString( "detailIdStrengthParallax%d", getProcessIndex() ) ); 153 154 Var *detailInfo = (Var*)LangElement::find( name ); 155 if ( !detailInfo ) 156 { 157 detailInfo = new Var; 158 detailInfo->setType( "vec3" ); 159 detailInfo->setName( name ); 160 detailInfo->uniform = true; 161 detailInfo->constSortPos = cspPotentialPrimitive; 162 } 163 164 return detailInfo; 165} 166 167Var* TerrainFeatGLSL::_getMacroIdStrengthParallax() 168{ 169 String name( String::ToString( "macroIdStrengthParallax%d", getProcessIndex() ) ); 170 171 Var *detailInfo = (Var*)LangElement::find( name ); 172 if ( !detailInfo ) 173 { 174 detailInfo = new Var; 175 detailInfo->setType( "vec3" ); 176 detailInfo->setName( name ); 177 detailInfo->uniform = true; 178 detailInfo->constSortPos = cspPotentialPrimitive; 179 } 180 181 return detailInfo; 182} 183 184 185void TerrainBaseMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 186 const MaterialFeatureData &fd ) 187{ 188 MultiLine *meta = new MultiLine; 189 output = meta; 190 191 // Generate the incoming texture var. 192 Var *inTex; 193 { 194 Var *inPos = (Var*)LangElement::find( "inPosition" ); 195 if ( !inPos ) 196 inPos = (Var*)LangElement::find( "position" ); 197 198 inTex = new Var( "texCoord", "vec3" ); 199 200 Var *oneOverTerrainSize = _getUniformVar( "oneOverTerrainSize", "float", cspPass ); 201 202 // NOTE: The y coord here should be negative to have 203 // the texture maps not end up flipped which also caused 204 // normal and parallax mapping to be incorrect. 205 // 206 // This mistake early in development means that the layer 207 // id bilinear blend depends on it being that way. 208 // 209 // So instead i fixed this by flipping the base and detail 210 // coord y scale to compensate when rendering. 211 // 212 meta->addStatement( new GenOp( " @ = @.xyz * float3( @, @, -@ );\r\n", 213 new DecOp( inTex ), inPos, oneOverTerrainSize, oneOverTerrainSize, oneOverTerrainSize ) ); 214 } 215 216 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 217 218 // Pass the texture coord to the pixel shader. 219 Var *outTex = connectComp->getElement( RT_TEXCOORD ); 220 outTex->setName( "outTexCoord" ); 221 outTex->setStructName( "OUT" ); 222 outTex->setType( "vec3" ); 223 outTex->mapsToSampler = true; 224 meta->addStatement( new GenOp( " @.xy = @.xy;\r\n", outTex, inTex ) ); 225 226 // If this shader has a side projected layer then we 227 // pass the dot product between the +Y and the normal 228 // thru outTexCoord.z for use in blending the textures. 229 if ( fd.features.hasFeature( MFT_TerrainSideProject ) ) 230 { 231 Var *inNormal = (Var*)LangElement::find( "normal" ); 232 meta->addStatement( 233 new GenOp( " @.z = pow( abs( dot( normalize( float3( @.x, @.y, 0 ) ), float3( 0, 1, 0 ) ) ), 10.0 );\r\n", 234 outTex, inNormal, inNormal ) ); 235 } 236 else 237 meta->addStatement( new GenOp( " @.z = 0;\r\n", outTex ) ); 238 239 // HACK: This is sort of lazy... we generate the tanget 240 // vector here so that we're sure it exists in the parallax 241 // and normal features which will expect "T" to exist. 242 // 243 // If this shader doesn't use it the shader compiler will 244 // optimize away this code. 245 // 246 Var *inTangentZ = getVertTexCoord( "tcTangentZ" ); 247 Var *inTanget = new Var( "T", "vec3" ); 248 Var *squareSize = _getUniformVar( "squareSize", "float", cspPass ); 249 meta->addStatement( new GenOp( " @ = normalize( float3( @, 0, @ ) );\r\n", 250 new DecOp( inTanget ), squareSize, inTangentZ ) ); 251} 252 253void TerrainBaseMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 254 const MaterialFeatureData &fd ) 255{ 256 // grab connector texcoord register 257 Var *texCoord = getInTexCoord( "texCoord", "vec3", true, componentList ); 258 259 // create texture var 260 Var *diffuseMap = new Var; 261 diffuseMap->setType( "sampler2D" ); 262 diffuseMap->setName( "baseTexMap" ); 263 diffuseMap->uniform = true; 264 diffuseMap->sampler = true; 265 diffuseMap->constNum = Var::getTexUnitNum(); // used as texture unit num here 266 267 MultiLine *meta = new MultiLine; 268 269 Var *baseColor = new Var; 270 baseColor->setType( "vec4" ); 271 baseColor->setName( "baseColor" ); 272 meta->addStatement( new GenOp( " @ = tex2D( @, @.xy );\r\n", new DecOp( baseColor ), diffuseMap, texCoord ) ); 273 meta->addStatement(new GenOp(" @ = toLinear(@);\r\n", baseColor, baseColor)); 274 275 ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; 276 277 if(fd.features.hasFeature(MFT_isDeferred)) 278 { 279 target= ShaderFeature::RenderTarget1; 280 } 281 meta->addStatement( new GenOp( " @;\r\n", assignColor( baseColor, Material::Mul,NULL,target ) ) ); 282 283 output = meta; 284} 285 286ShaderFeature::Resources TerrainBaseMapFeatGLSL::getResources( const MaterialFeatureData &fd ) 287{ 288 Resources res; 289 res.numTexReg = 1; 290 res.numTex = 1; 291 292 return res; 293} 294 295U32 TerrainBaseMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const 296{ 297 return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget; 298} 299 300TerrainDetailMapFeatGLSL::TerrainDetailMapFeatGLSL() 301 : mTorqueDep( "shaders/common/gl/torque.glsl" ), 302 mTerrainDep( "shaders/common/terrain/terrain.glsl" ) 303 304{ 305 addDependency( &mTorqueDep ); 306 addDependency( &mTerrainDep ); 307} 308 309void TerrainDetailMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 310 const MaterialFeatureData &fd ) 311{ 312 const S32 detailIndex = getProcessIndex(); 313 314 // Grab incoming texture coords... the base map feature 315 // made sure this was created. 316 Var *inTex = (Var*)LangElement::find( "texCoord" ); 317 AssertFatal( inTex, "The texture coord is missing!" ); 318 319 // Grab the input position. 320 Var *inPos = (Var*)LangElement::find( "inPosition" ); 321 if ( !inPos ) 322 inPos = (Var*)LangElement::find( "position" ); 323 324 // Get the object space eye position. 325 Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive ); 326 327 MultiLine *meta = new MultiLine; 328 329 // If we have parallax mapping then make sure we've sent 330 // the negative view vector to the pixel shader. 331 if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) && 332 !LangElement::find( "outNegViewTS" ) ) 333 { 334 // Get the object to tangent transform which 335 // will consume 3 output registers. 336 Var *objToTangentSpace = getOutObjToTangentSpace( componentList, meta, fd ); 337 338 // Now use a single output register to send the negative 339 // view vector in tangent space to the pixel shader. 340 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 341 Var *outNegViewTS = connectComp->getElement( RT_TEXCOORD ); 342 outNegViewTS->setName( "outNegViewTS" ); 343 outNegViewTS->setStructName( "OUT" ); 344 outNegViewTS->setType( "vec3" ); 345 meta->addStatement( new GenOp( " @ = tMul( @, float3( @ - @.xyz ) );\r\n", 346 outNegViewTS, objToTangentSpace, eyePos, inPos ) ); 347 } 348 349 // Get the distance from the eye to this vertex. 350 Var *dist = (Var*)LangElement::find( "dist" ); 351 if ( !dist ) 352 { 353 dist = new Var; 354 dist->setType( "float" ); 355 dist->setName( "dist" ); 356 357 meta->addStatement( new GenOp( " @ = distance( @.xyz, @ );\r\n", 358 new DecOp( dist ), inPos, eyePos ) ); 359 } 360 361 // grab connector texcoord register 362 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 363 Var *outTex = connectComp->getElement( RT_TEXCOORD ); 364 outTex->setName( String::ToString( "detCoord%d", detailIndex ) ); 365 outTex->setStructName( "OUT" ); 366 outTex->setType( "vec4" ); 367 outTex->mapsToSampler = true; 368 369 // Get the detail scale and fade info. 370 Var *detScaleAndFade = new Var; 371 detScaleAndFade->setType( "vec4" ); 372 detScaleAndFade->setName( String::ToString( "detailScaleAndFade%d", detailIndex ) ); 373 detScaleAndFade->uniform = true; 374 detScaleAndFade->constSortPos = cspPotentialPrimitive; 375 376 // Setup the detail coord. 377 // 378 // NOTE: You see here we scale the texture coord by 'xyx' 379 // to generate the detail coord. This y is here because 380 // its scale is flipped to correct for the non negative y 381 // in texCoord. 382 // 383 // See TerrainBaseMapFeatGLSL::processVert(). 384 // 385 meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) ); 386 387 // And sneak the detail fade thru the w detailCoord. 388 meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", 389 outTex, detScaleAndFade, dist, detScaleAndFade ) ); 390 391 output = meta; 392} 393 394void TerrainDetailMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 395 const MaterialFeatureData &fd ) 396{ 397 const S32 detailIndex = getProcessIndex(); 398 Var *inTex = getVertTexCoord( "texCoord" ); 399 400 MultiLine *meta = new MultiLine; 401 402 // We need the negative tangent space view vector 403 // as in parallax mapping we step towards the camera. 404 Var *negViewTS = (Var*)LangElement::find( "negViewTS" ); 405 if ( !negViewTS && 406 fd.features.hasFeature( MFT_TerrainParallaxMap ) ) 407 { 408 Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" ); 409 if ( !inNegViewTS ) 410 { 411 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 412 inNegViewTS = connectComp->getElement( RT_TEXCOORD ); 413 inNegViewTS->setName( "outNegViewTS" ); 414 inNegViewTS->setStructName( "IN" ); 415 inNegViewTS->setType( "vec3" ); 416 } 417 418 negViewTS = new Var( "negViewTS", "vec3" ); 419 meta->addStatement( new GenOp( " @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) ); 420 } 421 422 // Get the layer samples. 423 Var *layerSample = (Var*)LangElement::find( "layerSample" ); 424 if ( !layerSample ) 425 { 426 layerSample = new Var; 427 layerSample->setType( "vec4" ); 428 layerSample->setName( "layerSample" ); 429 430 // Get the layer texture var 431 Var *layerTex = new Var; 432 layerTex->setType( "sampler2D" ); 433 layerTex->setName( "layerTex" ); 434 layerTex->uniform = true; 435 layerTex->sampler = true; 436 layerTex->constNum = Var::getTexUnitNum(); 437 438 // Read the layer texture to get the samples. 439 meta->addStatement( new GenOp( " @ = round( tex2D( @, @.xy ) * 255.0f );\r\n", 440 new DecOp( layerSample ), layerTex, inTex ) ); 441 } 442 443 Var *layerSize = (Var*)LangElement::find( "layerSize" ); 444 if ( !layerSize ) 445 { 446 layerSize = new Var; 447 layerSize->setType( "float" ); 448 layerSize->setName( "layerSize" ); 449 layerSize->uniform = true; 450 layerSize->constSortPos = cspPass; 451 } 452 453 // Grab the incoming detail coord. 454 Var *inDet = _getInDetailCoord( componentList ); 455 456 // Get the detail id. 457 Var *detailInfo = _getDetailIdStrengthParallax(); 458 459 // Create the detail blend var. 460 Var *detailBlend = new Var; 461 detailBlend->setType( "float" ); 462 detailBlend->setName( String::ToString( "detailBlend%d", detailIndex ) ); 463 464 // Calculate the blend for this detail texture. 465 meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n", 466 new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) ); 467 468 // New terrain 469 470 Var *lerpBlend = (Var*)LangElement::find("lerpBlend"); 471 if (!lerpBlend) 472 { 473 lerpBlend = new Var; 474 lerpBlend->setType("float"); 475 lerpBlend->setName("lerpBlend"); 476 lerpBlend->uniform = true; 477 lerpBlend->constSortPos = cspPrimitive; 478 } 479 480 481 Var *blendDepth = (Var*)LangElement::find(String::ToString("blendDepth%d", detailIndex)); 482 if (!blendDepth) 483 { 484 blendDepth = new Var; 485 blendDepth->setType("float"); 486 blendDepth->setName(String::ToString("blendDepth%d", detailIndex)); 487 blendDepth->uniform = true; 488 blendDepth->constSortPos = cspPrimitive; 489 } 490 491 ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; 492 493 if(fd.features.hasFeature( MFT_DeferredTerrainDetailMap )) 494 target= ShaderFeature::RenderTarget1; 495 496 Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) ); 497 498 if (!outColor) 499 { 500 // create color var 501 outColor = new Var; 502 outColor->setType("float4"); 503 outColor->setName("col"); 504 outColor->setStructName("OUT"); 505 meta->addStatement(new GenOp(" @;\r\n", outColor)); 506 } 507 508 Var *detailColor = (Var*)LangElement::find("detailColor"); 509 if (!detailColor) 510 { 511 detailColor = new Var; 512 detailColor->setType("float4"); 513 detailColor->setName("detailColor"); 514 meta->addStatement(new GenOp(" @;\r\n", new DecOp(detailColor))); 515 } 516 517 // Get the detail texture. 518 Var *detailMap = new Var; 519 detailMap->setType("sampler2D"); 520 detailMap->setName(String::ToString("detailMap%d", detailIndex)); 521 detailMap->uniform = true; 522 detailMap->sampler = true; 523 detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here 524 525 // Get the normal map texture. 526 Var *normalMap = _getNormalMapTex(); 527 528 // Issue happens somewhere here ----- 529 530 // Sample the normal map. 531 // 532 // We take two normal samples and lerp between them for 533 // side projection layers... else a single sample. 534 LangElement *texOp; 535 536 // Note that we're doing the standard greyscale detail 537 // map technique here which can darken and lighten the 538 // diffuse texture. 539 // 540 // We take two color samples and lerp between them for 541 // side projection layers... else a single sample. 542 // 543 if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex)) 544 { 545 meta->addStatement(new GenOp(" @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", 546 detailColor, detailMap, inDet, detailMap, inDet, inTex)); 547 548 texOp = new GenOp("lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )", 549 normalMap, inDet, normalMap, inDet, inTex); 550 } 551 else 552 { 553 meta->addStatement(new GenOp(" @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", 554 detailColor, detailMap, inDet)); 555 556 texOp = new GenOp("tex2D(@, @.xy)", normalMap, inDet); 557 } 558 559 // New terrain 560 561 // Get a var and accumulate the blend amount. 562 Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); 563 if ( !blendTotal ) 564 { 565 blendTotal = new Var; 566 blendTotal->setName( "blendTotal" ); 567 blendTotal->setType( "float" ); 568 meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) ); 569 } 570 571 // Add to the blend total. 572 meta->addStatement(new GenOp(" @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend)); 573 574 // If we had a parallax feature... then factor in the parallax 575 // amount so that it fades out with the layer blending. 576 if ( fd.features.hasFeature( MFT_TerrainParallaxMap, detailIndex ) ) 577 { 578 // Get the rest of our inputs. 579 Var *normalMap = _getNormalMapTex(); 580 581 // Call the library function to do the rest. 582 if (fd.features.hasFeature(MFT_IsDXTnm, detailIndex)) 583 { 584 meta->addStatement(new GenOp(" @.xy += parallaxOffsetDxtnm( @, @.xy, @, @.z * @ );\r\n", 585 inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend)); 586 } 587 else 588 { 589 meta->addStatement(new GenOp(" @.xy += parallaxOffset( @, @.xy, @, @.z * @ );\r\n", 590 inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend)); 591 } 592 } 593 594 // If we're using SM 3.0 then take advantage of 595 // dynamic branching to skip layers per-pixel. 596 597 598 if ( GFX->getPixelShaderVersion() >= 3.0f ) 599 meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); 600 601 meta->addStatement( new GenOp( " {\r\n" ) ); 602 603 // Note that we're doing the standard greyscale detail 604 // map technique here which can darken and lighten the 605 // diffuse texture. 606 // 607 // We take two color samples and lerp between them for 608 // side projection layers... else a single sample. 609 // 610 if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) ) 611 { 612 meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", 613 detailColor, detailMap, inDet, detailMap, inDet, inTex ) ); 614 } 615 else 616 { 617 meta->addStatement( new GenOp( " @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", 618 detailColor, detailMap, inDet ) ); 619 } 620 621 meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", 622 detailColor, detailInfo, inDet ) ); 623 624 meta->addStatement( new GenOp( " @ += @ * @;\r\n", 625 outColor, detailColor, detailBlend)); 626 627 meta->addStatement( new GenOp( " }\r\n" ) ); 628 629 output = meta; 630} 631 632ShaderFeature::Resources TerrainDetailMapFeatGLSL::getResources( const MaterialFeatureData &fd ) 633{ 634 Resources res; 635 636 if ( getProcessIndex() == 0 ) 637 { 638 // If this is the first detail pass then we 639 // samples from the layer tex. 640 res.numTex += 1; 641 642 // If this material also does parallax then it 643 // will generate the negative view vector and the 644 // worldToTanget transform. 645 if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) ) 646 res.numTexReg += 4; 647 } 648 649 // sample from the detail texture for diffuse coloring. 650 res.numTex += 1; 651 652 // If we have parallax for this layer then we'll also 653 // be sampling the normal map for the parallax heightmap. 654 if ( fd.features.hasFeature( MFT_TerrainParallaxMap, getProcessIndex() ) ) 655 res.numTex += 1; 656 657 // Finally we always send the detail texture 658 // coord to the pixel shader. 659 res.numTexReg += 1; 660 661 return res; 662} 663 664U32 TerrainDetailMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const 665{ 666 return fd.features[MFT_DeferredTerrainDetailMap] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget; 667} 668 669 670TerrainMacroMapFeatGLSL::TerrainMacroMapFeatGLSL() 671 : mTorqueDep( "shaders/common/gl/torque.glsl" ), 672 mTerrainDep( "shaders/common/terrain/terrain.glsl" ) 673 674{ 675 addDependency( &mTorqueDep ); 676 addDependency( &mTerrainDep ); 677} 678 679 680void TerrainMacroMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 681 const MaterialFeatureData &fd ) 682{ 683 const S32 detailIndex = getProcessIndex(); 684 685 // Grab incoming texture coords... the base map feature 686 // made sure this was created. 687 Var *inTex = (Var*)LangElement::find( "texCoord" ); 688 AssertFatal( inTex, "The texture coord is missing!" ); 689 690 // Grab the input position. 691 Var *inPos = (Var*)LangElement::find( "inPosition" ); 692 if ( !inPos ) 693 inPos = (Var*)LangElement::find( "position" ); 694 695 // Get the object space eye position. 696 Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive ); 697 698 MultiLine *meta = new MultiLine; 699 700 // Get the distance from the eye to this vertex. 701 Var *dist = (Var*)LangElement::find( "macroDist" ); 702 if ( !dist ) 703 { 704 dist = new Var; 705 dist->setType( "float" ); 706 dist->setName( "macroDist" ); 707 708 meta->addStatement( new GenOp( " @ = distance( @.xyz, @ );\r\n", 709 new DecOp( dist ), inPos, eyePos ) ); 710 } 711 712 // grab connector texcoord register 713 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 714 Var *outTex = connectComp->getElement( RT_TEXCOORD ); 715 outTex->setName( String::ToString( "macroCoord%d", detailIndex ) ); 716 outTex->setStructName( "OUT" ); 717 outTex->setType( "vec4" ); 718 outTex->mapsToSampler = true; 719 720 // Get the detail scale and fade info. 721 Var *detScaleAndFade = new Var; 722 detScaleAndFade->setType( "vec4" ); 723 detScaleAndFade->setName( String::ToString( "macroScaleAndFade%d", detailIndex ) ); 724 detScaleAndFade->uniform = true; 725 detScaleAndFade->constSortPos = cspPotentialPrimitive; 726 727 // Setup the detail coord. 728 meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) ); 729 730 // And sneak the detail fade thru the w detailCoord. 731 meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", 732 outTex, detScaleAndFade, dist, detScaleAndFade ) ); 733 734 output = meta; 735} 736 737 738void TerrainMacroMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 739 const MaterialFeatureData &fd ) 740{ 741 const S32 detailIndex = getProcessIndex(); 742 Var *inTex = getVertTexCoord( "texCoord" ); 743 744 MultiLine *meta = new MultiLine; 745 746 // We need the negative tangent space view vector 747 // as in parallax mapping we step towards the camera. 748 Var *negViewTS = (Var*)LangElement::find( "negViewTS" ); 749 if ( !negViewTS && 750 fd.features.hasFeature( MFT_TerrainParallaxMap ) ) 751 { 752 Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" ); 753 if ( !inNegViewTS ) 754 { 755 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] ); 756 inNegViewTS = connectComp->getElement( RT_TEXCOORD ); 757 inNegViewTS->setName( "outNegViewTS" ); 758 inNegViewTS->setStructName( "IN" ); 759 inNegViewTS->setType( "vec3" ); 760 } 761 762 negViewTS = new Var( "negViewTS", "vec3" ); 763 meta->addStatement( new GenOp( " @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) ); 764 } 765 766 // Get the layer samples. 767 Var *layerSample = (Var*)LangElement::find( "layerSample" ); 768 if ( !layerSample ) 769 { 770 layerSample = new Var; 771 layerSample->setType( "vec4" ); 772 layerSample->setName( "layerSample" ); 773 774 // Get the layer texture var 775 Var *layerTex = new Var; 776 layerTex->setType( "sampler2D" ); 777 layerTex->setName( "macrolayerTex" ); 778 layerTex->uniform = true; 779 layerTex->sampler = true; 780 layerTex->constNum = Var::getTexUnitNum(); 781 782 // Read the layer texture to get the samples. 783 meta->addStatement( new GenOp( " @ = round( tex2D( @, @.xy ) * 255.0f );\r\n", 784 new DecOp( layerSample ), layerTex, inTex ) ); 785 } 786 787 Var *layerSize = (Var*)LangElement::find( "layerSize" ); 788 if ( !layerSize ) 789 { 790 layerSize = new Var; 791 layerSize->setType( "float" ); 792 layerSize->setName( "layerSize" ); 793 layerSize->uniform = true; 794 layerSize->constSortPos = cspPass; 795 } 796 797 // Grab the incoming detail coord. 798 Var *inDet = _getInMacroCoord( componentList ); 799 800 // Get the detail id. 801 Var *detailInfo = _getMacroIdStrengthParallax(); 802 803 // Create the detail blend var. 804 Var *detailBlend = new Var; 805 detailBlend->setType( "float" ); 806 detailBlend->setName( String::ToString( "macroBlend%d", detailIndex ) ); 807 808 // Calculate the blend for this detail texture. 809 meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n", 810 new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) ); 811 812 // Get a var and accumulate the blend amount. 813 Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); 814 if ( !blendTotal ) 815 { 816 blendTotal = new Var; 817 //blendTotal->setName( "blendTotal" ); 818 blendTotal->setName( "blendTotal" ); 819 blendTotal->setType( "float" ); 820 meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) ); 821 } 822 823 // Add to the blend total. 824 meta->addStatement(new GenOp(" @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend)); 825 826 Var *detailColor = (Var*)LangElement::find( "macroColor" ); 827 if ( !detailColor ) 828 { 829 detailColor = new Var; 830 detailColor->setType( "vec4" ); 831 detailColor->setName( "macroColor" ); 832 meta->addStatement( new GenOp( " @;\r\n", new DecOp( detailColor ) ) ); 833 } 834 835 // Get the detail texture. 836 Var *detailMap = new Var; 837 detailMap->setType( "sampler2D" ); 838 detailMap->setName( String::ToString( "macroMap%d", detailIndex ) ); 839 detailMap->uniform = true; 840 detailMap->sampler = true; 841 detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here 842 843 // If we're using SM 3.0 then take advantage of 844 // dynamic branching to skip layers per-pixel. 845 if ( GFX->getPixelShaderVersion() >= 3.0f ) 846 meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); 847 848 meta->addStatement( new GenOp( " {\r\n" ) ); 849 850 // Note that we're doing the standard greyscale detail 851 // map technique here which can darken and lighten the 852 // diffuse texture. 853 // 854 // We take two color samples and lerp between them for 855 // side projection layers... else a single sample. 856 // 857 if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) ) 858 { 859 meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", 860 detailColor, detailMap, inDet, detailMap, inDet, inTex ) ); 861 } 862 else 863 { 864 meta->addStatement( new GenOp( " @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", 865 detailColor, detailMap, inDet ) ); 866 } 867 868 meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", 869 detailColor, detailInfo, inDet ) ); 870 ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; 871 872 if(fd.features.hasFeature(MFT_DeferredTerrainMacroMap)) 873 target= ShaderFeature::RenderTarget1; 874 875 Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) ); 876 877 meta->addStatement(new GenOp(" @ += @ * @;\r\n", 878 outColor, detailColor, detailBlend)); 879 880 meta->addStatement( new GenOp( " }\r\n" ) ); 881 882 output = meta; 883} 884 885 886 887ShaderFeature::Resources TerrainMacroMapFeatGLSL::getResources( const MaterialFeatureData &fd ) 888{ 889 Resources res; 890 891 if ( getProcessIndex() == 0 ) 892 { 893 // If this is the first detail pass then we 894 // samples from the layer tex. 895 res.numTex += 1; 896 } 897 898 res.numTex += 1; 899 900 // Finally we always send the detail texture 901 // coord to the pixel shader. 902 res.numTexReg += 1; 903 904 return res; 905} 906 907U32 TerrainMacroMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const 908{ 909 return fd.features[MFT_DeferredTerrainMacroMap] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget; 910} 911 912void TerrainNormalMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 913 const MaterialFeatureData &fd ) 914{ 915 // We only need to process normals during the prepass. 916 if ( !fd.features.hasFeature( MFT_PrePassConditioner ) ) 917 return; 918 919 MultiLine *meta = new MultiLine; 920 921 // Make sure the world to tangent transform 922 // is created and available for the pixel shader. 923 getOutViewToTangent( componentList, meta, fd ); 924 925 output = meta; 926} 927 928void TerrainNormalMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 929 const MaterialFeatureData &fd ) 930{ 931 932 MultiLine *meta = new MultiLine; 933 934 Var *viewToTangent = getInViewToTangent( componentList ); 935 936 // This var is read from GBufferConditionerGLSL and 937 // used in the prepass output. 938 Var *gbNormal = (Var*)LangElement::find( "gbNormal" ); 939 if ( !gbNormal ) 940 { 941 gbNormal = new Var; 942 gbNormal->setName( "gbNormal" ); 943 gbNormal->setType( "vec3" ); 944 meta->addStatement( new GenOp( " @ = tGetMatrix3Row(@, 2);\r\n", new DecOp( gbNormal ), viewToTangent ) ); 945 } 946 947 const S32 normalIndex = getProcessIndex(); 948 949 Var *detailBlend = (Var*)LangElement::find( String::ToString( "detailBlend%d", normalIndex ) ); 950 AssertFatal( detailBlend, "The detail blend is missing!" ); 951 952 // If we're using SM 3.0 then take advantage of 953 // dynamic branching to skip layers per-pixel. 954 if ( GFX->getPixelShaderVersion() >= 3.0f ) 955 meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); 956 957 meta->addStatement( new GenOp( " {\r\n" ) ); 958 959 // Get the normal map texture. 960 Var *normalMap = _getNormalMapTex(); 961 962 /// Get the texture coord. 963 Var *inDet = _getInDetailCoord( componentList ); 964 Var *inTex = getVertTexCoord( "texCoord" ); 965 966 // Sample the normal map. 967 // 968 // We take two normal samples and lerp between them for 969 // side projection layers... else a single sample. 970 LangElement *texOp; 971 if ( fd.features.hasFeature( MFT_TerrainSideProject, normalIndex ) ) 972 { 973 texOp = new GenOp( "lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )", 974 normalMap, inDet, normalMap, inDet, inTex ); 975 } 976 else 977 texOp = new GenOp( "tex2D(@, @.xy)", normalMap, inDet ); 978 979 // create bump normal 980 Var *bumpNorm = new Var; 981 bumpNorm->setName( "bumpNormal" ); 982 bumpNorm->setType( "vec4" ); 983 984 LangElement *bumpNormDecl = new DecOp( bumpNorm ); 985 meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) ); 986 987 // Normalize is done later... 988 // Note: The reverse mul order is intentional. Affine matrix. 989 meta->addStatement( new GenOp( " @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n", 990 gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet ) ); 991 992 // End the conditional block. 993 meta->addStatement( new GenOp( " }\r\n" ) ); 994 995 // If this is the last normal map then we 996 // can test to see the total blend value 997 // to see if we should clip the result. 998 //if ( fd.features.getNextFeatureIndex( MFT_TerrainNormalMap, normalIndex ) == -1 ) 999 //meta->addStatement( new GenOp( " clip( @ - 0.0001f );\r\n", blendTotal ) ); 1000 1001 output = meta; 1002} 1003 1004ShaderFeature::Resources TerrainNormalMapFeatGLSL::getResources( const MaterialFeatureData &fd ) 1005{ 1006 Resources res; 1007 1008 // We only need to process normals during the prepass. 1009 if ( fd.features.hasFeature( MFT_PrePassConditioner ) ) 1010 { 1011 // If this is the first normal map and there 1012 // are no parallax features then we will 1013 // generate the worldToTanget transform. 1014 if ( !fd.features.hasFeature( MFT_TerrainParallaxMap ) && 1015 ( getProcessIndex() == 0 || !fd.features.hasFeature( MFT_TerrainNormalMap, getProcessIndex() - 1 ) ) ) 1016 res.numTexReg = 3; 1017 1018 res.numTex = 1; 1019 } 1020 1021 return res; 1022} 1023 1024void TerrainLightMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 1025 const MaterialFeatureData &fd ) 1026{ 1027 // grab connector texcoord register 1028 Var *inTex = (Var*)LangElement::find( "texCoord" ); 1029 if ( !inTex ) 1030 return; 1031 1032 // Get the lightmap texture. 1033 Var *lightMap = new Var; 1034 lightMap->setType( "sampler2D" ); 1035 lightMap->setName( "lightMapTex" ); 1036 lightMap->uniform = true; 1037 lightMap->sampler = true; 1038 lightMap->constNum = Var::getTexUnitNum(); 1039 1040 MultiLine *meta = new MultiLine; 1041 1042 // Find or create the lightMask value which is read by 1043 // RTLighting to mask out the lights. 1044 // 1045 // The first light is always the sunlight so we apply 1046 // the shadow mask to only the first channel. 1047 // 1048 Var *lightMask = (Var*)LangElement::find( "lightMask" ); 1049 if ( !lightMask ) 1050 { 1051 lightMask = new Var( "lightMask", "vec4" ); 1052 meta->addStatement( new GenOp( " @ = vec4(1);\r\n", new DecOp( lightMask ) ) ); 1053 } 1054 1055 meta->addStatement( new GenOp( " @[0] = tex2D( @, @.xy ).r;\r\n", lightMask, lightMap, inTex ) ); 1056 output = meta; 1057} 1058 1059ShaderFeature::Resources TerrainLightMapFeatGLSL::getResources( const MaterialFeatureData &fd ) 1060{ 1061 Resources res; 1062 res.numTex = 1; 1063 return res; 1064} 1065 1066 1067void TerrainAdditiveFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 1068 const MaterialFeatureData &fd ) 1069{ 1070 Var *color = NULL; 1071 Var *normal = NULL; 1072 if (fd.features[MFT_DeferredTerrainDetailMap]) 1073 { 1074 color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget1) ); 1075 normal = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) ); 1076 } 1077 else 1078 color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) ); 1079 1080 Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); 1081 if ( !color || !blendTotal ) 1082 return; 1083 1084 MultiLine *meta = new MultiLine; 1085 1086 meta->addStatement( new GenOp( " clip( @ - 0.0001 );\r\n", blendTotal ) ); 1087 meta->addStatement( new GenOp( " @.a = @;\r\n", color, blendTotal ) ); 1088 if (normal) 1089 meta->addStatement(new GenOp(" @.a = @;\r\n", normal, blendTotal)); 1090 1091 output = meta; 1092} 1093 1094//standard matInfo map contains data of the form .r = bitflags, .g = (will contain AO), 1095//.b = specular strength, a= spec power. 1096//here, it's merely a cutout for now, so that lightmapping (target3) doesn't get mangled. 1097//we'll most likely revisit that later. possibly several ways... 1098 1099U32 TerrainBlankInfoMapFeatGLSL::getOutputTargets(const MaterialFeatureData &fd) const 1100{ 1101 return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::RenderTarget1; 1102} 1103 1104void TerrainBlankInfoMapFeatGLSL::processPix(Vector<ShaderComponent*> &componentList, 1105 const MaterialFeatureData &fd) 1106{ 1107 // search for material var 1108 Var *material; 1109 OutputTarget targ = RenderTarget1; 1110 if (fd.features[MFT_isDeferred]) 1111 { 1112 targ = RenderTarget2; 1113 } 1114 material = (Var*)LangElement::find(getOutputTargetVarName(targ)); 1115 1116 MultiLine * meta = new MultiLine; 1117 if (!material) 1118 { 1119 // create color var 1120 material = new Var; 1121 material->setType("vec4"); 1122 material->setName(getOutputTargetVarName(targ)); 1123 material->setStructName("OUT"); 1124 } 1125 1126 meta->addStatement(new GenOp(" @ = float4(0.0,0.0,0.0,0.0001);\r\n", material)); 1127 1128 output = meta; 1129} 1130
