From 4f472bf402a43604ecdb3866a441bd15396240e4 Mon Sep 17 00:00:00 2001 From: Lukas Aldershaab Date: Tue, 29 Dec 2020 02:00:14 +0100 Subject: [PATCH] New terrain blending --- .../source/terrain/glsl/terrFeatureGLSL.cpp | 511 +++++++++++++--- Engine/source/terrain/glsl/terrFeatureGLSL.h | 10 + .../source/terrain/hlsl/terrFeatureHLSL.cpp | 543 +++++++++++++++--- Engine/source/terrain/hlsl/terrFeatureHLSL.h | 10 + Engine/source/terrain/terrCellMaterial.cpp | 47 +- Engine/source/terrain/terrCellMaterial.h | 3 + Engine/source/terrain/terrData.cpp | 5 + Engine/source/terrain/terrData.h | 2 + Engine/source/terrain/terrFeatureTypes.cpp | 2 +- Engine/source/terrain/terrFeatureTypes.h | 2 +- Engine/source/terrain/terrMaterial.cpp | 4 + Engine/source/terrain/terrMaterial.h | 7 + 12 files changed, 967 insertions(+), 179 deletions(-) diff --git a/Engine/source/terrain/glsl/terrFeatureGLSL.cpp b/Engine/source/terrain/glsl/terrFeatureGLSL.cpp index 412f1810d..65cccf69a 100644 --- a/Engine/source/terrain/glsl/terrFeatureGLSL.cpp +++ b/Engine/source/terrain/glsl/terrFeatureGLSL.cpp @@ -48,6 +48,7 @@ namespace FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new NamedFeatureGLSL("TerrainMacroMap Deprecated")); // new TerrainMacroMapFeatGLSL); FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatGLSL ); FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureGLSL( "Terrain Side Projection" ) ); + FEATUREMGR->registerFeature(MFT_TerrainHeightBlend, new TerrainHeightMapBlendGLSL); FEATUREMGR->registerFeature( MFT_TerrainORMMap, new TerrainORMMapFeatGLSL ); FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatGLSL ); } @@ -311,6 +312,25 @@ void TerrainBaseMapFeatGLSL::processPix( Vector &componentLis } meta->addStatement( new GenOp( " @;\r\n", assignColor( baseColor, Material::Mul,NULL,target ) ) ); + // Set base ORM info + Var* ormConfig; + OutputTarget targ = RenderTarget1; + if (fd.features[MFT_isDeferred]) + { + targ = RenderTarget2; + } + ormConfig = (Var*)LangElement::find(getOutputTargetVarName(targ)); + if (!ormConfig) + { + // create color var + ormConfig = new Var; + ormConfig->setType("fragout"); + ormConfig->setName(getOutputTargetVarName(targ)); + ormConfig->setStructName("OUT"); + } + + meta->addStatement(new GenOp(" @ = float4(0.0, 1.0, 1.0, 0.0);\r\n", ormConfig)); + output = meta; } @@ -325,7 +345,7 @@ ShaderFeature::Resources TerrainBaseMapFeatGLSL::getResources( const MaterialFea U32 TerrainBaseMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const { - return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget; + return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 | ShaderFeature::RenderTarget2 : ShaderFeature::DefaultTarget | ShaderFeature::RenderTarget1; } TerrainDetailMapFeatGLSL::TerrainDetailMapFeatGLSL() @@ -541,12 +561,12 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component meta->addStatement(new GenOp(" @;\r\n", outColor)); } - Var *detailColor = (Var*)LangElement::find("detailColor"); + Var *detailColor = (Var*)LangElement::find(String::ToString("detailColor%d", detailIndex)); if (!detailColor) { detailColor = new Var; detailColor->setType("vec4"); - detailColor->setName("detailColor"); + detailColor->setName(String::ToString("detailColor%d", detailIndex)); meta->addStatement(new GenOp(" @;\r\n", new DecOp(detailColor))); } @@ -556,8 +576,6 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component // Get the normal map texture. Var *normalMap = _getNormalMapSampler(); - // Issue happens somewhere here ----- - // Sample the normal map. // // We take two normal samples and lerp between them for @@ -581,7 +599,8 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex))); } - // New terrain + meta->addStatement(new GenOp(" @ *= @.y * @.w;\r\n", + detailColor, new IndexOp(detailInfo, detailIndex), inDet)); // If we had a parallax feature... then factor in the parallax // amount so that it fades out with the layer blending. @@ -599,62 +618,48 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component inDet, normalMap, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend)); } } - + // Check to see if we have a gbuffer normal. - Var *gbNormal = (Var*)LangElement::find( "gbNormal" ); - - // If we have a gbuffer normal and we don't have a - // normal map feature then we need to lerp in a - // default normal else the normals below this layer - // will show thru. - if (gbNormal && - !fd.features.hasFeature(MFT_TerrainNormalMap, detailIndex)) + Var* viewToTangent = (Var*)LangElement::find("viewToTangent"); + if (!viewToTangent && fd.features.hasFeature(MFT_TerrainHeightBlend)) { - Var *viewToTangent = getInViewToTangent(componentList); - - meta->addStatement(new GenOp(" @ = lerp( @, tGetMatrix3Row(@, 2), min( @, @.w ) );\r\n", - gbNormal, gbNormal, viewToTangent, detailBlend, inDet)); + // This needs to be here, to ensure consistent ordering of texcoords, be careful with moving it + getInViewToTangent(componentList); } - // If we're using SM 3.0 then take advantage of - // dynamic branching to skip layers per-pixel. - - - if ( GFX->getPixelShaderVersion() >= 3.0f ) - meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); - - meta->addStatement( new GenOp( " {\r\n" ) ); - - // Note that we're doing the standard greyscale detail - // map technique here which can darken and lighten the - // diffuse texture. - // - // We take two color samples and lerp between them for - // side projection layers... else a single sample. - // - if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) ) + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) { - meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", - detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex), detailMap, inDet, new IndexOp(detailInfo, detailIndex), inTex ) ); + // Check to see if we have a gbuffer normal. + Var* gbNormal = (Var*)LangElement::find("gbNormal"); + + // If we have a gbuffer normal and we don't have a + // normal map feature then we need to lerp in a + // default normal else the normals below this layer + // will show thru. + if (gbNormal && + !fd.features.hasFeature(MFT_TerrainNormalMap, detailIndex)) + { + Var* viewToTangent = getInViewToTangent(componentList); + + meta->addStatement(new GenOp(" @ = lerp( @, tGetMatrix3Row(@, 2), min( @, @.w ) );\r\n", + gbNormal, gbNormal, viewToTangent, detailBlend, inDet)); + } + + // If we're using SM 3.0 then take advantage of + // dynamic branching to skip layers per-pixel. + if (GFX->getPixelShaderVersion() >= 3.0f) + meta->addStatement(new GenOp(" if ( @ > 0.0f )\r\n", detailBlend)); + + meta->addStatement(new GenOp(" {\r\n")); + meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", outColor, outColor)); + + meta->addStatement(new GenOp(" @ += @ * @;\r\n", + outColor, detailColor, detailBlend)); + + meta->addStatement(new GenOp(" @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", outColor, outColor)); + + meta->addStatement(new GenOp(" }\r\n")); } - else - { - meta->addStatement( new GenOp( " @ = ( tex2D( @, vec3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", - detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex)) ); - } - - meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", - detailColor, new IndexOp(detailInfo, detailIndex), inDet ) ); - - - meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", outColor, outColor)); - - meta->addStatement(new GenOp(" @ += @ * @;\r\n", - outColor, detailColor, detailBlend)); - - meta->addStatement(new GenOp(" @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", outColor, outColor)); - - meta->addStatement( new GenOp( " }\r\n" ) ); output = meta; } @@ -941,31 +946,11 @@ void TerrainNormalMapFeatGLSL::processPix( Vector &component MultiLine *meta = new MultiLine; - Var *viewToTangent = getInViewToTangent( componentList ); - - // This var is read from GBufferConditionerGLSL and - // used in the deferred output. - Var *gbNormal = (Var*)LangElement::find( "gbNormal" ); - if ( !gbNormal ) - { - gbNormal = new Var; - gbNormal->setName( "gbNormal" ); - gbNormal->setType( "vec3" ); - meta->addStatement( new GenOp( " @ = tGetMatrix3Row(@, 2);\r\n", new DecOp( gbNormal ), viewToTangent ) ); - } - const S32 normalIndex = getProcessIndex(); Var *detailBlend = (Var*)LangElement::find( String::ToString( "detailBlend%d", normalIndex ) ); AssertFatal( detailBlend, "The detail blend is missing!" ); - // If we're using SM 3.0 then take advantage of - // dynamic branching to skip layers per-pixel. - if ( GFX->getPixelShaderVersion() >= 3.0f ) - meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); - - meta->addStatement( new GenOp( " {\r\n" ) ); - // Get the normal map texture. Var *normalMap = _getNormalMapSampler(); @@ -989,19 +974,42 @@ void TerrainNormalMapFeatGLSL::processPix( Vector &component // create bump normal Var *bumpNorm = new Var; - bumpNorm->setName( "bumpNormal" ); + bumpNorm->setName( String::ToString("bumpNormal%d", normalIndex) ); bumpNorm->setType( "vec4" ); LangElement *bumpNormDecl = new DecOp( bumpNorm ); meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) ); - // Normalize is done later... - // Note: The reverse mul order is intentional. Affine matrix. - meta->addStatement(new GenOp(" @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n", - gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet)); + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + Var* viewToTangent = getInViewToTangent(componentList); - // End the conditional block. - meta->addStatement( new GenOp( " }\r\n" ) ); + // This var is read from GBufferConditionerGLSL and + // used in the deferred output. + Var* gbNormal = (Var*)LangElement::find("gbNormal"); + if (!gbNormal) + { + gbNormal = new Var; + gbNormal->setName("gbNormal"); + gbNormal->setType("vec3"); + meta->addStatement(new GenOp(" @ = tGetMatrix3Row(@, 2);\r\n", new DecOp(gbNormal), viewToTangent)); + } + + // If we're using SM 3.0 then take advantage of + // dynamic branching to skip layers per-pixel. + if (GFX->getPixelShaderVersion() >= 3.0f) + meta->addStatement(new GenOp(" if ( @ > 0.0f )\r\n", detailBlend)); + + meta->addStatement(new GenOp(" {\r\n")); + + // Normalize is done later... + // Note: The reverse mul order is intentional. Affine matrix. + meta->addStatement(new GenOp(" @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n", + gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet)); + + // End the conditional block. + meta->addStatement(new GenOp(" }\r\n")); + } output = meta; } @@ -1204,7 +1212,7 @@ void TerrainORMMapFeatGLSL::processPix(Vector &componentList, // search for material var Var * ormConfig; - OutputTarget targ = DefaultTarget; + OutputTarget targ = RenderTarget1; if (fd.features[MFT_isDeferred]) { targ = RenderTarget2; @@ -1239,7 +1247,13 @@ void TerrainORMMapFeatGLSL::processPix(Vector &componentList, meta->addStatement(new GenOp(" @.b = 1.0 - @.b;\r\n", matinfoCol, matinfoCol)); } - meta->addStatement(new GenOp(" @.gba += @ * @;\r\n", ormConfig, matinfoCol, detailBlend)); + + meta->addStatement(new GenOp(" @ = lerp(float3(1.0, 1.0, 0.0), @, @.y * @.w);\r\n", matinfoCol, matinfoCol, new IndexOp(detailInfo, compositeIndex), inDet)); + + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + meta->addStatement(new GenOp(" @.gba += @ * @;\r\n", ormConfig, matinfoCol, detailBlend)); + } output = meta; } @@ -1295,5 +1309,332 @@ void TerrainBlankInfoMapFeatGLSL::processPix(Vector &component meta->addStatement(new GenOp(" @.gba += vec3(@, @, 0.0);\r\n", material, detailBlend, detailBlend)); + output = meta; +} + +void TerrainHeightMapBlendGLSL::processPix(Vector& componentList, + const MaterialFeatureData& fd) +{ + + ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; + + if (fd.features.hasFeature(MFT_isDeferred)) + target = ShaderFeature::RenderTarget1; + + Var* outColor = (Var*)LangElement::find(getOutputTargetVarName(target)); + + if (!outColor) + return; + + MultiLine* meta = new MultiLine; + + // Count the number of detail textures + int detailCount = 0; + while (true) + { + if (LangElement::find(String::ToString("detailBlend%d", detailCount)) == NULL) + { + break; + } + + ++detailCount; + } + + if (detailCount == 0) + { + return; + } + + // Compute the "height" of each detail layer and store it detailHX + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + Var* bumpNormal = (Var*)LangElement::find(String::ToString("bumpNormal%d", idx)); + Var* blendDepth = (Var*)LangElement::find(String::ToString("blendDepth%d", idx)); + if (!blendDepth) + { + blendDepth = new Var; + blendDepth->setType("float"); + blendDepth->setName(String::ToString("blendDepth%d", idx)); + blendDepth->uniform = true; + blendDepth->constSortPos = cspPrimitive; + } + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + if (!detailH) + { + detailH = new Var; + detailH->setType("float"); + detailH->setName(String::ToString("detailH%d", idx)); + + meta->addStatement(new GenOp(" @ = 0;\r\n", + new DecOp(detailH))); + meta->addStatement(new GenOp(" if (@ > 0.0f) {\r\n", detailBlend)); + if (bumpNormal != NULL) + { + meta->addStatement(new GenOp(" @ = clamp(@.a + @, 0.0, 1.0);\r\n", + detailH, bumpNormal, blendDepth)); + } + else + { + meta->addStatement(new GenOp(" @ = clamp(0.5 + @, 0.0, 1.0);\r\n", + detailH, blendDepth)); + } + meta->addStatement(new GenOp(" }\r\n")); + } + } + + meta->addStatement(new GenOp("\r\n")); + + // Compute blending factors + Var* depth = (Var*)LangElement::find("baseBlendDepth"); + if (depth == NULL) + { + depth = new Var; + depth->setType("float"); + depth->setName("baseBlendDepth"); + depth->uniform = true; + depth->constSortPos = cspPrimitive; + } + + Var* ma = (Var*)LangElement::find("ma"); + if (ma == NULL) + { + ma = new Var; + ma->setType("float"); + ma->setName("ma"); + meta->addStatement(new GenOp(" @ = 0;\r\n", + new DecOp(ma))); + } + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@, @ + @);\r\n", + ma, ma, detailH, detailBlend)); + } + + meta->addStatement(new GenOp(" @ -= @;\r\n", + ma, depth)); + + meta->addStatement(new GenOp("\r\n")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + if (!detailB) + { + detailB = new Var; + detailB->setType("float"); + detailB->setName(String::ToString("detailB%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@ + @ - @, 0);\r\n", + new DecOp(detailB), detailH, detailBlend, ma)); + } + } + + meta->addStatement(new GenOp("\r\n")); + + // Compute albedo + meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", + outColor, outColor)); + + meta->addStatement(new GenOp(" @.rgb += (", + outColor)); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailColor = (Var*)LangElement::find(String::ToString("detailColor%d", idx)); + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@.rgb * @", detailColor, detailB)); + } + + meta->addStatement(new GenOp(") / (")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@", detailB)); + } + + + meta->addStatement(new GenOp(");\r\n")); + + meta->addStatement(new GenOp(" @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", + outColor, outColor)); + + meta->addStatement(new GenOp("\r\n")); + + // Compute ORM + Var* ormOutput; + OutputTarget targ = DefaultTarget; + if (fd.features[MFT_isDeferred]) + { + targ = RenderTarget2; + } + ormOutput = (Var*)LangElement::find(getOutputTargetVarName(targ)); + + meta->addStatement(new GenOp(" @.gba = (", + ormOutput)); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* matinfoCol = (Var*)LangElement::find(String::ToString("matinfoCol%d", idx)); + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + if (matinfoCol) + { + meta->addStatement(new GenOp("@ * @", matinfoCol, detailB)); + } + else + { + meta->addStatement(new GenOp("vec3(1.0, 1.0, 0.0) * @", detailB)); + } + } + + meta->addStatement(new GenOp(") / (")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@", detailB)); + } + + + meta->addStatement(new GenOp(");\r\n")); + + + meta->addStatement(new GenOp("\r\n")); + + // Compute normal-specific blending factors + // LukasPJ: I'm not sure why this is necessary, it might not be. + Var* normalMa = (Var*)LangElement::find("normalMa"); + if (normalMa == NULL) + { + normalMa = new Var; + normalMa->setType("float"); + normalMa->setName("normalMa"); + meta->addStatement(new GenOp(" @ = 0;\r\n", + new DecOp(normalMa))); + } + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx)); + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@, @ + min(@, @.w));\r\n", + normalMa, normalMa, detailH, detailBlend, detCoord)); + } + + meta->addStatement(new GenOp(" @ -= @;\r\n", + normalMa, depth)); + + meta->addStatement(new GenOp("\r\n")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx)); + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx)); + if (!normalDetailB) + { + normalDetailB = new Var; + normalDetailB->setType("float"); + normalDetailB->setName(String::ToString("normalDetailB%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@ + min(@, @.w) - @, 0);\r\n", + new DecOp(normalDetailB), detailH, detailBlend, detCoord, normalMa)); + } + } + + // Compute normals + Var* gbNormal = (Var*)LangElement::find("gbNormal"); + if (!gbNormal) + { + gbNormal = new Var; + gbNormal->setName("gbNormal"); + gbNormal->setType("vec3"); + meta->addStatement(new GenOp(" @;\r\n", new DecOp(gbNormal))); + } + + if (gbNormal != NULL) + { + meta->addStatement(new GenOp(" @ = (", + gbNormal)); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx)); + Var* bumpNormal = (Var*)LangElement::find(String::ToString("bumpNormal%d", idx)); + Var* viewToTangent = getInViewToTangent(componentList); + + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + if (bumpNormal != NULL) + { + meta->addStatement(new GenOp("tMul(@.xyz, @) * @", bumpNormal, viewToTangent, normalDetailB)); + } + else + { + meta->addStatement(new GenOp("tGetMatrix3Row(@, 2) * @", viewToTangent, normalDetailB)); + } + } + + meta->addStatement(new GenOp(") / (")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx)); + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@", normalDetailB)); + } + + + meta->addStatement(new GenOp(");\r\n")); + } + + output = meta; } diff --git a/Engine/source/terrain/glsl/terrFeatureGLSL.h b/Engine/source/terrain/glsl/terrFeatureGLSL.h index 3e954caf0..dcfde2204 100644 --- a/Engine/source/terrain/glsl/terrFeatureGLSL.h +++ b/Engine/source/terrain/glsl/terrFeatureGLSL.h @@ -178,4 +178,14 @@ public: virtual String getName() { return "Blank Matinfo map"; } }; +class TerrainHeightMapBlendGLSL : public TerrainFeatGLSL +{ +public: + + virtual void processPix(Vector& componentList, + const MaterialFeatureData& fd); + + virtual String getName() { return "Terrain Heightmap Blend"; } +}; + #endif // _TERRFEATUREGLSL_H_ diff --git a/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp b/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp index 8c0dd82ba..9b34b5022 100644 --- a/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp +++ b/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp @@ -48,6 +48,7 @@ namespace FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new NamedFeatureHLSL("TerrainMacroMap Deprecated")); // new TerrainMacroMapFeatHLSL); FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatHLSL ); FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureHLSL( "Terrain Side Projection" ) ); + FEATUREMGR->registerFeature( MFT_TerrainHeightBlend, new TerrainHeightMapBlendHLSL ); FEATUREMGR->registerFeature( MFT_TerrainORMMap, new TerrainORMMapFeatHLSL ); FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatHLSL ); } @@ -371,6 +372,26 @@ void TerrainBaseMapFeatHLSL::processPix( Vector &componentLis } meta->addStatement( new GenOp( " @;\r\n", assignColor( baseColor, Material::Mul,NULL,target ) ) ); + + if (fd.features[MFT_isDeferred]) + { + // Set base ORM info + Var* ormConfig; + OutputTarget targ = RenderTarget1; + targ = RenderTarget2; + ormConfig = (Var*)LangElement::find(getOutputTargetVarName(targ)); + if (!ormConfig) + { + // create color var + ormConfig = new Var; + ormConfig->setType("fragout"); + ormConfig->setName(getOutputTargetVarName(targ)); + ormConfig->setStructName("OUT"); + } + + meta->addStatement(new GenOp(" @ = float4(0.0, 1.0, 1.0, 0.0);\r\n", ormConfig)); + } + output = meta; } @@ -385,7 +406,7 @@ ShaderFeature::Resources TerrainBaseMapFeatHLSL::getResources( const MaterialFea U32 TerrainBaseMapFeatHLSL::getOutputTargets( const MaterialFeatureData &fd ) const { - return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget; + return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 | ShaderFeature::RenderTarget2 : ShaderFeature::DefaultTarget; } TerrainDetailMapFeatHLSL::TerrainDetailMapFeatHLSL() @@ -587,40 +608,22 @@ void TerrainDetailMapFeatHLSL::processPix( Vector &component } } - - // Check to see if we have a gbuffer normal. - Var *gbNormal = (Var*)LangElement::find( "gbNormal" ); - // If we have a gbuffer normal and we don't have a - // normal map feature then we need to lerp in a - // default normal else the normals below this layer - // will show thru. - if (gbNormal && - !fd.features.hasFeature(MFT_TerrainNormalMap, detailIndex)) - { - Var *viewToTangent = getInViewToTangent(componentList); - meta->addStatement(new GenOp(" @ = lerp( @, @[2], min( @, @.w ) );\r\n", - gbNormal, gbNormal, viewToTangent, detailBlend, inDet)); - } - Var *detailColor = (Var*)LangElement::find( "detailColor" ); + Var *detailColor = (Var*)LangElement::find(String::ToString("detailColor%d", detailIndex)); if ( !detailColor ) { detailColor = new Var; detailColor->setType( "float4" ); - detailColor->setName( "detailColor" ); + detailColor->setName( String::ToString("detailColor%d", detailIndex) ); meta->addStatement( new GenOp( " @;\r\n", new DecOp( detailColor ) ) ); } - // If we're using SM 3.0 then take advantage of - // dynamic branching to skip layers per-pixel. - - - if ( GFX->getPixelShaderVersion() >= 3.0f ) - meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); - - meta->addStatement( new GenOp( " {\r\n" ) ); - + // Sample the normal map. + // + // We take two normal samples and lerp between them for + // side projection layers... else a single sample. + // // Note that we're doing the standard greyscale detail // map technique here which can darken and lighten the // diffuse texture. @@ -635,34 +638,68 @@ void TerrainDetailMapFeatHLSL::processPix( Vector &component if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex)) { - - meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", + meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), inTex)); } else { - meta->addStatement(new GenOp(" @ = ( @.Sample( @, float3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", + meta->addStatement(new GenOp(" @ = ( @.Sample( @, float3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex))); } - meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", - detailColor, new IndexOp(detailInfo, detailIndex), inDet ) ); + meta->addStatement(new GenOp(" @ *= @.y * @.w;\r\n", + detailColor, new IndexOp(detailInfo, detailIndex), inDet)); - ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; - if (fd.features.hasFeature(MFT_isDeferred)) - target= ShaderFeature::RenderTarget1; + // Check to see if we have a gbuffer normal. + Var* viewToTangent = (Var*)LangElement::find("viewToTangent"); + if (!viewToTangent && fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + // This needs to be here, to ensure consistent ordering of texcoords, be careful with moving it + getInViewToTangent(componentList); + } - Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) ); + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + // Check to see if we have a gbuffer normal. + Var* gbNormal = (Var*)LangElement::find("gbNormal"); - meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", outColor, outColor)); + // If we have a gbuffer normal and we don't have a + // normal map feature then we need to lerp in a + // default normal else the normals below this layer + // will show thru. + if (gbNormal && + !fd.features.hasFeature(MFT_TerrainNormalMap, detailIndex)) + { + Var* viewToTangent = getInViewToTangent(componentList); - meta->addStatement( new GenOp( " @ += @ * @;\r\n", - outColor, detailColor, detailBlend)); + meta->addStatement(new GenOp(" @ = lerp( @, @[2], min( @, @.w ) );\r\n", + gbNormal, gbNormal, viewToTangent, detailBlend, inDet)); + } - meta->addStatement(new GenOp(" @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", outColor, outColor)); + // If we're using SM 3.0 then take advantage of + // dynamic branching to skip layers per-pixel. + if (GFX->getPixelShaderVersion() >= 3.0f) + meta->addStatement(new GenOp(" if ( @ > 0.0f )\r\n", detailBlend)); - meta->addStatement( new GenOp( " }\r\n" ) ); + meta->addStatement(new GenOp(" {\r\n")); + + ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; + + if (fd.features.hasFeature(MFT_isDeferred)) + target = ShaderFeature::RenderTarget1; + + Var* outColor = (Var*)LangElement::find(getOutputTargetVarName(target)); + + meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", outColor, outColor)); + + meta->addStatement(new GenOp(" @ += @ * @;\r\n", + outColor, detailColor, detailBlend)); + + meta->addStatement(new GenOp(" @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", outColor, outColor)); + + meta->addStatement(new GenOp(" }\r\n")); + } output = meta; } @@ -901,16 +938,16 @@ void TerrainMacroMapFeatHLSL::processPix( Vector &componentL // if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex)) { - meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", + meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), inTex)); } else { - meta->addStatement(new GenOp(" @ = ( @.Sample( @, float3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", + meta->addStatement(new GenOp(" @ = ( @.Sample( @, float3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex))); } - meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", + meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", detailColor, new IndexOp(detailInfo, detailIndex), inDet ) ); ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; @@ -982,42 +1019,21 @@ void TerrainNormalMapFeatHLSL::processPix( Vector &component MultiLine *meta = new MultiLine; - Var *viewToTangent = getInViewToTangent( componentList ); - - // This var is read from GBufferConditionerHLSL and - // used in the deferred output. - Var *gbNormal = (Var*)LangElement::find( "gbNormal" ); - if ( !gbNormal ) - { - gbNormal = new Var; - gbNormal->setName( "gbNormal" ); - gbNormal->setType( "float3" ); - meta->addStatement( new GenOp( " @ = @[2];\r\n", new DecOp( gbNormal ), viewToTangent ) ); - } - const S32 normalIndex = getProcessIndex(); Var *detailBlend = (Var*)LangElement::find( String::ToString( "detailBlend%d", normalIndex ) ); AssertFatal( detailBlend, "The detail blend is missing!" ); - // If we're using SM 3.0 then take advantage of - // dynamic branching to skip layers per-pixel. - if ( GFX->getPixelShaderVersion() >= 3.0f ) - meta->addStatement( new GenOp( " if ( @ > 0.0f )\r\n", detailBlend ) ); - - meta->addStatement( new GenOp( " {\r\n" ) ); - /// Get the texture coord. - Var *inDet = _getInDetailCoord( componentList ); - Var *inTex = getVertTexCoord( "texCoord" ); - + Var* inDet = _getInDetailCoord(componentList); + Var* inTex = getVertTexCoord("texCoord"); Var* detailInfo = _getDetailIdStrengthParallax(); // Sample the normal map. // // We take two normal samples and lerp between them for // side projection layers... else a single sample. - LangElement *texOp; + LangElement* texOp; Var* normalMapSampler = _getNormalMapSampler(); Var* normalMapArray = _getNormalMapArray(); @@ -1031,20 +1047,43 @@ void TerrainNormalMapFeatHLSL::processPix( Vector &component texOp = new GenOp("@.Sample(@, float3(@.xy, @.x))", normalMapArray, normalMapSampler, inDet, new IndexOp(detailInfo, normalIndex)); // create bump normal - Var *bumpNorm = new Var; - bumpNorm->setName( "bumpNormal" ); - bumpNorm->setType( "float4" ); + Var* bumpNorm = new Var; + bumpNorm->setName(String::ToString("bumpNormal%d", normalIndex)); + bumpNorm->setType("float4"); - LangElement *bumpNormDecl = new DecOp( bumpNorm ); - meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) ); + LangElement* bumpNormDecl = new DecOp(bumpNorm); + meta->addStatement(expandNormalMap(texOp, bumpNormDecl, bumpNorm, fd)); + + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + Var* viewToTangent = getInViewToTangent(componentList); + + // This var is read from GBufferConditionerHLSL and + // used in the deferred output. + Var* gbNormal = (Var*)LangElement::find("gbNormal"); + if (!gbNormal) + { + gbNormal = new Var; + gbNormal->setName("gbNormal"); + gbNormal->setType("float3"); + meta->addStatement(new GenOp(" @ = @[2];\r\n", new DecOp(gbNormal), viewToTangent)); + } + + // If we're using SM 3.0 then take advantage of + // dynamic branching to skip layers per-pixel. + if (GFX->getPixelShaderVersion() >= 3.0f) + meta->addStatement(new GenOp(" if ( @ > 0.0f )\r\n", detailBlend)); + + meta->addStatement(new GenOp(" {\r\n")); // Normalize is done later... // Note: The reverse mul order is intentional. Affine matrix. - meta->addStatement( new GenOp( " @ = lerp( @, mul( @.xyz, @ ), min( @, @.w ) );\r\n", - gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet ) ); + meta->addStatement(new GenOp(" @ = lerp( @, mul( @.xyz, @ ), min( @, @.w ) );\r\n", + gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet)); - // End the conditional block. - meta->addStatement( new GenOp( " }\r\n" ) ); + // End the conditional block. + meta->addStatement(new GenOp(" }\r\n")); + } output = meta; } @@ -1247,7 +1286,7 @@ void TerrainORMMapFeatHLSL::processPix(Vector &componentList, // search for material var Var * ormConfig; - OutputTarget targ = DefaultTarget; + OutputTarget targ = RenderTarget1; if (fd.features[MFT_isDeferred]) { targ = RenderTarget2; @@ -1282,7 +1321,12 @@ void TerrainORMMapFeatHLSL::processPix(Vector &componentList, meta->addStatement(new GenOp(" @.b = 1.0 - @.b;\r\n", matinfoCol, matinfoCol)); } - meta->addStatement(new GenOp(" @.gba += @ * @;\r\n", ormConfig, matinfoCol, detailBlend)); + meta->addStatement(new GenOp(" @ = lerp(float3(1.0, 1.0, 0.0), @, @.y * @.w);\r\n", matinfoCol, matinfoCol, new IndexOp(detailInfo, compositeIndex), inDet)); + + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + meta->addStatement(new GenOp(" @.gba += @ * @;\r\n", ormConfig, matinfoCol, detailBlend)); + } output = meta; } @@ -1297,7 +1341,7 @@ ShaderFeature::Resources TerrainORMMapFeatHLSL::getResources(const MaterialFeatu // reminder, the matinfo buffer is flags, smooth, ao, metal U32 TerrainBlankInfoMapFeatHLSL::getOutputTargets(const MaterialFeatureData &fd) const { - return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::DefaultTarget; + return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::RenderTarget1; } void TerrainBlankInfoMapFeatHLSL::processPix(Vector &componentList, @@ -1307,12 +1351,12 @@ void TerrainBlankInfoMapFeatHLSL::processPix(Vector &component // search for material var Var *material; - OutputTarget targ = DefaultTarget; + OutputTarget ormConfig = RenderTarget1; if (fd.features[MFT_isDeferred]) { - targ = RenderTarget2; + ormConfig = RenderTarget2; } - material = (Var*)LangElement::find(getOutputTargetVarName(targ)); + material = (Var*)LangElement::find(getOutputTargetVarName(ormConfig)); MultiLine * meta = new MultiLine; if (!material) @@ -1320,7 +1364,7 @@ void TerrainBlankInfoMapFeatHLSL::processPix(Vector &component // create color var material = new Var; material->setType("fragout"); - material->setName(getOutputTargetVarName(targ)); + material->setName(getOutputTargetVarName(ormConfig)); material->setStructName("OUT"); } @@ -1334,7 +1378,338 @@ void TerrainBlankInfoMapFeatHLSL::processPix(Vector &component String matinfoName(String::ToString("matinfoCol%d", compositeIndex)); - meta->addStatement(new GenOp(" @.gba += float3(@, @, 0.0);\r\n", material, detailBlend, detailBlend)); + if (!fd.features.hasFeature(MFT_TerrainHeightBlend)) + { + meta->addStatement(new GenOp(" @.gba += float3(@, @, 0.0);\r\n", material, detailBlend, detailBlend)); + } + + output = meta; +} + +void TerrainHeightMapBlendHLSL::processPix(Vector& componentList, + const MaterialFeatureData& fd) +{ + + ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; + + if (fd.features.hasFeature(MFT_isDeferred)) + target = ShaderFeature::RenderTarget1; + + Var* outColor = (Var*)LangElement::find(getOutputTargetVarName(target)); + + if (!outColor) + return; + + MultiLine* meta = new MultiLine; + + // Count number of detail layers + int detailCount = 0; + while (true) + { + if(LangElement::find(String::ToString("detailBlend%d", detailCount)) == NULL) + { + break; + } + + ++detailCount; + } + + if ( detailCount == 0 ) + { + return; + } + + // Compute blend factors + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + Var* bumpNormal = (Var*)LangElement::find(String::ToString("bumpNormal%d", idx)); + Var* blendDepth = (Var*)LangElement::find(String::ToString("blendDepth%d", idx)); + if (!blendDepth) + { + blendDepth = new Var; + blendDepth->setType("float"); + blendDepth->setName(String::ToString("blendDepth%d", idx)); + blendDepth->uniform = true; + blendDepth->constSortPos = cspPrimitive; + } + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + if (!detailH) + { + detailH = new Var; + detailH->setType("float"); + detailH->setName(String::ToString("detailH%d", idx)); + + meta->addStatement(new GenOp(" @ = 0;\r\n", + new DecOp(detailH))); + meta->addStatement(new GenOp(" if (@ > 0.0f) {\r\n", detailBlend)); + if (bumpNormal != NULL) + { + meta->addStatement(new GenOp(" @ = clamp(@.a + @, 0.0, 1.0);\r\n", + detailH, bumpNormal, blendDepth)); + } + else + { + meta->addStatement(new GenOp(" @ = clamp(0.5 + @, 0.0, 1.0);\r\n", + detailH, blendDepth)); + } + meta->addStatement(new GenOp(" }\r\n")); + } + } + + meta->addStatement(new GenOp("\r\n")); + + Var* depth = (Var*)LangElement::find("baseBlendDepth"); + if (depth == NULL) + { + depth = new Var; + depth->setType("float"); + depth->setName("baseBlendDepth"); + depth->uniform = true; + depth->constSortPos = cspPrimitive; + } + + Var* ma = (Var*)LangElement::find("ma"); + if (ma == NULL) + { + ma = new Var; + ma->setType("float"); + ma->setName("ma"); + meta->addStatement(new GenOp(" @ = 0;\r\n", + new DecOp(ma))); + } + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx)); + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@, @ + @);\r\n", + ma, ma, detailH, detailBlend)); + } + + meta->addStatement(new GenOp(" @ -= @;\r\n", + ma, depth)); + + meta->addStatement(new GenOp("\r\n")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + if (!detailB) + { + detailB = new Var; + detailB->setType("float"); + detailB->setName(String::ToString("detailB%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@ + @ - @, 0);\r\n", + new DecOp(detailB), detailH, detailBlend, ma)); + } + } + + meta->addStatement(new GenOp("\r\n")); + + // Compute albedo + meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", + outColor, outColor)); + + meta->addStatement(new GenOp(" @.rgb += (", + outColor)); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailColor = (Var*)LangElement::find(String::ToString("detailColor%d", idx)); + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@.rgb * @", detailColor, detailB)); + } + + meta->addStatement(new GenOp(") / (")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@", detailB)); + } + + + meta->addStatement(new GenOp(");\r\n")); + + meta->addStatement(new GenOp(" @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", + outColor, outColor)); + + meta->addStatement(new GenOp("\r\n")); + + // Compute ORM + Var* ormOutput; + OutputTarget targ = DefaultTarget; + if (fd.features[MFT_isDeferred]) + { + targ = RenderTarget2; + } + ormOutput = (Var*)LangElement::find(getOutputTargetVarName(targ)); + + meta->addStatement(new GenOp(" @.gba = (", + ormOutput)); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* matinfoCol = (Var*)LangElement::find(String::ToString("matinfoCol%d", idx)); + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + if (matinfoCol) + { + meta->addStatement(new GenOp("@ * @", matinfoCol, detailB)); + } + else + { + meta->addStatement(new GenOp("float3(1.0, 1.0, 0.0) * @", detailB)); + } + } + + meta->addStatement(new GenOp(") / (")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx)); + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@", detailB)); + } + + + meta->addStatement(new GenOp(");\r\n")); + + + meta->addStatement(new GenOp("\r\n")); + + // Compute normal-specific blending factors + // LukasPJ: I'm not sure why this is necessary, it might not be. + Var* normalMa = (Var*)LangElement::find("normalMa"); + if (normalMa == NULL) + { + normalMa = new Var; + normalMa->setType("float"); + normalMa->setName("normalMa"); + meta->addStatement(new GenOp(" @ = 0;\r\n", + new DecOp(normalMa))); + } + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx)); + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@, @ + min(@, @.w));\r\n", + normalMa, normalMa, detailH, detailBlend, detCoord)); + } + + meta->addStatement(new GenOp(" @ -= @;\r\n", + normalMa, depth)); + + meta->addStatement(new GenOp("\r\n")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx)); + + Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx)); + Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx)); + Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx)); + if (!normalDetailB) + { + normalDetailB = new Var; + normalDetailB->setType("float"); + normalDetailB->setName(String::ToString("normalDetailB%d", idx)); + + meta->addStatement(new GenOp(" @ = max(@ + min(@, @.w) - @, 0);\r\n", + new DecOp(normalDetailB), detailH, detailBlend, detCoord, normalMa)); + } + } + + // Compute normals + Var* gbNormal = (Var*)LangElement::find("gbNormal"); + if (!gbNormal) + { + gbNormal = new Var; + gbNormal->setName("gbNormal"); + gbNormal->setType("float3"); + meta->addStatement(new GenOp(" @;\r\n", new DecOp(gbNormal))); + } + + if (gbNormal != NULL) + { + meta->addStatement(new GenOp(" @ = (", + gbNormal)); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx)); + Var* bumpNormal = (Var*)LangElement::find(String::ToString("bumpNormal%d", idx)); + Var* viewToTangent = getInViewToTangent(componentList); + + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + if (bumpNormal != NULL) + { + meta->addStatement(new GenOp("mul(@.xyz, @) * @", bumpNormal, viewToTangent, normalDetailB)); + } + else + { + meta->addStatement(new GenOp("@[2] * @", viewToTangent, normalDetailB)); + } + } + + meta->addStatement(new GenOp(") / (")); + + for (S32 idx = 0; idx < detailCount; ++idx) + { + Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx)); + + if (idx > 0) + { + meta->addStatement(new GenOp(" + ")); + } + + meta->addStatement(new GenOp("@", normalDetailB)); + } + + + meta->addStatement(new GenOp(");\r\n")); + } + output = meta; } diff --git a/Engine/source/terrain/hlsl/terrFeatureHLSL.h b/Engine/source/terrain/hlsl/terrFeatureHLSL.h index 57851621a..38bd46330 100644 --- a/Engine/source/terrain/hlsl/terrFeatureHLSL.h +++ b/Engine/source/terrain/hlsl/terrFeatureHLSL.h @@ -184,4 +184,14 @@ public: virtual String getName() { return "Blank Matinfo map"; } }; +class TerrainHeightMapBlendHLSL : public TerrainFeatHLSL +{ +public: + + virtual void processPix(Vector& componentList, + const MaterialFeatureData& fd); + + virtual String getName() { return "Terrain Heightmap Blend"; } +}; + #endif // _TERRFEATUREHLSL_H_ diff --git a/Engine/source/terrain/terrCellMaterial.cpp b/Engine/source/terrain/terrCellMaterial.cpp index 588301442..583aa5abe 100644 --- a/Engine/source/terrain/terrCellMaterial.cpp +++ b/Engine/source/terrain/terrCellMaterial.cpp @@ -401,16 +401,18 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, features.addFeature(MFT_isDeferred, featureIndex); features.addFeature(MFT_TerrainDetailMap, featureIndex); - if (!(mat->getORMConfigMap().isEmpty())) + if (deferredMat) { - if (deferredMat) - features.addFeature(MFT_isDeferred, featureIndex); - features.addFeature(MFT_TerrainORMMap, featureIndex); - } - else - { - features.addFeature(MFT_DeferredTerrainBlankInfoMap, featureIndex); + if (!(mat->getORMConfigMap().isEmpty())) + { + features.addFeature(MFT_TerrainORMMap, featureIndex); + } + else + { + features.addFeature(MFT_DeferredTerrainBlankInfoMap, featureIndex); + } } + if (mat->getInvertRoughness()) features.addFeature(MFT_InvertRoughness, featureIndex); @@ -444,6 +446,12 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, featureIndex++; } + // New blending + if (matCount > 0 && !Con::getBoolVariable("$Terrain::LerpBlend", false)) + { + features.addFeature(MFT_TerrainHeightBlend); + } + MaterialFeatureData featureData; featureData.features = features; featureData.materialFeatures = features; @@ -528,6 +536,7 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, mLightMapTexConst = mShader->getShaderConstHandle("$lightMapTex"); mOneOverTerrainSizeConst = mShader->getShaderConstHandle("$oneOverTerrainSize"); mSquareSizeConst = mShader->getShaderConstHandle("$squareSize"); + mBlendDepthConst = mShader->getShaderConstHandle("$baseBlendDepth"); mLightParamsConst = mShader->getShaderConstHandle("$rtParamslightInfoBuffer"); @@ -634,6 +643,23 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, desc.samplers[sampler].minFilter = GFXTextureFilterLinear; } + for (U32 i = 0; i < matCount && !baseOnly; i++) + { + TerrainMaterial* mat = mMaterialInfos[i]->mat; + + if (mat == NULL) + continue; + + // We only include materials that + // have more than a base texture. + if (mat->getDetailSize() <= 0 || + mat->getDetailDistance() <= 0 || + mat->getDetailMap().isEmpty()) + continue; + + mMaterialInfos[i]->mBlendDepthConst = mShader->getShaderConstHandle(avar("$blendDepth%d", i)); + } + // If we're doing deferred it requires some // special stencil settings for it to work. if ( deferredMat ) @@ -701,10 +727,13 @@ void TerrainCellMaterial::_updateMaterialConsts( ) detailScaleAndFadeArray[j] = detailScaleAndFade; detailInfoArray[j] = detailIdStrengthParallax; + + mConsts->setSafe(matInfo->mBlendDepthConst, matInfo->mat->getBlendDepth()); } mConsts->setSafe(mDetailInfoVArrayConst, detailScaleAndFadeArray); mConsts->setSafe(mDetailInfoPArrayConst, detailInfoArray); + } bool TerrainCellMaterial::setupPass( const SceneRenderState *state, @@ -782,6 +811,8 @@ bool TerrainCellMaterial::setupPass( const SceneRenderState *state, mConsts->set( mFogDataConst, fogData ); } + mConsts->setSafe( mBlendDepthConst, Con::getFloatVariable("$Terrain::BlendDepth", 0.2f) ); + mConsts->setSafe( mFogColorConst, sceneData.fogColor ); if ( mLightInfoBufferConst->isValid() && diff --git a/Engine/source/terrain/terrCellMaterial.h b/Engine/source/terrain/terrCellMaterial.h index c73e3ba56..ff8568e52 100644 --- a/Engine/source/terrain/terrCellMaterial.h +++ b/Engine/source/terrain/terrCellMaterial.h @@ -69,6 +69,7 @@ protected: TerrainMaterial *mat; U32 layerId; + GFXShaderConstHandle* mBlendDepthConst; }; /// @@ -116,6 +117,8 @@ protected: GFXShaderConstHandle *mNormalTexArrayConst; GFXShaderConstHandle *mOrmTexArrayConst; + GFXShaderConstHandle* mBlendDepthConst; + TerrainBlock *mTerrain; U32 mCurrPass; diff --git a/Engine/source/terrain/terrData.cpp b/Engine/source/terrain/terrData.cpp index be29ec7c9..3d035af62 100644 --- a/Engine/source/terrain/terrData.cpp +++ b/Engine/source/terrain/terrData.cpp @@ -1471,6 +1471,11 @@ DefineEngineMethod(TerrainBlock, saveAsset, bool, (), , return static_cast(object)->saveAsset(); } +DefineEngineMethod( TerrainBlock, setMaterialsDirty, void, (),, "") +{ + static_cast(object)->setMaterialsDirty(); +} + //ConsoleMethod(TerrainBlock, save, bool, 3, 3, "(string fileName) - saves the terrain block's terrain file to the specified file name.") //{ // char filename[256]; diff --git a/Engine/source/terrain/terrData.h b/Engine/source/terrain/terrData.h index 68521a166..4b33d6c61 100644 --- a/Engine/source/terrain/terrData.h +++ b/Engine/source/terrain/terrData.h @@ -313,6 +313,8 @@ public: /// Deletes all the materials on the terrain. void deleteAllMaterials(); + void setMaterialsDirty() { mDetailsDirty = true; }; + //void setMaterialName( U32 index, const String &name ); /// Accessors and mutators for TerrainMaterialUndoAction. diff --git a/Engine/source/terrain/terrFeatureTypes.cpp b/Engine/source/terrain/terrFeatureTypes.cpp index 816414cce..a1c28a08d 100644 --- a/Engine/source/terrain/terrFeatureTypes.cpp +++ b/Engine/source/terrain/terrFeatureTypes.cpp @@ -33,7 +33,7 @@ ImplementFeatureType( MFT_TerrainNormalMap, MFG_Texture, 103.0f, false ); ImplementFeatureType( MFT_TerrainMacroMap, MFG_Texture, 104.0f, false ); ImplementFeatureType( MFT_TerrainLightMap, MFG_Texture, 105.0f, false ); ImplementFeatureType( MFT_TerrainSideProject, MFG_Texture, 106.0f, false ); -ImplementFeatureType( MFT_TerrainAdditive, MFG_PostProcess, 999.0f, false ); +ImplementFeatureType( MFT_TerrainHeightBlend, MFG_PreLighting, 200.0f, false ); //Deferred Shading ImplementFeatureType( MFT_DeferredTerrainBlankInfoMap, MFG_Texture, 104.1f, false); ImplementFeatureType( MFT_TerrainORMMap, MFG_Texture, 104.2f, false); diff --git a/Engine/source/terrain/terrFeatureTypes.h b/Engine/source/terrain/terrFeatureTypes.h index 043e052cf..825758af9 100644 --- a/Engine/source/terrain/terrFeatureTypes.h +++ b/Engine/source/terrain/terrFeatureTypes.h @@ -34,7 +34,7 @@ DeclareFeatureType( MFT_TerrainNormalMap ); DeclareFeatureType( MFT_TerrainParallaxMap ); DeclareFeatureType( MFT_TerrainLightMap ); DeclareFeatureType( MFT_TerrainSideProject ); -DeclareFeatureType( MFT_TerrainAdditive ); +DeclareFeatureType( MFT_TerrainHeightBlend ); //Deferred Shading DeclareFeatureType( MFT_TerrainORMMap ); DeclareFeatureType( MFT_DeferredTerrainBlankInfoMap ); diff --git a/Engine/source/terrain/terrMaterial.cpp b/Engine/source/terrain/terrMaterial.cpp index 74a0c51e0..5d1c3330d 100644 --- a/Engine/source/terrain/terrMaterial.cpp +++ b/Engine/source/terrain/terrMaterial.cpp @@ -68,6 +68,7 @@ TerrainMaterial::TerrainMaterial() mMacroStrength( 0.7f ), mMacroDistance( 500.0f ), mParallaxScale( 0.0f ), + mBlendDepth( 0.5f ), mIsSRGB(false), mInvertRoughness(false) { @@ -91,6 +92,9 @@ void TerrainMaterial::initPersistFields() addField( "parallaxScale", TypeF32, Offset( mParallaxScale, TerrainMaterial ), "Used to scale the height from the normal map to give some self " "occlusion effect (aka parallax) to the terrain material" ); + addField("blendDepth", TypeF32, Offset(mBlendDepth, TerrainMaterial), "Depth for blending the textures using the new blending method by Lukas Joergensen." + "Higher numbers = larger blend radius."); + scriptBindMapSlot(DetailMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo up close."); addField( "detailSize", TypeF32, Offset( mDetailSize, TerrainMaterial ), "Used to scale the detail map to the material square" ); addField( "detailStrength", TypeF32, Offset( mDetailStrength, TerrainMaterial ), "Exponentially sharpens or lightens the detail map rendering on the material" ); diff --git a/Engine/source/terrain/terrMaterial.h b/Engine/source/terrain/terrMaterial.h index cc9b7d8b1..c3896190f 100644 --- a/Engine/source/terrain/terrMaterial.h +++ b/Engine/source/terrain/terrMaterial.h @@ -85,6 +85,11 @@ protected: /// F32 mParallaxScale; + /// Depth for blending the textures using the new + /// blending method. Higher numbers = larger blend + /// radius. + F32 mBlendDepth; + public: TerrainMaterial(); @@ -122,6 +127,8 @@ public: F32 getParallaxScale() const { return mParallaxScale; } + F32 getBlendDepth() const { return mBlendDepth; } + bool getIsSRGB() const { return mIsSRGB; } bool getInvertRoughness() const { return mInvertRoughness; }