pushed a forgotten feature on OpenGL terrrain.
[Torque-3d.git] / Engine / source / terrain / glsl / terrFeatureGLSL.cpp
blob7761a8545d3de21d2b3f7d6ef17d81241be8ef48
1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 // IN THE SOFTWARE.
21 //-----------------------------------------------------------------------------
23 #include "platform/platform.h"
24 #include "terrain/glsl/terrFeatureGLSL.h"
26 #include "terrain/terrFeatureTypes.h"
27 #include "materials/materialFeatureTypes.h"
28 #include "materials/materialFeatureData.h"
29 #include "materials/processedMaterial.h"
30 #include "gfx/gfxDevice.h"
31 #include "shaderGen/langElement.h"
32 #include "shaderGen/shaderOp.h"
33 #include "shaderGen/featureMgr.h"
34 #include "shaderGen/shaderGen.h"
35 #include "core/module.h"
37 namespace
39 void register_glsl_shader_features_for_terrain(GFXAdapterType type)
41 if(type != OpenGL)
42 return;
44 FEATUREMGR->registerFeature( MFT_TerrainBaseMap, new TerrainBaseMapFeatGLSL );
45 FEATUREMGR->registerFeature( MFT_TerrainParallaxMap, new NamedFeatureGLSL( "Terrain Parallax Texture" ) );
46 FEATUREMGR->registerFeature( MFT_TerrainDetailMap, new TerrainDetailMapFeatGLSL );
47 FEATUREMGR->registerFeature( MFT_TerrainNormalMap, new TerrainNormalMapFeatGLSL );
48 FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new TerrainMacroMapFeatGLSL );
49 FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatGLSL );
50 FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureGLSL( "Terrain Side Projection" ) );
51 FEATUREMGR->registerFeature( MFT_TerrainAdditive, new TerrainAdditiveFeatGLSL );
52 FEATUREMGR->registerFeature( MFT_DeferredTerrainBaseMap, new TerrainBaseMapFeatGLSL );
53 FEATUREMGR->registerFeature( MFT_DeferredTerrainMacroMap, new TerrainMacroMapFeatGLSL );
54 FEATUREMGR->registerFeature( MFT_DeferredTerrainDetailMap, new TerrainDetailMapFeatGLSL );
55 FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatGLSL );
60 MODULE_BEGIN( TerrainFeatGLSL )
62 MODULE_INIT_AFTER( ShaderGen )
64 MODULE_INIT
66 SHADERGEN->getFeatureInitSignal().notify(&register_glsl_shader_features_for_terrain);
69 MODULE_END;
72 TerrainFeatGLSL::TerrainFeatGLSL()
73 : mTorqueDep( "shaders/common/gl/torque.glsl" )
75 addDependency( &mTorqueDep );
78 Var* TerrainFeatGLSL::_getUniformVar( const char *name, const char *type, ConstantSortPosition csp )
80 Var *theVar = (Var*)LangElement::find( name );
81 if ( !theVar )
83 theVar = new Var;
84 theVar->setType( type );
85 theVar->setName( name );
86 theVar->uniform = true;
87 theVar->constSortPos = csp;
90 return theVar;
93 Var* TerrainFeatGLSL::_getInDetailCoord( Vector<ShaderComponent*> &componentList )
95 String name( String::ToString( "detCoord%d", getProcessIndex() ) );
96 Var *inDet = (Var*)LangElement::find( name );
98 if ( !inDet )
100 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
102 inDet = connectComp->getElement( RT_TEXCOORD );
103 inDet->setName( name );
104 inDet->setStructName( "IN" );
105 inDet->setType( "vec4" );
106 inDet->mapsToSampler = true;
109 return inDet;
112 Var* TerrainFeatGLSL::_getInMacroCoord( Vector<ShaderComponent*> &componentList )
114 String name( String::ToString( "macroCoord%d", getProcessIndex() ) );
115 Var *inDet = (Var*)LangElement::find( name );
117 if ( !inDet )
119 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
121 inDet = connectComp->getElement( RT_TEXCOORD );
122 inDet->setName( name );
123 inDet->setStructName( "IN" );
124 inDet->setType( "vec4" );
125 inDet->mapsToSampler = true;
128 return inDet;
131 Var* TerrainFeatGLSL::_getNormalMapTex()
133 String name( String::ToString( "normalMap%d", getProcessIndex() ) );
134 Var *normalMap = (Var*)LangElement::find( name );
136 if ( !normalMap )
138 normalMap = new Var;
139 normalMap->setType( "sampler2D" );
140 normalMap->setName( name );
141 normalMap->uniform = true;
142 normalMap->sampler = true;
143 normalMap->constNum = Var::getTexUnitNum();
146 return normalMap;
149 Var* TerrainFeatGLSL::_getDetailIdStrengthParallax()
151 String name( String::ToString( "detailIdStrengthParallax%d", getProcessIndex() ) );
153 Var *detailInfo = (Var*)LangElement::find( name );
154 if ( !detailInfo )
156 detailInfo = new Var;
157 detailInfo->setType( "vec3" );
158 detailInfo->setName( name );
159 detailInfo->uniform = true;
160 detailInfo->constSortPos = cspPotentialPrimitive;
163 return detailInfo;
166 Var* TerrainFeatGLSL::_getMacroIdStrengthParallax()
168 String name( String::ToString( "macroIdStrengthParallax%d", getProcessIndex() ) );
170 Var *detailInfo = (Var*)LangElement::find( name );
171 if ( !detailInfo )
173 detailInfo = new Var;
174 detailInfo->setType( "vec3" );
175 detailInfo->setName( name );
176 detailInfo->uniform = true;
177 detailInfo->constSortPos = cspPotentialPrimitive;
180 return detailInfo;
184 void TerrainBaseMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList,
185 const MaterialFeatureData &fd )
187 MultiLine *meta = new MultiLine;
188 output = meta;
190 // Generate the incoming texture var.
191 Var *inTex;
193 Var *inPos = (Var*)LangElement::find( "inPosition" );
194 if ( !inPos )
195 inPos = (Var*)LangElement::find( "position" );
197 inTex = new Var( "texCoord", "vec3" );
199 Var *oneOverTerrainSize = _getUniformVar( "oneOverTerrainSize", "float", cspPass );
201 // NOTE: The y coord here should be negative to have
202 // the texture maps not end up flipped which also caused
203 // normal and parallax mapping to be incorrect.
205 // This mistake early in development means that the layer
206 // id bilinear blend depends on it being that way.
208 // So instead i fixed this by flipping the base and detail
209 // coord y scale to compensate when rendering.
211 meta->addStatement( new GenOp( " @ = @.xyz * float3( @, @, -@ );\r\n",
212 new DecOp( inTex ), inPos, oneOverTerrainSize, oneOverTerrainSize, oneOverTerrainSize ) );
215 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
217 // Pass the texture coord to the pixel shader.
218 Var *outTex = connectComp->getElement( RT_TEXCOORD );
219 outTex->setName( "outTexCoord" );
220 outTex->setStructName( "OUT" );
221 outTex->setType( "vec3" );
222 outTex->mapsToSampler = true;
223 meta->addStatement( new GenOp( " @.xy = @.xy;\r\n", outTex, inTex ) );
225 // If this shader has a side projected layer then we
226 // pass the dot product between the +Y and the normal
227 // thru outTexCoord.z for use in blending the textures.
228 if ( fd.features.hasFeature( MFT_TerrainSideProject ) )
230 Var *inNormal = (Var*)LangElement::find( "normal" );
231 meta->addStatement(
232 new GenOp( " @.z = pow( abs( dot( normalize( float3( @.x, @.y, 0 ) ), float3( 0, 1, 0 ) ) ), 10.0 );\r\n",
233 outTex, inNormal, inNormal ) );
235 else
236 meta->addStatement( new GenOp( " @.z = 0;\r\n", outTex ) );
238 // HACK: This is sort of lazy... we generate the tanget
239 // vector here so that we're sure it exists in the parallax
240 // and normal features which will expect "T" to exist.
242 // If this shader doesn't use it the shader compiler will
243 // optimize away this code.
245 Var *inTangentZ = getVertTexCoord( "tcTangentZ" );
246 Var *inTanget = new Var( "T", "vec3" );
247 Var *squareSize = _getUniformVar( "squareSize", "float", cspPass );
248 meta->addStatement( new GenOp( " @ = normalize( float3( @, 0, @ ) );\r\n",
249 new DecOp( inTanget ), squareSize, inTangentZ ) );
252 void TerrainBaseMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
253 const MaterialFeatureData &fd )
255 // grab connector texcoord register
256 Var *texCoord = getInTexCoord( "texCoord", "vec3", true, componentList );
258 // create texture var
259 Var *diffuseMap = new Var;
260 diffuseMap->setType( "sampler2D" );
261 diffuseMap->setName( "baseTexMap" );
262 diffuseMap->uniform = true;
263 diffuseMap->sampler = true;
264 diffuseMap->constNum = Var::getTexUnitNum(); // used as texture unit num here
266 MultiLine *meta = new MultiLine;
268 Var *baseColor = new Var;
269 baseColor->setType( "vec4" );
270 baseColor->setName( "baseColor" );
271 meta->addStatement( new GenOp( " @ = tex2D( @, @.xy );\r\n", new DecOp( baseColor ), diffuseMap, texCoord ) );
272 meta->addStatement(new GenOp(" @ = toLinear(@);\r\n", baseColor, baseColor));
274 ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
276 if(fd.features.hasFeature(MFT_isDeferred))
278 target= ShaderFeature::RenderTarget1;
280 meta->addStatement( new GenOp( " @;\r\n", assignColor( baseColor, Material::Mul,NULL,target ) ) );
282 output = meta;
285 ShaderFeature::Resources TerrainBaseMapFeatGLSL::getResources( const MaterialFeatureData &fd )
287 Resources res;
288 res.numTexReg = 1;
289 res.numTex = 1;
291 return res;
294 U32 TerrainBaseMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
296 return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
299 TerrainDetailMapFeatGLSL::TerrainDetailMapFeatGLSL()
300 : mTorqueDep( "shaders/common/gl/torque.glsl" ),
301 mTerrainDep( "shaders/common/terrain/terrain.glsl" )
304 addDependency( &mTorqueDep );
305 addDependency( &mTerrainDep );
308 void TerrainDetailMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList,
309 const MaterialFeatureData &fd )
311 const S32 detailIndex = getProcessIndex();
313 // Grab incoming texture coords... the base map feature
314 // made sure this was created.
315 Var *inTex = (Var*)LangElement::find( "texCoord" );
316 AssertFatal( inTex, "The texture coord is missing!" );
318 // Grab the input position.
319 Var *inPos = (Var*)LangElement::find( "inPosition" );
320 if ( !inPos )
321 inPos = (Var*)LangElement::find( "position" );
323 // Get the object space eye position.
324 Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive );
326 MultiLine *meta = new MultiLine;
328 // If we have parallax mapping then make sure we've sent
329 // the negative view vector to the pixel shader.
330 if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) &&
331 !LangElement::find( "outNegViewTS" ) )
333 // Get the object to tangent transform which
334 // will consume 3 output registers.
335 Var *objToTangentSpace = getOutObjToTangentSpace( componentList, meta, fd );
337 // Now use a single output register to send the negative
338 // view vector in tangent space to the pixel shader.
339 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
340 Var *outNegViewTS = connectComp->getElement( RT_TEXCOORD );
341 outNegViewTS->setName( "outNegViewTS" );
342 outNegViewTS->setStructName( "OUT" );
343 outNegViewTS->setType( "vec3" );
344 meta->addStatement( new GenOp( " @ = tMul( @, float3( @ - @.xyz ) );\r\n",
345 outNegViewTS, objToTangentSpace, eyePos, inPos ) );
348 // Get the distance from the eye to this vertex.
349 Var *dist = (Var*)LangElement::find( "dist" );
350 if ( !dist )
352 dist = new Var;
353 dist->setType( "float" );
354 dist->setName( "dist" );
356 meta->addStatement( new GenOp( " @ = distance( @.xyz, @ );\r\n",
357 new DecOp( dist ), inPos, eyePos ) );
360 // grab connector texcoord register
361 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
362 Var *outTex = connectComp->getElement( RT_TEXCOORD );
363 outTex->setName( String::ToString( "detCoord%d", detailIndex ) );
364 outTex->setStructName( "OUT" );
365 outTex->setType( "vec4" );
366 outTex->mapsToSampler = true;
368 // Get the detail scale and fade info.
369 Var *detScaleAndFade = new Var;
370 detScaleAndFade->setType( "vec4" );
371 detScaleAndFade->setName( String::ToString( "detailScaleAndFade%d", detailIndex ) );
372 detScaleAndFade->uniform = true;
373 detScaleAndFade->constSortPos = cspPotentialPrimitive;
375 // Setup the detail coord.
377 // NOTE: You see here we scale the texture coord by 'xyx'
378 // to generate the detail coord. This y is here because
379 // its scale is flipped to correct for the non negative y
380 // in texCoord.
382 // See TerrainBaseMapFeatGLSL::processVert().
384 meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) );
386 // And sneak the detail fade thru the w detailCoord.
387 meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n",
388 outTex, detScaleAndFade, dist, detScaleAndFade ) );
390 output = meta;
393 void TerrainDetailMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
394 const MaterialFeatureData &fd )
396 const S32 detailIndex = getProcessIndex();
397 Var *inTex = getVertTexCoord( "texCoord" );
399 // new terrain
400 bool hasNormal = fd.features.hasFeature(MFT_TerrainNormalMap, detailIndex);
402 MultiLine *meta = new MultiLine;
404 // We need the negative tangent space view vector
405 // as in parallax mapping we step towards the camera.
406 Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
407 if ( !negViewTS &&
408 fd.features.hasFeature( MFT_TerrainParallaxMap ) )
410 Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
411 if ( !inNegViewTS )
413 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
414 inNegViewTS = connectComp->getElement( RT_TEXCOORD );
415 inNegViewTS->setName( "outNegViewTS" );
416 inNegViewTS->setStructName( "IN" );
417 inNegViewTS->setType( "vec3" );
420 negViewTS = new Var( "negViewTS", "vec3" );
421 meta->addStatement( new GenOp( " @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
424 // Get the layer samples.
425 Var *layerSample = (Var*)LangElement::find( "layerSample" );
426 if ( !layerSample )
428 layerSample = new Var;
429 layerSample->setType( "vec4" );
430 layerSample->setName( "layerSample" );
432 // Get the layer texture var
433 Var *layerTex = new Var;
434 layerTex->setType( "sampler2D" );
435 layerTex->setName( "layerTex" );
436 layerTex->uniform = true;
437 layerTex->sampler = true;
438 layerTex->constNum = Var::getTexUnitNum();
440 // Read the layer texture to get the samples.
441 meta->addStatement( new GenOp( " @ = round( tex2D( @, @.xy ) * 255.0f );\r\n",
442 new DecOp( layerSample ), layerTex, inTex ) );
445 Var *layerSize = (Var*)LangElement::find( "layerSize" );
446 if ( !layerSize )
448 layerSize = new Var;
449 layerSize->setType( "float" );
450 layerSize->setName( "layerSize" );
451 layerSize->uniform = true;
452 layerSize->constSortPos = cspPass;
455 // Grab the incoming detail coord.
456 Var *inDet = _getInDetailCoord( componentList );
458 // Get the detail id.
459 Var *detailInfo = _getDetailIdStrengthParallax();
461 // Create the detail blend var.
462 Var *detailBlend = new Var;
463 detailBlend->setType( "float" );
464 detailBlend->setName( String::ToString( "detailBlend%d", detailIndex ) );
466 // Calculate the blend for this detail texture.
467 meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n",
468 new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) );
470 // New terrain
472 Var *lerpBlend = (Var*)LangElement::find("lerpBlend");
473 if (!lerpBlend)
475 lerpBlend = new Var;
476 lerpBlend->setType("float");
477 lerpBlend->setName("lerpBlend");
478 lerpBlend->uniform = true;
479 lerpBlend->constSortPos = cspPrimitive;
483 Var *blendDepth = (Var*)LangElement::find(String::ToString("blendDepth%d", detailIndex));
484 if (!blendDepth)
486 blendDepth = new Var;
487 blendDepth->setType("float");
488 blendDepth->setName(String::ToString("blendDepth%d", detailIndex));
489 blendDepth->uniform = true;
490 blendDepth->constSortPos = cspPrimitive;
493 Var *baseColor = (Var*)LangElement::find("baseColor");
494 ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
496 if(fd.features.hasFeature( MFT_DeferredTerrainDetailMap ))
497 target= ShaderFeature::RenderTarget1;
499 Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) );
501 if (!outColor)
503 // create color var
504 outColor = new Var;
505 outColor->setType("float4");
506 outColor->setName("col");
507 outColor->setStructName("OUT");
508 meta->addStatement(new GenOp(" @;\r\n", outColor));
511 Var *detailColor = (Var*)LangElement::find("detailColor");
512 if (!detailColor)
514 detailColor = new Var;
515 detailColor->setType("float4");
516 detailColor->setName("detailColor");
517 meta->addStatement(new GenOp(" @;\r\n", new DecOp(detailColor)));
520 // Get the detail texture.
521 Var *detailMap = new Var;
522 detailMap->setType("sampler2D");
523 detailMap->setName(String::ToString("detailMap%d", detailIndex));
524 detailMap->uniform = true;
525 detailMap->sampler = true;
526 detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here
528 // Get the normal map texture.
529 Var *normalMap = _getNormalMapTex();
531 // Issue happens somewhere here -----
533 // Sample the normal map.
535 // We take two normal samples and lerp between them for
536 // side projection layers... else a single sample.
537 LangElement *texOp;
539 // Note that we're doing the standard greyscale detail
540 // map technique here which can darken and lighten the
541 // diffuse texture.
543 // We take two color samples and lerp between them for
544 // side projection layers... else a single sample.
546 if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex))
548 meta->addStatement(new GenOp(" @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n",
549 detailColor, detailMap, inDet, detailMap, inDet, inTex));
551 texOp = new GenOp("lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )",
552 normalMap, inDet, normalMap, inDet, inTex);
554 else
556 meta->addStatement(new GenOp(" @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n",
557 detailColor, detailMap, inDet));
559 texOp = new GenOp("tex2D(@, @.xy)", normalMap, inDet);
562 // New terrain
564 // Get a var and accumulate the blend amount.
565 Var *blendTotal = (Var*)LangElement::find( "blendTotal" );
566 if ( !blendTotal )
568 blendTotal = new Var;
569 blendTotal->setName( "blendTotal" );
570 blendTotal->setType( "float" );
571 meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) );
574 // Add to the blend total.
575 meta->addStatement( new GenOp( " @ += @;\r\n", blendTotal, detailBlend ) );
577 // If we had a parallax feature... then factor in the parallax
578 // amount so that it fades out with the layer blending.
579 if ( fd.features.hasFeature( MFT_TerrainParallaxMap, detailIndex ) )
581 // Get the rest of our inputs.
582 Var *normalMap = _getNormalMapTex();
584 // Call the library function to do the rest.
585 if (fd.features.hasFeature(MFT_IsDXTnm, detailIndex))
587 meta->addStatement(new GenOp(" @.xy += parallaxOffsetDxtnm( @, @.xy, @, @.z * @ );\r\n",
588 inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend));
590 else
592 meta->addStatement(new GenOp(" @.xy += parallaxOffset( @, @.xy, @, @.z * @ );\r\n",
593 inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend));
597 // If we're using SM 3.0 then take advantage of
598 // dynamic branching to skip layers per-pixel.
601 if ( GFX->getPixelShaderVersion() >= 3.0f )
602 meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) );
604 meta->addStatement( new GenOp( " {\r\n" ) );
606 // Note that we're doing the standard greyscale detail
607 // map technique here which can darken and lighten the
608 // diffuse texture.
610 // We take two color samples and lerp between them for
611 // side projection layers... else a single sample.
613 if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) )
615 meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n",
616 detailColor, detailMap, inDet, detailMap, inDet, inTex ) );
618 else
620 meta->addStatement( new GenOp( " @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n",
621 detailColor, detailMap, inDet ) );
624 meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n",
625 detailColor, detailInfo, inDet ) );
627 meta->addStatement( new GenOp( " @ += @ * @;\r\n",
628 outColor, detailColor, detailBlend));
630 meta->addStatement( new GenOp( " }\r\n" ) );
632 output = meta;
635 ShaderFeature::Resources TerrainDetailMapFeatGLSL::getResources( const MaterialFeatureData &fd )
637 Resources res;
639 if ( getProcessIndex() == 0 )
641 // If this is the first detail pass then we
642 // samples from the layer tex.
643 res.numTex += 1;
645 // If this material also does parallax then it
646 // will generate the negative view vector and the
647 // worldToTanget transform.
648 if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) )
649 res.numTexReg += 4;
652 // sample from the detail texture for diffuse coloring.
653 res.numTex += 1;
655 // If we have parallax for this layer then we'll also
656 // be sampling the normal map for the parallax heightmap.
657 if ( fd.features.hasFeature( MFT_TerrainParallaxMap, getProcessIndex() ) )
658 res.numTex += 1;
660 // Finally we always send the detail texture
661 // coord to the pixel shader.
662 res.numTexReg += 1;
664 return res;
667 U32 TerrainDetailMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
669 return fd.features[MFT_DeferredTerrainDetailMap] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
673 TerrainMacroMapFeatGLSL::TerrainMacroMapFeatGLSL()
674 : mTorqueDep( "shaders/common/gl/torque.glsl" ),
675 mTerrainDep( "shaders/common/terrain/terrain.glsl" )
678 addDependency( &mTorqueDep );
679 addDependency( &mTerrainDep );
683 void TerrainMacroMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList,
684 const MaterialFeatureData &fd )
686 const S32 detailIndex = getProcessIndex();
688 // Grab incoming texture coords... the base map feature
689 // made sure this was created.
690 Var *inTex = (Var*)LangElement::find( "texCoord" );
691 AssertFatal( inTex, "The texture coord is missing!" );
693 // Grab the input position.
694 Var *inPos = (Var*)LangElement::find( "inPosition" );
695 if ( !inPos )
696 inPos = (Var*)LangElement::find( "position" );
698 // Get the object space eye position.
699 Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive );
701 MultiLine *meta = new MultiLine;
703 // Get the distance from the eye to this vertex.
704 Var *dist = (Var*)LangElement::find( "macroDist" );
705 if ( !dist )
707 dist = new Var;
708 dist->setType( "float" );
709 dist->setName( "macroDist" );
711 meta->addStatement( new GenOp( " @ = distance( @.xyz, @ );\r\n",
712 new DecOp( dist ), inPos, eyePos ) );
715 // grab connector texcoord register
716 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
717 Var *outTex = connectComp->getElement( RT_TEXCOORD );
718 outTex->setName( String::ToString( "macroCoord%d", detailIndex ) );
719 outTex->setStructName( "OUT" );
720 outTex->setType( "vec4" );
721 outTex->mapsToSampler = true;
723 // Get the detail scale and fade info.
724 Var *detScaleAndFade = new Var;
725 detScaleAndFade->setType( "vec4" );
726 detScaleAndFade->setName( String::ToString( "macroScaleAndFade%d", detailIndex ) );
727 detScaleAndFade->uniform = true;
728 detScaleAndFade->constSortPos = cspPotentialPrimitive;
730 // Setup the detail coord.
731 meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) );
733 // And sneak the detail fade thru the w detailCoord.
734 meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n",
735 outTex, detScaleAndFade, dist, detScaleAndFade ) );
737 output = meta;
741 void TerrainMacroMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
742 const MaterialFeatureData &fd )
744 const S32 detailIndex = getProcessIndex();
745 Var *inTex = getVertTexCoord( "texCoord" );
747 MultiLine *meta = new MultiLine;
749 // We need the negative tangent space view vector
750 // as in parallax mapping we step towards the camera.
751 Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
752 if ( !negViewTS &&
753 fd.features.hasFeature( MFT_TerrainParallaxMap ) )
755 Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
756 if ( !inNegViewTS )
758 ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
759 inNegViewTS = connectComp->getElement( RT_TEXCOORD );
760 inNegViewTS->setName( "outNegViewTS" );
761 inNegViewTS->setStructName( "IN" );
762 inNegViewTS->setType( "vec3" );
765 negViewTS = new Var( "negViewTS", "vec3" );
766 meta->addStatement( new GenOp( " @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
769 // Get the layer samples.
770 Var *layerSample = (Var*)LangElement::find( "layerSample" );
771 if ( !layerSample )
773 layerSample = new Var;
774 layerSample->setType( "vec4" );
775 layerSample->setName( "layerSample" );
777 // Get the layer texture var
778 Var *layerTex = new Var;
779 layerTex->setType( "sampler2D" );
780 layerTex->setName( "macrolayerTex" );
781 layerTex->uniform = true;
782 layerTex->sampler = true;
783 layerTex->constNum = Var::getTexUnitNum();
785 // Read the layer texture to get the samples.
786 meta->addStatement( new GenOp( " @ = round( tex2D( @, @.xy ) * 255.0f );\r\n",
787 new DecOp( layerSample ), layerTex, inTex ) );
790 Var *layerSize = (Var*)LangElement::find( "layerSize" );
791 if ( !layerSize )
793 layerSize = new Var;
794 layerSize->setType( "float" );
795 layerSize->setName( "layerSize" );
796 layerSize->uniform = true;
797 layerSize->constSortPos = cspPass;
800 // Grab the incoming detail coord.
801 Var *inDet = _getInMacroCoord( componentList );
803 // Get the detail id.
804 Var *detailInfo = _getMacroIdStrengthParallax();
806 // Create the detail blend var.
807 Var *detailBlend = new Var;
808 detailBlend->setType( "float" );
809 detailBlend->setName( String::ToString( "macroBlend%d", detailIndex ) );
811 // Calculate the blend for this detail texture.
812 meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n",
813 new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) );
815 // Get a var and accumulate the blend amount.
816 Var *blendTotal = (Var*)LangElement::find( "blendTotal" );
817 if ( !blendTotal )
819 blendTotal = new Var;
820 //blendTotal->setName( "blendTotal" );
821 blendTotal->setName( "blendTotal" );
822 blendTotal->setType( "float" );
823 meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) );
826 // Add to the blend total.
827 meta->addStatement( new GenOp( " @ += @;\r\n", blendTotal, detailBlend ) );
829 Var *detailColor = (Var*)LangElement::find( "macroColor" );
830 if ( !detailColor )
832 detailColor = new Var;
833 detailColor->setType( "vec4" );
834 detailColor->setName( "macroColor" );
835 meta->addStatement( new GenOp( " @;\r\n", new DecOp( detailColor ) ) );
838 // Get the detail texture.
839 Var *detailMap = new Var;
840 detailMap->setType( "sampler2D" );
841 detailMap->setName( String::ToString( "macroMap%d", detailIndex ) );
842 detailMap->uniform = true;
843 detailMap->sampler = true;
844 detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here
846 // If we're using SM 3.0 then take advantage of
847 // dynamic branching to skip layers per-pixel.
848 if ( GFX->getPixelShaderVersion() >= 3.0f )
849 meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) );
851 meta->addStatement( new GenOp( " {\r\n" ) );
853 // Note that we're doing the standard greyscale detail
854 // map technique here which can darken and lighten the
855 // diffuse texture.
857 // We take two color samples and lerp between them for
858 // side projection layers... else a single sample.
860 if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) )
862 meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n",
863 detailColor, detailMap, inDet, detailMap, inDet, inTex ) );
865 else
867 meta->addStatement( new GenOp( " @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n",
868 detailColor, detailMap, inDet ) );
871 meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n",
872 detailColor, detailInfo, inDet ) );
873 ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
875 if(fd.features.hasFeature(MFT_DeferredTerrainMacroMap))
876 target= ShaderFeature::RenderTarget1;
878 Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) );
880 meta->addStatement(new GenOp(" @ += @ * @;\r\n",
881 outColor, detailColor, detailBlend));
883 meta->addStatement( new GenOp( " }\r\n" ) );
885 output = meta;
890 ShaderFeature::Resources TerrainMacroMapFeatGLSL::getResources( const MaterialFeatureData &fd )
892 Resources res;
894 if ( getProcessIndex() == 0 )
896 // If this is the first detail pass then we
897 // samples from the layer tex.
898 res.numTex += 1;
901 res.numTex += 1;
903 // Finally we always send the detail texture
904 // coord to the pixel shader.
905 res.numTexReg += 1;
907 return res;
910 U32 TerrainMacroMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
912 return fd.features[MFT_DeferredTerrainMacroMap] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
915 void TerrainNormalMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList,
916 const MaterialFeatureData &fd )
918 // We only need to process normals during the prepass.
919 if ( !fd.features.hasFeature( MFT_PrePassConditioner ) )
920 return;
922 MultiLine *meta = new MultiLine;
924 // Make sure the world to tangent transform
925 // is created and available for the pixel shader.
926 getOutViewToTangent( componentList, meta, fd );
928 output = meta;
931 void TerrainNormalMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
932 const MaterialFeatureData &fd )
935 MultiLine *meta = new MultiLine;
937 Var *viewToTangent = getInViewToTangent( componentList );
939 // This var is read from GBufferConditionerGLSL and
940 // used in the prepass output.
941 Var *gbNormal = (Var*)LangElement::find( "gbNormal" );
942 if ( !gbNormal )
944 gbNormal = new Var;
945 gbNormal->setName( "gbNormal" );
946 gbNormal->setType( "vec3" );
947 meta->addStatement( new GenOp( " @ = tGetMatrix3Row(@, 2);\r\n", new DecOp( gbNormal ), viewToTangent ) );
950 const S32 normalIndex = getProcessIndex();
952 Var *detailBlend = (Var*)LangElement::find( String::ToString( "detailBlend%d", normalIndex ) );
953 AssertFatal( detailBlend, "The detail blend is missing!" );
955 // If we're using SM 3.0 then take advantage of
956 // dynamic branching to skip layers per-pixel.
957 if ( GFX->getPixelShaderVersion() >= 3.0f )
958 meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) );
960 meta->addStatement( new GenOp( " {\r\n" ) );
962 // Get the normal map texture.
963 Var *normalMap = _getNormalMapTex();
965 /// Get the texture coord.
966 Var *inDet = _getInDetailCoord( componentList );
967 Var *inTex = getVertTexCoord( "texCoord" );
969 // Sample the normal map.
971 // We take two normal samples and lerp between them for
972 // side projection layers... else a single sample.
973 LangElement *texOp;
974 if ( fd.features.hasFeature( MFT_TerrainSideProject, normalIndex ) )
976 texOp = new GenOp( "lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )",
977 normalMap, inDet, normalMap, inDet, inTex );
979 else
980 texOp = new GenOp( "tex2D(@, @.xy)", normalMap, inDet );
982 // create bump normal
983 Var *bumpNorm = new Var;
984 bumpNorm->setName( "bumpNormal" );
985 bumpNorm->setType( "vec4" );
987 LangElement *bumpNormDecl = new DecOp( bumpNorm );
988 meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) );
990 // Normalize is done later...
991 // Note: The reverse mul order is intentional. Affine matrix.
992 meta->addStatement( new GenOp( " @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n",
993 gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet ) );
995 // End the conditional block.
996 meta->addStatement( new GenOp( " }\r\n" ) );
998 // If this is the last normal map then we
999 // can test to see the total blend value
1000 // to see if we should clip the result.
1001 //if ( fd.features.getNextFeatureIndex( MFT_TerrainNormalMap, normalIndex ) == -1 )
1002 //meta->addStatement( new GenOp( " clip( @ - 0.0001f );\r\n", blendTotal ) );
1004 output = meta;
1007 ShaderFeature::Resources TerrainNormalMapFeatGLSL::getResources( const MaterialFeatureData &fd )
1009 Resources res;
1011 // We only need to process normals during the prepass.
1012 if ( fd.features.hasFeature( MFT_PrePassConditioner ) )
1014 // If this is the first normal map and there
1015 // are no parallax features then we will
1016 // generate the worldToTanget transform.
1017 if ( !fd.features.hasFeature( MFT_TerrainParallaxMap ) &&
1018 ( getProcessIndex() == 0 || !fd.features.hasFeature( MFT_TerrainNormalMap, getProcessIndex() - 1 ) ) )
1019 res.numTexReg = 3;
1021 res.numTex = 1;
1024 return res;
1027 void TerrainLightMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
1028 const MaterialFeatureData &fd )
1030 // grab connector texcoord register
1031 Var *inTex = (Var*)LangElement::find( "texCoord" );
1032 if ( !inTex )
1033 return;
1035 // Get the lightmap texture.
1036 Var *lightMap = new Var;
1037 lightMap->setType( "sampler2D" );
1038 lightMap->setName( "lightMapTex" );
1039 lightMap->uniform = true;
1040 lightMap->sampler = true;
1041 lightMap->constNum = Var::getTexUnitNum();
1043 MultiLine *meta = new MultiLine;
1045 // Find or create the lightMask value which is read by
1046 // RTLighting to mask out the lights.
1048 // The first light is always the sunlight so we apply
1049 // the shadow mask to only the first channel.
1051 Var *lightMask = (Var*)LangElement::find( "lightMask" );
1052 if ( !lightMask )
1054 lightMask = new Var( "lightMask", "vec4" );
1055 meta->addStatement( new GenOp( " @ = vec4(1);\r\n", new DecOp( lightMask ) ) );
1058 meta->addStatement( new GenOp( " @[0] = tex2D( @, @.xy ).r;\r\n", lightMask, lightMap, inTex ) );
1059 output = meta;
1062 ShaderFeature::Resources TerrainLightMapFeatGLSL::getResources( const MaterialFeatureData &fd )
1064 Resources res;
1065 res.numTex = 1;
1066 return res;
1070 void TerrainAdditiveFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
1071 const MaterialFeatureData &fd )
1073 Var *color = NULL;
1074 if (fd.features[MFT_DeferredTerrainDetailMap])
1075 color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget1) );
1076 else
1077 color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) );
1079 Var *blendTotal = (Var*)LangElement::find( "blendTotal" );
1080 if ( !color || !blendTotal )
1081 return;
1083 MultiLine *meta = new MultiLine;
1085 meta->addStatement( new GenOp( " clip( @ - 0.0001 );\r\n", blendTotal ) );
1086 meta->addStatement( new GenOp( " @.a = @;\r\n", color, blendTotal ) );
1088 output = meta;
1091 //standard matInfo map contains data of the form .r = bitflags, .g = (will contain AO),
1092 //.b = specular strength, a= spec power.
1093 //here, it's merely a cutout for now, so that lightmapping (target3) doesn't get mangled.
1094 //we'll most likely revisit that later. possibly several ways...
1096 U32 TerrainBlankInfoMapFeatGLSL::getOutputTargets(const MaterialFeatureData &fd) const
1098 return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::RenderTarget1;
1101 void TerrainBlankInfoMapFeatGLSL::processPix(Vector<ShaderComponent*> &componentList,
1102 const MaterialFeatureData &fd)
1104 // search for material var
1105 Var *material;
1106 OutputTarget targ = RenderTarget1;
1107 if (fd.features[MFT_isDeferred])
1109 targ = RenderTarget2;
1111 material = (Var*)LangElement::find(getOutputTargetVarName(targ));
1113 MultiLine * meta = new MultiLine;
1114 if (!material)
1116 // create color var
1117 material = new Var;
1118 material->setType("vec4");
1119 material->setName(getOutputTargetVarName(targ));
1120 material->setStructName("OUT");
1123 meta->addStatement(new GenOp(" @ = float4(0.0,0.0,0.0,0.0001);\r\n", material));
1125 output = meta;