Merge branch 'Atom/santorac/MultilayerPbrImprovements' into Atom/santorac/DepthBasedLayerBlending

This commit is contained in:
Chris Santora
2021-05-13 12:12:51 -07:00
19 changed files with 182 additions and 46 deletions
@@ -199,7 +199,7 @@
"displayName": "Debug Draw Mode",
"description": "Enables various debug view features.",
"type": "Enum",
"enumValues": [ "None", "BlendSource", "DepthMaps" ],
"enumValues": [ "None", "BlendSource", "DisplacementMaps" ],
"defaultValue": "None",
"connection": {
"type": "ShaderOption",
@@ -322,11 +322,11 @@
"displayName": "Blend Source",
"description": "The source to use for defining the blend mask. Note VertexColors mode will still use the texture as a fallback if the mesh does not have a COLOR0 stream.",
"type": "Enum",
"enumValues": ["TextureMap", "VertexColors"],
"defaultValue": "TextureMap",
"enumValues": ["BlendMask", "VertexColors", "Displacement"],
"defaultValue": "BlendMask",
"connection": {
"type": "ShaderOption",
"id": "o_blendSource"
"id": "o_layerBlendSource"
}
},
{
@@ -62,8 +62,8 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
uint m_parallaxUvIndex;
// These are used to limit the heightmap intersection search range to the narrowest band possible, to give the best quality result.
float m_displacementMin; // The lowest displacement value possible from all layers combined
float m_displacementMax; // The highest displacement value possible from all layers combined
float m_displacementMin; // The lowest displacement value possible from all layers combined (negative values are below the surface)
float m_displacementMax; // The highest displacement value possible from all layers combined (negative values are below the surface)
float3x3 m_uvMatrix;
float4 m_pad4; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed.
@@ -95,14 +95,11 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
// ------ Shader Options ----------------------------------------
option bool o_layer2_enabled;
option bool o_layer3_enabled;
enum class DebugDrawMode { None, BlendSource, DepthMaps };
enum class DebugDrawMode { None, BlendSource, DisplacementMaps };
option DebugDrawMode o_debugDrawMode;
enum class BlendMaskSource { TextureMap, VertexColors, Fallback };
option BlendMaskSource o_blendSource;
enum class LayerBlendSource { BlendMask, VertexColors, Displacement, Fallback };
option LayerBlendSource o_layerBlendSource;
// Indicates whether the vertex input struct's "m_optional_blendMask" is bound. If false, it is not safe to read from m_optional_blendMask.
// This option gets set automatically by the system at runtime; there is a soft naming convention that associates it with m_optional_blendMask.
@@ -111,32 +108,35 @@ option BlendMaskSource o_blendSource;
option bool o_blendMask_isBound;
// ------ Blend Utilities ----------------------------------------
// This is mainly used to pass extra data to the GetDepth callback function during the parallax depth search.
// But since we have it, we use it in some other functions as well rather than passing it around.
static float3 s_blendMaskFromVertexStream;
//! Returns the BlendMaskSource that will actually be used when rendering (not necessarily the same BlendMaskSource specified by the user)
BlendMaskSource GetFinalBlendMaskSource()
//! Returns the LayerBlendSource that will actually be used when rendering (not necessarily the same LayerBlendSource specified by the user)
LayerBlendSource GetFinalLayerBlendSource()
{
if(o_blendSource == BlendMaskSource::TextureMap)
if(o_layerBlendSource == LayerBlendSource::BlendMask)
{
return BlendMaskSource::TextureMap;
return LayerBlendSource::BlendMask;
}
else if(o_blendSource == BlendMaskSource::VertexColors)
else if(o_layerBlendSource == LayerBlendSource::VertexColors)
{
if(o_blendMask_isBound)
{
return BlendMaskSource::VertexColors;
return LayerBlendSource::VertexColors;
}
else
{
return BlendMaskSource::TextureMap;
return LayerBlendSource::BlendMask;
}
}
else if(o_layerBlendSource == LayerBlendSource::Displacement)
{
return LayerBlendSource::Displacement;
}
else
{
return BlendMaskSource::Fallback;
return LayerBlendSource::Fallback;
}
}
@@ -175,6 +175,19 @@ float3 GetBlendSourceValues(float2 uv)
return blendSourceValues;
}
//! Returns blend weights given the depth values for each layer
//! @param layerDepthValues - the per-layer depth values as provided by GetLayerDepthValues()
float3 GetBlendWeightsFromLayerDepthValues(float3 layerDepthValues)
{
float highestPoint = min(layerDepthValues.x, min(layerDepthValues.y, layerDepthValues.z));
float3 blendWeights = float3(layerDepthValues.x <= highestPoint ? 1.0 : 0.0,
layerDepthValues.y <= highestPoint ? 1.0 : 0.0,
layerDepthValues.z <= highestPoint ? 1.0 : 0.0);
return blendWeights;
}
float3 GetLayerDepthValues(float2 uv, float2 uv_ddx, float2 uv_ddy);
//! Return the final blend mask values to be used for rendering, based on the available data and configuration.
//! @return The blend weights for each layer.
//! Even though layer1 not explicitly specified in the blend source data, it is explicitly included with the returned values.
@@ -207,6 +220,21 @@ float3 GetBlendWeights(float2 uv)
return blendWeights;
}
//! Return the final blend mask values to be used for rendering, based on the available data and configuration.
//! Note this will sample the displacement maps in the case of LayerBlendSource::Displacement. If you have already
//! called GetLayerDepthValues(), use the GetBlendWeights() overlad that takes layerDepthValues instead.
float3 GetBlendWeights(float2 uv, float3 vertexBlendWeights)
{
float3 layerDepthValues = float3(0,0,0);
if(GetFinalLayerBlendSource() == LayerBlendSource::Displacement)
{
layerDepthValues = GetLayerDepthValues(uv, ddx_fine(uv), ddy_fine(uv));
}
return GetBlendWeights(uv, vertexBlendWeights, layerDepthValues);
}
float BlendLayers(float layer1, float layer2, float layer3, float3 blendWeights)
{
return dot(float3(layer1, layer2, layer3), blendWeights);
@@ -236,8 +264,8 @@ bool ShouldHandleParallaxInDepthShaders()
return ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
}
// Callback function for ParallaxMapping.azsli
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
//! Returns the depth values for each layer
float3 GetLayerDepthValues(float2 uv, float2 uv_ddx, float2 uv_ddy)
{
float3 layerDepthValues = float3(0,0,0);
@@ -279,12 +307,20 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
layerDepthValues.b *= MaterialSrg::m_layer3_m_depthFactor;
layerDepthValues.b -= MaterialSrg::m_layer3_m_depthOffset;
}
return layerDepthValues;
}
//! Callback function for ParallaxMapping.azsli
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
{
float3 layerDepthValues = GetLayerDepthValues(uv, uv_ddx, uv_ddy);
// Note, when the blend source is BlendMaskSource::VertexColors, parallax will not be able to blend correctly between layers. It will end up using the same blend mask values
// Note, when the blend source is LayerBlendSource::VertexColors, parallax will not be able to blend correctly between layers. It will end up using the same blend mask values
// for every UV position when searching for the intersection. This leads to smearing artifacts at the transition point, but these won't be so noticeable as long as
// you have a small depth factor relative to the size of the blend transition.
float3 blendWeights = GetBlendWeights(uv);
float3 blendWeightValues = GetBlendWeights(uv, s_blendWeightsFromVertexStream, layerDepthValues);
float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeights);
float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeightValues);
return DepthResultAbsolute(depth);
}
@@ -53,7 +53,7 @@ struct VSDepthOutput
float3 m_tangent : TANGENT;
float3 m_bitangent : BITANGENT;
float3 m_worldPosition : UV0;
float3 m_blendMask : UV3;
float3 m_blendWeights : UV3;
};
VSDepthOutput MainVS(VSInput IN)
@@ -80,11 +80,11 @@ VSDepthOutput MainVS(VSInput IN)
if(o_blendMask_isBound)
{
OUT.m_blendMask = IN.m_optional_blendMask.rgb;
OUT.m_blendWeights = IN.m_optional_blendMask.rgb;
}
else
{
OUT.m_blendMask = float3(1,1,1);
OUT.m_blendWeights = float3(1,1,1);
}
return OUT;
@@ -94,7 +94,7 @@ struct VSOutput
// Extended fields (only referenced in this azsl file)...
float2 m_uv[UvSetCount] : UV1;
float3 m_blendMask : UV7;
float3 m_blendWeights : UV7;
};
#include <Atom/Features/Vertex/VertexHelper.azsli>
@@ -112,11 +112,11 @@ VSOutput ForwardPassVS(VSInput IN)
if(o_blendMask_isBound)
{
OUT.m_blendMask = IN.m_optional_blendMask.rgb;
OUT.m_blendWeights = IN.m_optional_blendMask.rgb;
}
else
{
OUT.m_blendMask = float3(1,1,1);
OUT.m_blendWeights = float3(1,1,1);
}
// Shadow coords will be calculated in the pixel shader in this case
@@ -332,13 +332,13 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// ------- Debug Modes -------
if(o_debugDrawMode == DebugDrawMode::BlendSource)
if(o_debugDrawMode == DebugDrawMode::BlendMaskValues)
{
float3 blendSource = GetBlendSourceValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]);
return DebugOutput(blendSource);
float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]);
return DebugOutput(blendMaskValues);
}
if(o_debugDrawMode == DebugDrawMode::DepthMaps)
if(o_debugDrawMode == DebugDrawMode::DisplacementMaps)
{
float depth = GetNormalizedDepth(-MaterialSrg::m_displacementMax, -MaterialSrg::m_displacementMin, IN.m_uv[MaterialSrg::m_parallaxUvIndex], float2(0,0), float2(0,0));
return DebugOutput(float3(depth,depth,depth));
@@ -434,7 +434,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// ------- Combine Albedo, roughness, specular, roughness ---------
float3 baseColor = BlendLayers(lightingInputLayer1.m_baseColor, lightingInputLayer2.m_baseColor, lightingInputLayer3.m_baseColor, blendWeights);
float3 baseColor = BlendLayers(layer1_baseColor, layer2_baseColor, layer3_baseColor, blendMaskValues);
float3 specularF0Factor = BlendLayers(lightingInputLayer1.m_specularF0Factor, lightingInputLayer2.m_specularF0Factor, lightingInputLayer3.m_specularF0Factor, blendWeights);
float3 metallic = BlendLayers(lightingInputLayer1.m_metallic, lightingInputLayer2.m_metallic, lightingInputLayer3.m_metallic, blendWeights);
@@ -33,7 +33,7 @@ function GetShaderOptionDependencies()
return {"o_parallax_feature_enabled"}
end
function MergeRange(heightMinMax, offset, factor)
function GetMergedHeightRange(heightMinMax, offset, factor)
top = offset
bottom = offset - factor
@@ -68,9 +68,9 @@ function Process(context)
local offsetLayer3 = context:GetMaterialPropertyValue_float("layer3_parallax.offset")
local heightMinMax = {nil, nil}
if(enable1) then MergeRange(heightMinMax, offsetLayer1, factorLayer1) end
if(enable2) then MergeRange(heightMinMax, offsetLayer2, factorLayer2) end
if(enable3) then MergeRange(heightMinMax, offsetLayer3, factorLayer3) end
if(enable1) then GetMergedHeightRange(heightMinMax, offsetLayer1, factorLayer1) end
if(enable2) then GetMergedHeightRange(heightMinMax, offsetLayer2, factorLayer2) end
if(enable3) then GetMergedHeightRange(heightMinMax, offsetLayer3, factorLayer3) end
if(heightMinMax[1] - heightMinMax[0] < 0.0001) then
context:SetShaderOptionValue_bool("o_parallax_feature_enabled", false)
@@ -53,7 +53,7 @@ struct VertexOutput
float3 m_tangent : TANGENT;
float3 m_bitangent : BITANGENT;
float3 m_worldPosition : UV0;
float3 m_blendMask : UV3;
float3 m_blendWeights : UV3;
};
VertexOutput MainVS(VertexInput IN)
@@ -79,11 +79,11 @@ VertexOutput MainVS(VertexInput IN)
if(o_blendMask_isBound)
{
OUT.m_blendMask = IN.m_optional_blendMask.rgb;
OUT.m_blendWeights = IN.m_optional_blendMask.rgb;
}
else
{
OUT.m_blendMask = float3(1,1,1);
OUT.m_blendWeights = float3(1,1,1);
}
return OUT;
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"general": {
"debugDrawMode": "BlendSource"
"debugDrawMode": "BlendMaskValues"
}
}
}
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"general": {
"debugDrawMode": "DepthMaps"
"debugDrawMode": "DisplacementMaps"
}
}
}
@@ -0,0 +1,70 @@
{
"description": "",
"materialType": "Materials/Types/StandardMultilayerPBR.materialtype",
"parentMaterial": "",
"propertyLayoutVersion": 3,
"properties": {
"blend": {
"blendSource": "Displacement"
},
"layer1_baseColor": {
"textureMap": "TestData/Textures/cc0/Rock030_2K_Color.jpg"
},
"layer1_normal": {
"textureMap": "TestData/Textures/cc0/Rock030_2K_Normal.jpg"
},
"layer1_occlusion": {
"diffuseTextureMap": "TestData/Textures/cc0/Rocks002_1K_AmbientOcclusion.jpg"
},
"layer1_parallax": {
"enable": true,
"factor": 0.10000000149011612,
"textureMap": "TestData/Textures/cc0/Rock030_2K_Displacement.jpg"
},
"layer1_roughness": {
"textureMap": "TestData/Textures/cc0/Rock030_2K_Roughness.jpg"
},
"layer2_baseColor": {
"textureMap": "TestData/Textures/cc0/Ground033_1K_Color.jpg"
},
"layer2_normal": {
"textureMap": "TestData/Textures/cc0/Ground033_1K_Normal.jpg"
},
"layer2_occlusion": {
"diffuseTextureMap": "TestData/Textures/cc0/Ground033_1K_AmbientOcclusion.jpg"
},
"layer2_parallax": {
"enable": true,
"factor": 0.014999999664723874,
"offset": -0.024000000208616258,
"textureMap": "TestData/Textures/cc0/Ground033_1K_Displacement.jpg"
},
"layer2_roughness": {
"textureMap": "TestData/Textures/cc0/Ground033_1K_Roughness.jpg"
},
"layer3_baseColor": {
"textureMap": "TestData/Textures/cc0/Rocks002_1K_Color.jpg"
},
"layer3_normal": {
"textureMap": "TestData/Textures/cc0/Rocks002_1K_Normal.jpg"
},
"layer3_parallax": {
"enable": true,
"factor": 0.027000000700354577,
"offset": -0.02199999988079071,
"textureMap": "TestData/Textures/cc0/Rocks002_1K_Displacement.jpg"
},
"layer3_roughness": {
"textureMap": "TestData/Textures/cc0/Rocks002_1K_Roughness.jpg"
},
"layer3_uv": {
"scale": 1.600000023841858
},
"parallax": {
"algorithm": "Relief",
"enable": true,
"pdo": true,
"quality": "Low"
}
}
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f9ec269d03a9552c0ecf24778912fa6190c412b006433db8b7c40e1c0c83e6f7
size 516915
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b53c4aca020d5833618a5b73b6578c8693dd14e603eb32681e2c7ecc90f59047
size 1020622
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:46ea8a9406ce6df21ce3a6045aac5b1421ce119919ff050951277dd76464ee2c
size 258716
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ac1ad9bea240374bfc6aaaacc42e24eadfbf93c7185617fc1c52e610cb45cb69
size 1292910
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8fce266a7445a4d4b5bb3fbf7cb3330e0580b058aeaf2ef7f265a01641dbbdc4
size 637326
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ca54f762bcddc10ab2d609f10864328cb5a567c43efb8c9bcfe9cb2955db9577
size 433887
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5b5f5ff297aef6470045d087cf0c3341f7782e36a750965a052d49d03dd37426
size 1595449
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c8753448320e0916a70036ef77a06bce746bfa45c14e62b2fbda0987a13bfbb3
size 277114
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5ea23ea8d85d1fffa119e481e6ac85ad3a3096470a5e12f252d37e1b293e5e37
size 2119669
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:caa6e94f904135461da4d200fc6c21c86dc99cc7d413ea740e678f7758b2b156
size 555680