Merge branch 'main' into jromnoa_atom_renderer_test_fix
This commit is contained in:
@@ -42,6 +42,7 @@ class TestAssetPicker(object):
|
||||
|
||||
@pytest.mark.test_case_id("C13751579", "C1508814")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.xfail # ATOM-15493
|
||||
def test_AssetPicker_UI_UX(self, request, editor, level, launcher_platform):
|
||||
expected_lines = [
|
||||
"TestEntity Entity successfully created",
|
||||
|
||||
@@ -946,19 +946,6 @@
|
||||
"type": "Bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the depth values",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"min": 0.0,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_depthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture Map",
|
||||
@@ -981,6 +968,32 @@
|
||||
"id": "m_parallaxUvIndex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Heightmap Scale",
|
||||
"description": "The total height of the heightmap in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"min": 0.0,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_depthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "offset",
|
||||
"displayName": "Offset",
|
||||
"description": "Adjusts the overall displacement amount in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"softMin": -0.1,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_depthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invert",
|
||||
"displayName": "Invert",
|
||||
@@ -1026,6 +1039,17 @@
|
||||
"type": "ShaderOption",
|
||||
"id": "o_parallax_enablePixelDepthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "showClipping",
|
||||
"displayName": "Show Clipping",
|
||||
"description": "Highlight areas where the heightmap is clipped by the mesh surface.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_parallax_highlightClipping"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subsurfaceScattering": [
|
||||
@@ -1714,22 +1738,6 @@
|
||||
"shaderOption": "o_emissive_useTexture"
|
||||
}
|
||||
},
|
||||
{
|
||||
// See the comment above for details.
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "parallax.textureMap",
|
||||
"dependentProperties": ["parallax.textureMapUv"],
|
||||
"useTextureProperty": "parallax.enable",
|
||||
"shaderTags": [
|
||||
"ForwardPass",
|
||||
"ForwardPass_EDS",
|
||||
"Shadowmap_WithPS",
|
||||
"DepthPass_WithPS"
|
||||
],
|
||||
"shaderOption": "o_parallax_feature_enabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
// See the comment above for details.
|
||||
"type": "UseTexture",
|
||||
@@ -1813,34 +1821,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
// Controls visibility for properties in the editor.
|
||||
// @param actions - a list of actions that are executed in order. visibility will be set when triggerProperty hits the triggerValue.
|
||||
// @param affectedProperties - the properties that are affected by actions.
|
||||
"type": "UpdatePropertyVisibility",
|
||||
"args": {
|
||||
"actions": [
|
||||
{
|
||||
"triggerProperty": "parallax.enable",
|
||||
"triggerValue": true,
|
||||
"visibility": "Enabled"
|
||||
},
|
||||
{
|
||||
"triggerProperty": "parallax.enable",
|
||||
"triggerValue": false,
|
||||
"visibility": "Hidden"
|
||||
}
|
||||
],
|
||||
"affectedProperties": [
|
||||
"parallax.factor",
|
||||
"parallax.textureMap",
|
||||
"parallax.invert",
|
||||
"parallax.algorithm",
|
||||
"parallax.quality",
|
||||
"parallax.pdo"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UpdatePropertyVisibility",
|
||||
"args": {
|
||||
@@ -2076,6 +2056,12 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
"file": "StandardPBR_ParallaxState.lua"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
#include <viewsrg.srgi>
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
|
||||
#include "MaterialInputs/BaseColorInput.azsli"
|
||||
#include "MaterialInputs/RoughnessInput.azsli"
|
||||
@@ -104,7 +106,22 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
}
|
||||
|
||||
// Callback function for ParallaxMapping.azsli
|
||||
float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
return SampleDepthOrHeightMap(MaterialSrg::m_depthInverted, MaterialSrg::m_depthMap, MaterialSrg::m_sampler, uv, uv_ddx, uv_ddy);
|
||||
}
|
||||
|
||||
COMMON_OPTIONS_PARALLAX()
|
||||
|
||||
bool ShouldHandleParallax()
|
||||
{
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scattering is enabled.
|
||||
return !o_enableSubsurfaceScattering && o_parallax_feature_enabled && o_useDepthMap;
|
||||
}
|
||||
|
||||
bool ShouldHandleParallaxInDepthShaders()
|
||||
{
|
||||
// The depth pass shaders need to calculate parallax when the result could affect the depth buffer, or when
|
||||
// parallax could affect texel clipping.
|
||||
return ShouldHandleParallax() && (o_parallax_enablePixelDepthOffset || o_opacity_mode == OpacityMode::Cutout);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include "./EnhancedPBR_Common.azsli"
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/ParallaxMapping.azsli>
|
||||
@@ -55,7 +54,7 @@ VSDepthOutput MainVS(VSInput IN)
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
OUT.m_worldPosition = worldPosition.xyz;
|
||||
|
||||
@@ -74,45 +73,28 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
{
|
||||
PSDepthOutput OUT;
|
||||
|
||||
// Clip Alpha
|
||||
float2 baseColorUV = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
float alpha = SampleAlpha(MaterialSrg::m_baseColorMap, MaterialSrg::m_opacityMap, baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
float3 tangent = tangents[MaterialSrg::m_parallaxUvIndex];
|
||||
float3 bitangent = bitangents[MaterialSrg::m_parallaxUvIndex];
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
float3 tangentOffset = GetParallaxOffset( MaterialSrg::m_depthFactor,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex],
|
||||
ViewSrg::m_worldPosition.xyz - IN.m_worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrix);
|
||||
|
||||
PixelDepthOffset pdo = CalcPixelDepthOffset(MaterialSrg::m_depthFactor,
|
||||
tangentOffset,
|
||||
IN.m_worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrixInverse,
|
||||
ObjectSrg::GetWorldMatrix(),
|
||||
ViewSrg::m_viewProjectionMatrix);
|
||||
OUT.m_depth = pdo.m_depth;
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor, MaterialSrg::m_depthOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, OUT.m_depth);
|
||||
}
|
||||
|
||||
// Clip Alpha
|
||||
float2 baseColorUV = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
float alpha = SampleAlpha(MaterialSrg::m_baseColorMap, MaterialSrg::m_opacityMap, baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ COMMON_OPTIONS_NORMAL()
|
||||
COMMON_OPTIONS_CLEAR_COAT()
|
||||
COMMON_OPTIONS_OCCLUSION()
|
||||
COMMON_OPTIONS_EMISSIVE()
|
||||
COMMON_OPTIONS_PARALLAX()
|
||||
COMMON_OPTIONS_DETAIL_MAPS()
|
||||
// Note COMMON_OPTIONS_PARALLAX is in StandardPBR_Common.azsli because it's needed by all StandardPBR shaders.
|
||||
|
||||
// Alpha
|
||||
#include "MaterialInputs/AlphaInput.azsli"
|
||||
@@ -102,8 +102,11 @@ VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
|
||||
// but we would need to address how it works with the parallax code below that indexes into the m_detailUV array.
|
||||
OUT.m_detailUv[0] = mul(MaterialSrg::m_detailUvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_detailUv[1] = mul(MaterialSrg::m_detailUvMatrix, float3(IN.m_uv1, 1.0)).xy;
|
||||
|
||||
// Shadow coords will be calculated in the pixel shader in this case
|
||||
bool skipShadowCoords = ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
|
||||
|
||||
VertexHelper(IN, OUT, worldPosition, o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset);
|
||||
VertexHelper(IN, OUT, worldPosition, skipShadowCoords);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -132,9 +135,11 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
// ------- Depth & Parallax -------
|
||||
|
||||
depth = IN.m_position.z;
|
||||
|
||||
bool displacementIsClipped = false;
|
||||
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scatteirng is enabled
|
||||
if(!o_enableSubsurfaceScattering && o_parallax_feature_enabled && o_useDepthMap)
|
||||
if(ShouldHandleParallax())
|
||||
{
|
||||
// GetParallaxInput applies an tangent offset to the UV. We want to apply the same offset to the detailUv (note: this needs to be tested with content)
|
||||
// The math is: offset = newUv - oldUv; detailUv += offset;
|
||||
@@ -143,9 +148,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor,
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor, MaterialSrg::m_depthOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth);
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth, displacementIsClipped);
|
||||
|
||||
// Apply second part of the offset to the detail UV (see comment above)
|
||||
IN.m_detailUv[MaterialSrg::m_parallaxUvIndex] -= IN.m_uv[MaterialSrg::m_parallaxUvIndex];
|
||||
@@ -206,6 +211,11 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float3 baseColor = GetDetailedBaseColorInput(
|
||||
MaterialSrg::m_baseColorMap, MaterialSrg::m_sampler, baseColorUv, o_baseColor_useTexture, MaterialSrg::m_baseColor, MaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode,
|
||||
MaterialSrg::m_detail_baseColor_texture, MaterialSrg::m_sampler, detailUv, o_detail_baseColor_useTexture, detailLayerBaseColorFactor);
|
||||
|
||||
if(o_parallax_highlightClipping && displacementIsClipped)
|
||||
{
|
||||
ApplyParallaxClippingHighlight(baseColor);
|
||||
}
|
||||
|
||||
// ------- Metallic -------
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include "EnhancedPBR_Common.azsli"
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/ParallaxMapping.azsli>
|
||||
#include <Atom/Features/MatrixUtility.azsli>
|
||||
@@ -54,8 +53,8 @@ VertexOutput MainVS(VertexInput IN)
|
||||
// By design, only UV0 is allowed to apply transforms.
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
OUT.m_worldPosition = worldPosition.xyz;
|
||||
|
||||
@@ -75,57 +74,32 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
{
|
||||
PSDepthOutput OUT;
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
static const float ShadowMapDepthBias = 0.000001;
|
||||
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor, MaterialSrg::m_depthOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, OUT.m_depth);
|
||||
|
||||
OUT.m_depth += ShadowMapDepthBias;
|
||||
}
|
||||
|
||||
// Clip Alpha
|
||||
float2 baseColorUV = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
float alpha = SampleAlpha(MaterialSrg::m_baseColorMap, MaterialSrg::m_opacityMap, baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
float3 dirToCamera;
|
||||
if(ViewSrg::m_projectionMatrix[0].w)
|
||||
{
|
||||
// orthographic projection (directional light)
|
||||
// No view position, use light direction
|
||||
dirToCamera = ViewSrg::m_viewMatrix[2].xyz;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirToCamera = ViewSrg::m_worldPosition.xyz - IN.m_worldPosition;
|
||||
}
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
{
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
float3 tangent = tangents[MaterialSrg::m_parallaxUvIndex];
|
||||
float3 bitangent = bitangents[MaterialSrg::m_parallaxUvIndex];
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
float3 tangentOffset = GetParallaxOffset( MaterialSrg::m_depthFactor,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex],
|
||||
dirToCamera,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrix);
|
||||
|
||||
PixelDepthOffset pdo = CalcPixelDepthOffset(MaterialSrg::m_depthFactor,
|
||||
tangentOffset,
|
||||
IN.m_worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrixInverse,
|
||||
ObjectSrg::GetWorldMatrix(),
|
||||
ViewSrg::m_viewProjectionMatrix);
|
||||
OUT.m_depth = pdo.m_depth;
|
||||
}
|
||||
return OUT;
|
||||
}
|
||||
|
||||
+25
-13
@@ -24,16 +24,15 @@
|
||||
#define COMMON_SRG_INPUTS_PARALLAX(prefix) \
|
||||
Texture2D prefix##m_depthMap; \
|
||||
float prefix##m_depthFactor; \
|
||||
float prefix##m_depthOffset; \
|
||||
bool prefix##m_depthInverted;
|
||||
|
||||
#define COMMON_OPTIONS_PARALLAX(prefix) \
|
||||
option bool prefix##o_useDepthMap;
|
||||
|
||||
option bool o_parallax_feature_enabled;
|
||||
|
||||
void GetParallaxInput(float3 normal, float3 tangent, float3 bitangent, float depthFactor,
|
||||
void GetParallaxInput(float3 normal, float3 tangent, float3 bitangent, float depthFactor, float depthOffset,
|
||||
float4x4 objectWorldMatrix, float3x3 uvMatrix, float3x3 uvMatrixInverse,
|
||||
inout float2 uv, inout float3 worldPosition, inout float depth)
|
||||
inout float2 uv, inout float3 worldPosition, inout float depth, out bool isClipped)
|
||||
{
|
||||
if(o_parallax_feature_enabled)
|
||||
{
|
||||
@@ -49,20 +48,22 @@ void GetParallaxInput(float3 normal, float3 tangent, float3 bitangent, float dep
|
||||
dirToCamera = ViewSrg::m_worldPosition.xyz - worldPosition;
|
||||
}
|
||||
|
||||
float3 tangentOffset = GetParallaxOffset( depthFactor,
|
||||
uv,
|
||||
dirToCamera,
|
||||
tangent,
|
||||
bitangent,
|
||||
normal,
|
||||
uvMatrix);
|
||||
ParallaxOffset tangentOffset = GetParallaxOffset( depthFactor,
|
||||
depthOffset,
|
||||
uv,
|
||||
dirToCamera,
|
||||
tangent,
|
||||
bitangent,
|
||||
normal,
|
||||
uvMatrix);
|
||||
|
||||
uv += tangentOffset.xy;
|
||||
uv += tangentOffset.m_offsetTS.xy;
|
||||
isClipped = tangentOffset.m_isClipped;
|
||||
|
||||
if(o_parallax_enablePixelDepthOffset)
|
||||
{
|
||||
PixelDepthOffset pdo = CalcPixelDepthOffset(depthFactor,
|
||||
tangentOffset,
|
||||
tangentOffset.m_offsetTS,
|
||||
worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
@@ -70,9 +71,20 @@ void GetParallaxInput(float3 normal, float3 tangent, float3 bitangent, float dep
|
||||
uvMatrixInverse,
|
||||
objectWorldMatrix,
|
||||
ViewSrg::m_viewProjectionMatrix);
|
||||
|
||||
depth = pdo.m_depth;
|
||||
|
||||
worldPosition = pdo.m_worldPosition;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void GetParallaxInput(float3 normal, float3 tangent, float3 bitangent, float depthFactor, float depthOffset,
|
||||
float4x4 objectWorldMatrix, float3x3 uvMatrix, float3x3 uvMatrixInverse,
|
||||
inout float2 uv, inout float3 worldPosition, inout float depth)
|
||||
{
|
||||
bool isClipped;
|
||||
GetParallaxInput(normal, tangent, bitangent, depthFactor, depthOffset, objectWorldMatrix, uvMatrix, uvMatrixInverse, uv, worldPosition, depth, isClipped);
|
||||
}
|
||||
|
||||
|
||||
+54
-119
@@ -18,11 +18,6 @@
|
||||
"displayName": "Parallax Settings",
|
||||
"description": "Properties for configuring the parallax effect, applied to all layers."
|
||||
},
|
||||
{
|
||||
"id": "opacity",
|
||||
"displayName": "Opacity",
|
||||
"description": "Properties for configuring the materials transparency."
|
||||
},
|
||||
{
|
||||
"id": "uv",
|
||||
"displayName": "UVs",
|
||||
@@ -361,19 +356,6 @@
|
||||
"id": "m_parallaxUvIndex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the depth values for all layers.",
|
||||
"type": "Float",
|
||||
"defaultValue": 1.0,
|
||||
"min": 0.0,
|
||||
"softMax": 2.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_parallaxMainDepthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "algorithm",
|
||||
"displayName": "Algorithm",
|
||||
@@ -408,73 +390,17 @@
|
||||
"type": "ShaderOption",
|
||||
"id": "o_parallax_enablePixelDepthOffset"
|
||||
}
|
||||
}
|
||||
],
|
||||
"opacity": [
|
||||
},
|
||||
{
|
||||
"id": "mode",
|
||||
"displayName": "Opacity Mode",
|
||||
"description": "Opacity mode for this texture.",
|
||||
"type": "Enum",
|
||||
"enumValues": [ "Opaque", "Cutout", "Blended" ],
|
||||
"defaultValue": "Opaque",
|
||||
"id": "showClipping",
|
||||
"displayName": "Show Clipping",
|
||||
"description": "Highlight areas where the heightmap is clipped by the mesh surface.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_opacity_mode"
|
||||
"id": "o_parallax_highlightClipping"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "alphaSource",
|
||||
"displayName": "Alpha Source",
|
||||
"description": "Source texture of alpha value.",
|
||||
"type": "Enum",
|
||||
"enumValues": [ "Packed", "Split", "None" ],
|
||||
"defaultValue": "Packed",
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_opacity_source"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture Map",
|
||||
"description": "Texture map for defining surface opacity.",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_opacityMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "textureMapUv",
|
||||
"displayName": "UV",
|
||||
"description": "Opacity texture map UV set",
|
||||
"type": "Enum",
|
||||
"enumIsUv": true,
|
||||
"defaultValue": "Tiled",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_opacityMapUvIndex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Factor for cutout threshold and blending",
|
||||
"type": "Float",
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"defaultValue": 0.5,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_opacityFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "doubleSided",
|
||||
"displayName": "Double-sided",
|
||||
"description": "Whether to render back-faces or just front-faces.",
|
||||
"type": "Bool"
|
||||
}
|
||||
],
|
||||
"uv": [
|
||||
@@ -1343,8 +1269,8 @@
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the depth values",
|
||||
"displayName": "Heightmap Scale",
|
||||
"description": "The total height of the heightmap in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"min": 0.0,
|
||||
@@ -1354,6 +1280,19 @@
|
||||
"id": "m_layer1_m_depthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "offset",
|
||||
"displayName": "Offset",
|
||||
"description": "Adjusts the overall displacement amount in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"softMin": -0.1,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_layer1_m_depthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invert",
|
||||
"displayName": "Invert",
|
||||
@@ -2036,8 +1975,8 @@
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the depth values",
|
||||
"displayName": "Heightmap Scale",
|
||||
"description": "The total height of the heightmap in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"min": 0.0,
|
||||
@@ -2047,6 +1986,19 @@
|
||||
"id": "m_layer2_m_depthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "offset",
|
||||
"displayName": "Offset",
|
||||
"description": "Adjusts the overall displacement amount in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"softMin": -0.1,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_layer2_m_depthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invert",
|
||||
"displayName": "Invert",
|
||||
@@ -2729,8 +2681,8 @@
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the depth values",
|
||||
"displayName": "Heightmap Scale",
|
||||
"description": "The total height of the heightmap in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"min": 0.0,
|
||||
@@ -2740,6 +2692,19 @@
|
||||
"id": "m_layer3_m_depthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "offset",
|
||||
"displayName": "Offset",
|
||||
"description": "Adjusts the overall displacement amount in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"softMin": -0.1,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_layer3_m_depthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invert",
|
||||
"displayName": "Invert",
|
||||
@@ -2851,16 +2816,7 @@
|
||||
{
|
||||
"file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
|
||||
"tag": "SkinnedMeshMotionVector"
|
||||
},
|
||||
// Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency
|
||||
{
|
||||
"file": "Shaders/Depth/DepthPassTransparentMin.shader",
|
||||
"tag": "DepthPassTransparentMin"
|
||||
},
|
||||
{
|
||||
"file": "Shaders/Depth/DepthPassTransparentMax.shader",
|
||||
"tag": "DepthPassTransparentMax"
|
||||
}
|
||||
}
|
||||
],
|
||||
"functors": [
|
||||
//##############################################################################################
|
||||
@@ -2885,7 +2841,7 @@
|
||||
{
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
"file": "StandardPBR_ShaderEnable.lua"
|
||||
"file": "StandardMultilayerPBR_ShaderEnable.lua"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2925,27 +2881,6 @@
|
||||
"file": "StandardPBR_SubsurfaceState.lua"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
"file": "StandardPBR_HandleOpacityDoubleSided.lua"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "OverrideDrawList",
|
||||
"args": {
|
||||
"triggerProperty": "opacity.mode",
|
||||
"triggerValue": "Blended",
|
||||
"shaderIndex": 1,
|
||||
"drawList": "transparent"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
"file": "StandardPBR_HandleOpacityMode.lua"
|
||||
}
|
||||
},
|
||||
//##############################################################################################
|
||||
// Layer 1 Functors
|
||||
//##############################################################################################
|
||||
|
||||
+36
-12
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
|
||||
#include "MaterialInputs/BaseColorInput.azsli"
|
||||
#include "MaterialInputs/RoughnessInput.azsli"
|
||||
@@ -26,6 +27,8 @@
|
||||
#include "MaterialInputs/ParallaxInput.azsli"
|
||||
#include "MaterialInputs/UvSetCount.azsli"
|
||||
|
||||
// ------ ShaderResourceGroup ----------------------------------------
|
||||
|
||||
#define DEFINE_LAYER_SRG_INPUTS(prefix) \
|
||||
COMMON_SRG_INPUTS_BASE_COLOR(prefix) \
|
||||
COMMON_SRG_INPUTS_ROUGHNESS(prefix) \
|
||||
@@ -57,17 +60,16 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
float4 m_pad3; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed.
|
||||
|
||||
uint m_parallaxUvIndex;
|
||||
float m_parallaxMainDepthFactor;
|
||||
|
||||
// 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
|
||||
|
||||
float3x3 m_uvMatrix;
|
||||
float4 m_pad4; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed.
|
||||
float3x3 m_uvMatrixInverse;
|
||||
float4 m_pad5; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed.
|
||||
|
||||
float m_opacityFactor;
|
||||
Texture2D m_opacityMap;
|
||||
uint m_opacityMapUvIndex;
|
||||
|
||||
Sampler m_sampler
|
||||
{
|
||||
AddressU = Wrap;
|
||||
@@ -109,6 +111,8 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
uint m_transmissionThicknessMapUvIndex;
|
||||
}
|
||||
|
||||
// ------ Shader Options ----------------------------------------
|
||||
|
||||
enum class DebugDrawMode { None, BlendMaskValues, DepthMaps };
|
||||
option DebugDrawMode o_debugDrawMode;
|
||||
|
||||
@@ -121,6 +125,8 @@ option BlendMaskSource o_blendSource;
|
||||
// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream.
|
||||
option bool o_blendMask_isBound;
|
||||
|
||||
// ------ Blend Utilities ----------------------------------------
|
||||
|
||||
//! Returns the BlendMaskSource that will actually be used when rendering (not necessarily the same BlendMaskSource specified by the user)
|
||||
BlendMaskSource GetFinalBlendMaskSource()
|
||||
{
|
||||
@@ -181,6 +187,22 @@ float3 BlendLayers(float3 layer1, float3 layer2, float3 layer3, float3 blendMask
|
||||
return layer1 * blendMaskValues.r + layer2 * blendMaskValues.g + layer3 * blendMaskValues.b;
|
||||
}
|
||||
|
||||
// ------ Parallax Utilities ----------------------------------------
|
||||
|
||||
bool ShouldHandleParallax()
|
||||
{
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scattering is enabled.
|
||||
// Also, all the debug draw modes avoid parallax (they early-return before parallax code actually) so you can see exactly where the various maps appear on the surface UV space.
|
||||
return !o_enableSubsurfaceScattering && o_parallax_feature_enabled && o_debugDrawMode == DebugDrawMode::None;
|
||||
}
|
||||
|
||||
bool ShouldHandleParallaxInDepthShaders()
|
||||
{
|
||||
// The depth pass shaders need to calculate parallax when the result could affect the depth buffer (or when
|
||||
// parallax could affect texel clipping but we don't have alpha/clipping support in multilayer PBR).
|
||||
return ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
|
||||
}
|
||||
|
||||
// These static values are used to pass extra data to the GetDepth callback function during the parallax depth search.
|
||||
static float3 s_blendMaskFromVertexStream;
|
||||
|
||||
@@ -192,7 +214,7 @@ void GetDepth_Setup(float3 vertexBlendMask)
|
||||
}
|
||||
|
||||
// Callback function for ParallaxMapping.azsli
|
||||
float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
float3 layerDepthValues = float3(0,0,0);
|
||||
|
||||
@@ -204,8 +226,9 @@ float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
layerUv = mul(MaterialSrg::m_layer1_m_uvMatrix, float3(uv, 1.0)).xy;
|
||||
}
|
||||
|
||||
layerDepthValues.r = SampleDepthOrHeightMap(MaterialSrg::m_layer1_m_depthInverted, MaterialSrg::m_layer1_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy);
|
||||
layerDepthValues.r = SampleDepthOrHeightMap(MaterialSrg::m_layer1_m_depthInverted, MaterialSrg::m_layer1_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy).m_depth;
|
||||
layerDepthValues.r *= MaterialSrg::m_layer1_m_depthFactor;
|
||||
layerDepthValues.r -= MaterialSrg::m_layer1_m_depthOffset;
|
||||
}
|
||||
|
||||
if(o_layer2_o_useDepthMap)
|
||||
@@ -216,8 +239,9 @@ float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
layerUv = mul(MaterialSrg::m_layer2_m_uvMatrix, float3(uv, 1.0)).xy;
|
||||
}
|
||||
|
||||
layerDepthValues.g = SampleDepthOrHeightMap(MaterialSrg::m_layer2_m_depthInverted, MaterialSrg::m_layer2_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy);
|
||||
layerDepthValues.g = SampleDepthOrHeightMap(MaterialSrg::m_layer2_m_depthInverted, MaterialSrg::m_layer2_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy).m_depth;
|
||||
layerDepthValues.g *= MaterialSrg::m_layer2_m_depthFactor;
|
||||
layerDepthValues.g -= MaterialSrg::m_layer2_m_depthOffset;
|
||||
}
|
||||
|
||||
if(o_layer3_o_useDepthMap)
|
||||
@@ -228,8 +252,9 @@ float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
layerUv = mul(MaterialSrg::m_layer3_m_uvMatrix, float3(uv, 1.0)).xy;
|
||||
}
|
||||
|
||||
layerDepthValues.b = SampleDepthOrHeightMap(MaterialSrg::m_layer3_m_depthInverted, MaterialSrg::m_layer3_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy);
|
||||
layerDepthValues.b = SampleDepthOrHeightMap(MaterialSrg::m_layer3_m_depthInverted, MaterialSrg::m_layer3_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy).m_depth;
|
||||
layerDepthValues.b *= MaterialSrg::m_layer3_m_depthFactor;
|
||||
layerDepthValues.b -= MaterialSrg::m_layer3_m_depthOffset;
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -237,7 +262,6 @@ float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
// you have a small depth factor relative to the size of the blend transition.
|
||||
float3 blendMaskValues = GetBlendMaskValues(uv, s_blendMaskFromVertexStream);
|
||||
|
||||
float3 depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendMaskValues);
|
||||
|
||||
return depth;
|
||||
float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendMaskValues);
|
||||
return DepthResultAbsolute(depth);
|
||||
}
|
||||
|
||||
+5
-14
@@ -11,12 +11,10 @@
|
||||
*/
|
||||
|
||||
#include <viewsrg.srgi>
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/ParallaxMapping.azsli>
|
||||
#include <Atom/Features/MatrixUtility.azsli>
|
||||
|
||||
#include "MaterialInputs/AlphaInput.azsli"
|
||||
#include "MaterialInputs/ParallaxInput.azsli"
|
||||
|
||||
|
||||
@@ -72,7 +70,7 @@ VSDepthOutput MainVS(VSInput IN)
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
OUT.m_worldPosition = worldPosition.xyz;
|
||||
|
||||
@@ -101,18 +99,9 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
{
|
||||
PSDepthOutput OUT;
|
||||
|
||||
// Alpha
|
||||
float2 layer1_baseColorUV = IN.m_uv[MaterialSrg::m_layer1_m_baseColorMapUvIndex];
|
||||
float2 layer2_baseColorUV = IN.m_uv[MaterialSrg::m_layer2_m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
// [GFX TODO][ATOM-14589] Figure out how to deal with opacity, instead of just hard-coding to layer1
|
||||
float alpha = SampleAlpha(MaterialSrg::m_layer1_m_baseColorMap, MaterialSrg::m_opacityMap, layer1_baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
if(o_debugDrawMode == DebugDrawMode::None && o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
@@ -126,7 +115,9 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_parallaxMainDepthFactor,
|
||||
float parallaxOverallOffset = MaterialSrg::m_displacementMax;
|
||||
float parallaxOverallFactor = MaterialSrg::m_displacementMax - MaterialSrg::m_displacementMin;
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], parallaxOverallFactor, parallaxOverallOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth);
|
||||
|
||||
|
||||
+24
-41
@@ -55,7 +55,6 @@ DEFINE_LAYER_OPTIONS(o_layer1_)
|
||||
DEFINE_LAYER_OPTIONS(o_layer2_)
|
||||
DEFINE_LAYER_OPTIONS(o_layer3_)
|
||||
|
||||
#include "MaterialInputs/AlphaInput.azsli"
|
||||
#include "MaterialInputs/SubsurfaceInput.azsli"
|
||||
#include "MaterialInputs/TransmissionInput.azsli"
|
||||
#include "StandardMultilayerPBR_Common.azsli"
|
||||
@@ -121,9 +120,8 @@ VSOutput ForwardPassVS(VSInput IN)
|
||||
OUT.m_blendMask = float3(1,1,1);
|
||||
}
|
||||
|
||||
// We can skip per-vertex shadow coords when parallax is enabled because we need to calculate per-pixel shadow coords anyway.
|
||||
// We cannot skip shadow coords when o_debugDrawMode is on because some debug draw modes return before parallax.
|
||||
bool skipShadowCoords = o_debugDrawMode == DebugDrawMode::None && o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset;
|
||||
// Shadow coords will be calculated in the pixel shader in this case
|
||||
bool skipShadowCoords = ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
|
||||
VertexHelper(IN, OUT, worldPosition, skipShadowCoords);
|
||||
|
||||
return OUT;
|
||||
@@ -167,23 +165,27 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
if(o_debugDrawMode == DebugDrawMode::DepthMaps)
|
||||
{
|
||||
GetDepth_Setup(IN.m_blendMask);
|
||||
float depth = GetDepth(IN.m_uv[MaterialSrg::m_parallaxUvIndex], float2(0,0), float2(0,0));
|
||||
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));
|
||||
}
|
||||
|
||||
// ------- Parallax -------
|
||||
|
||||
bool displacementIsClipped = false;
|
||||
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scatteirng is enabled
|
||||
if(!o_enableSubsurfaceScattering && o_parallax_feature_enabled)
|
||||
if(ShouldHandleParallax())
|
||||
{
|
||||
GetDepth_Setup(IN.m_blendMask);
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_parallaxMainDepthFactor,
|
||||
|
||||
float parallaxOverallOffset = MaterialSrg::m_displacementMax;
|
||||
float parallaxOverallFactor = MaterialSrg::m_displacementMax - MaterialSrg::m_displacementMin;
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], parallaxOverallFactor, parallaxOverallOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth);
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth, displacementIsClipped);
|
||||
|
||||
// Adjust directional light shadow coorinates for parallax correction
|
||||
if(o_parallax_enablePixelDepthOffset)
|
||||
@@ -218,15 +220,6 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
// Now that any parallax has been calculated, we calculate the blend factors for any layers that are impacted by the parallax.
|
||||
float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
|
||||
|
||||
// ------- Alpha & Clip -------
|
||||
|
||||
float2 layer1_baseColorUv = uvLayer1[MaterialSrg::m_layer1_m_baseColorMapUvIndex];
|
||||
float2 layer2_baseColorUv = uvLayer2[MaterialSrg::m_layer2_m_baseColorMapUvIndex];
|
||||
float2 layer3_baseColorUv = uvLayer3[MaterialSrg::m_layer3_m_baseColorMapUvIndex];
|
||||
float2 opacityUv = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
// [GFX TODO][ATOM-14589] Figure out how to deal with opacity, instead of just hard-coding to layer1
|
||||
float alpha = GetAlphaInputAndClip(MaterialSrg::m_layer1_m_baseColorMap, MaterialSrg::m_opacityMap, layer1_baseColorUv, opacityUv, MaterialSrg::m_sampler, MaterialSrg::m_opacityFactor, o_opacity_source);
|
||||
|
||||
// ------- Normal -------
|
||||
|
||||
float3 layer1_normalFactor = MaterialSrg::m_layer1_m_normalFactor * blendMaskValues.r;
|
||||
@@ -245,6 +238,10 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
|
||||
|
||||
// ------- Base Color -------
|
||||
|
||||
float2 layer1_baseColorUv = uvLayer1[MaterialSrg::m_layer1_m_baseColorMapUvIndex];
|
||||
float2 layer2_baseColorUv = uvLayer2[MaterialSrg::m_layer2_m_baseColorMapUvIndex];
|
||||
float2 layer3_baseColorUv = uvLayer3[MaterialSrg::m_layer3_m_baseColorMapUvIndex];
|
||||
|
||||
float3 layer1_sampledColor = GetBaseColorInput(MaterialSrg::m_layer1_m_baseColorMap, MaterialSrg::m_sampler, layer1_baseColorUv, MaterialSrg::m_layer1_m_baseColor.rgb, o_layer1_o_baseColor_useTexture);
|
||||
float3 layer2_sampledColor = GetBaseColorInput(MaterialSrg::m_layer2_m_baseColorMap, MaterialSrg::m_sampler, layer2_baseColorUv, MaterialSrg::m_layer2_m_baseColor.rgb, o_layer2_o_baseColor_useTexture);
|
||||
@@ -253,6 +250,11 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float3 layer2_baseColor = BlendBaseColor(layer2_sampledColor, MaterialSrg::m_layer2_m_baseColor.rgb, MaterialSrg::m_layer2_m_baseColorFactor, o_layer2_o_baseColorTextureBlendMode, o_layer2_o_baseColor_useTexture);
|
||||
float3 layer3_baseColor = BlendBaseColor(layer3_sampledColor, MaterialSrg::m_layer3_m_baseColor.rgb, MaterialSrg::m_layer3_m_baseColorFactor, o_layer3_o_baseColorTextureBlendMode, o_layer3_o_baseColor_useTexture);
|
||||
float3 baseColor = BlendLayers(layer1_baseColor, layer2_baseColor, layer3_baseColor, blendMaskValues);
|
||||
|
||||
if(o_parallax_highlightClipping && displacementIsClipped)
|
||||
{
|
||||
ApplyParallaxClippingHighlight(baseColor);
|
||||
}
|
||||
|
||||
// ------- Metallic -------
|
||||
|
||||
@@ -427,32 +429,13 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
lightingData.FinalizeLighting(surface.transmission.tint);
|
||||
|
||||
|
||||
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
|
||||
{
|
||||
alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles.
|
||||
}
|
||||
const float alpha = 1.0;
|
||||
|
||||
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
|
||||
|
||||
// ------- Opacity -------
|
||||
|
||||
if (o_opacity_mode == OpacityMode::Blended)
|
||||
{
|
||||
// [GFX_TODO ATOM-13187] PbrLighting shouldn't be writing directly to render targets. It's confusing when
|
||||
// specular is being added to diffuse just because we're calling render target 0 "diffuse".
|
||||
|
||||
// For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular
|
||||
// to be added on top of the diffuse, but then the diffuse must be pre-multiplied.
|
||||
// It's done this way because surface transparency doesn't really change specular response (eg, glass).
|
||||
lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse
|
||||
lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pack factor and quality, drawback: because of precision limit of float16 cannot represent exact 1, maximum representable value is 0.9961
|
||||
uint factorAndQuality = dot(round(float2(saturate(surfaceScatteringFactor), MaterialSrg::m_subsurfaceScatteringQuality) * 255), float2(256, 1));
|
||||
lightingOutput.m_diffuseColor.w = factorAndQuality * (o_enableSubsurfaceScattering ? 1.0 : -1.0);
|
||||
}
|
||||
// Pack factor and quality, drawback: because of precision limit of float16 cannot represent exact 1, maximum representable value is 0.9961
|
||||
uint factorAndQuality = dot(round(float2(saturate(surfaceScatteringFactor), MaterialSrg::m_subsurfaceScatteringQuality) * 255), float2(256, 1));
|
||||
lightingOutput.m_diffuseColor.w = factorAndQuality * (o_enableSubsurfaceScattering ? 1.0 : -1.0);
|
||||
|
||||
|
||||
return lightingOutput;
|
||||
|
||||
+33
-19
@@ -20,10 +20,12 @@ function GetMaterialPropertyDependencies()
|
||||
"layer1_parallax.enable",
|
||||
"layer2_parallax.enable",
|
||||
"layer3_parallax.enable",
|
||||
"parallax.factor",
|
||||
"layer1_parallax.factor",
|
||||
"layer2_parallax.factor",
|
||||
"layer3_parallax.factor"
|
||||
"layer3_parallax.factor",
|
||||
"layer1_parallax.offset",
|
||||
"layer2_parallax.offset",
|
||||
"layer3_parallax.offset"
|
||||
}
|
||||
end
|
||||
|
||||
@@ -31,6 +33,23 @@ function GetShaderOptionDependencies()
|
||||
return {"o_parallax_feature_enabled"}
|
||||
end
|
||||
|
||||
function MergeRange(heightMinMax, offset, factor)
|
||||
top = offset
|
||||
bottom = offset - factor
|
||||
|
||||
if(heightMinMax[1] == nil) then
|
||||
heightMinMax[1] = top
|
||||
else
|
||||
heightMinMax[1] = math.max(heightMinMax[1], top)
|
||||
end
|
||||
|
||||
if(heightMinMax[0] == nil) then
|
||||
heightMinMax[0] = bottom
|
||||
else
|
||||
heightMinMax[0] = math.min(heightMinMax[0], bottom)
|
||||
end
|
||||
end
|
||||
|
||||
function Process(context)
|
||||
local enableParallax = context:GetMaterialPropertyValue_bool("parallax.enable")
|
||||
local enable1 = context:GetMaterialPropertyValue_bool("layer1_parallax.enable")
|
||||
@@ -39,30 +58,25 @@ function Process(context)
|
||||
enableParallax = enableParallax and (enable1 or enable2 or enable3)
|
||||
context:SetShaderOptionValue_bool("o_parallax_feature_enabled", enableParallax)
|
||||
|
||||
-- Smaller values for the main parallax factor used in GetParallaxOffset() give better quality.
|
||||
-- So increase the per-layer parallax factors by normalizing them, and reduce the main factor accordingly.
|
||||
if(enableParallax) then
|
||||
local factorLayer1 = context:GetMaterialPropertyValue_float("layer1_parallax.factor")
|
||||
local factorLayer2 = context:GetMaterialPropertyValue_float("layer2_parallax.factor")
|
||||
local factorLayer3 = context:GetMaterialPropertyValue_float("layer3_parallax.factor")
|
||||
local mainFactor = context:GetMaterialPropertyValue_float("parallax.factor")
|
||||
|
||||
maxLayerFactor = 0.0
|
||||
if(enable1) then maxLayerFactor = math.max(maxLayerFactor, factorLayer1) end
|
||||
if(enable2) then maxLayerFactor = math.max(maxLayerFactor, factorLayer2) end
|
||||
if(enable3) then maxLayerFactor = math.max(maxLayerFactor, factorLayer3) end
|
||||
local offsetLayer1 = context:GetMaterialPropertyValue_float("layer1_parallax.offset")
|
||||
local offsetLayer2 = context:GetMaterialPropertyValue_float("layer2_parallax.offset")
|
||||
local offsetLayer3 = context:GetMaterialPropertyValue_float("layer3_parallax.offset")
|
||||
|
||||
if(maxLayerFactor < 0.0001) then
|
||||
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(heightMinMax[1] - heightMinMax[0] < 0.0001) then
|
||||
context:SetShaderOptionValue_bool("o_parallax_feature_enabled", false)
|
||||
else
|
||||
factorLayer1 = factorLayer1 / maxLayerFactor
|
||||
factorLayer2 = factorLayer2 / maxLayerFactor
|
||||
factorLayer3 = factorLayer3 / maxLayerFactor
|
||||
mainFactor = mainFactor * maxLayerFactor;
|
||||
context:SetShaderConstant_float("m_layer1_m_depthFactor", factorLayer1)
|
||||
context:SetShaderConstant_float("m_layer2_m_depthFactor", factorLayer2)
|
||||
context:SetShaderConstant_float("m_layer3_m_depthFactor", factorLayer3)
|
||||
context:SetShaderConstant_float("m_parallaxMainDepthFactor", mainFactor)
|
||||
context:SetShaderConstant_float("m_displacementMin", heightMinMax[0])
|
||||
context:SetShaderConstant_float("m_displacementMax", heightMinMax[1])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -76,8 +90,8 @@ function ProcessEditor(context)
|
||||
end
|
||||
|
||||
context:SetMaterialPropertyVisibility("parallax.parallaxUv", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.factor", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.algorithm", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.quality", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.pdo", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.showClipping", visibility)
|
||||
end
|
||||
|
||||
+2
-1
@@ -42,7 +42,8 @@ function ProcessEditor(context)
|
||||
if(not enable or textureMap == nil) then
|
||||
visibility = MaterialPropertyVisibility_Hidden
|
||||
end
|
||||
|
||||
|
||||
context:SetMaterialPropertyVisibility("parallax.factor", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.offset", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.invert", visibility)
|
||||
end
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
--------------------------------------------------------------------------------------
|
||||
--
|
||||
-- All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
-- its licensors.
|
||||
--
|
||||
-- For complete copyright and license terms please see the LICENSE at the root of this
|
||||
-- distribution (the "License"). All use of this software is governed by the License,
|
||||
-- or, if provided, by the license below or the license accompanying this file. Do not
|
||||
-- remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
--
|
||||
--
|
||||
----------------------------------------------------------------------------------------------------
|
||||
|
||||
function GetMaterialPropertyDependencies()
|
||||
return {"parallax.enable", "parallax.pdo"}
|
||||
end
|
||||
|
||||
function Process(context)
|
||||
local parallaxEnabled = context:GetMaterialPropertyValue_bool("parallax.enable")
|
||||
local parallaxPdoEnabled = context:GetMaterialPropertyValue_bool("parallax.pdo")
|
||||
|
||||
local depthPass = context:GetShaderByTag("DepthPass")
|
||||
local shadowMap = context:GetShaderByTag("Shadowmap")
|
||||
local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS")
|
||||
local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS")
|
||||
local shadowMapWitPS = context:GetShaderByTag("Shadowmap_WithPS")
|
||||
local forwardPass = context:GetShaderByTag("ForwardPass")
|
||||
|
||||
local shadingAffectsDepth = parallaxEnabled and parallaxPdoEnabled;
|
||||
|
||||
depthPass:SetEnabled(not shadingAffectsDepth)
|
||||
shadowMap:SetEnabled(not shadingAffectsDepth)
|
||||
forwardPassEDS:SetEnabled(not shadingAffectsDepth)
|
||||
|
||||
depthPassWithPS:SetEnabled(shadingAffectsDepth)
|
||||
shadowMapWitPS:SetEnabled(shadingAffectsDepth)
|
||||
forwardPass:SetEnabled(shadingAffectsDepth)
|
||||
end
|
||||
+7
-16
@@ -12,12 +12,10 @@
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include <viewsrg.srgi>
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/ParallaxMapping.azsli>
|
||||
#include <Atom/Features/MatrixUtility.azsli>
|
||||
|
||||
#include "MaterialInputs/AlphaInput.azsli"
|
||||
#include "MaterialInputs/ParallaxInput.azsli"
|
||||
|
||||
#include "MaterialInputs/ParallaxInput.azsli"
|
||||
@@ -71,7 +69,7 @@ VertexOutput MainVS(VertexInput IN)
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
OUT.m_worldPosition = worldPosition.xyz;
|
||||
|
||||
@@ -100,18 +98,9 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
{
|
||||
PSDepthOutput OUT;
|
||||
|
||||
// Alpha
|
||||
float2 layer1_baseColorUV = IN.m_uv[MaterialSrg::m_layer1_m_baseColorMapUvIndex];
|
||||
float2 layer2_baseColorUV = IN.m_uv[MaterialSrg::m_layer2_m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
// [GFX TODO][ATOM-14589] Figure out how to deal with opacity, instead of just hard-coding to layer1
|
||||
float alpha = SampleAlpha(MaterialSrg::m_layer1_m_baseColorMap, MaterialSrg::m_opacityMap, layer1_baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
if(o_debugDrawMode == DebugDrawMode::None && o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
@@ -124,13 +113,15 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_parallaxMainDepthFactor,
|
||||
|
||||
float parallaxOverallOffset = MaterialSrg::m_displacementMax;
|
||||
float parallaxOverallFactor = MaterialSrg::m_displacementMax - MaterialSrg::m_displacementMin;
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], parallaxOverallFactor, parallaxOverallOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth);
|
||||
|
||||
OUT.m_depth = depth;
|
||||
}
|
||||
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -910,8 +910,8 @@
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the depth values",
|
||||
"displayName": "Heightmap Scale",
|
||||
"description": "The total height of the heightmap in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"min": 0.0,
|
||||
@@ -921,6 +921,19 @@
|
||||
"id": "m_depthFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "offset",
|
||||
"displayName": "Offset",
|
||||
"description": "Adjusts the overall displacement amount in local model units.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.0,
|
||||
"softMin": -0.1,
|
||||
"softMax": 0.1,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_depthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invert",
|
||||
"displayName": "Invert",
|
||||
@@ -966,6 +979,17 @@
|
||||
"type": "ShaderOption",
|
||||
"id": "o_parallax_enablePixelDepthOffset"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "showClipping",
|
||||
"displayName": "Show Clipping",
|
||||
"description": "Highlight areas where the heightmap is clipped by the mesh surface.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_parallax_highlightClipping"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subsurfaceScattering": [
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
#include <viewsrg.srgi>
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
|
||||
#include "MaterialInputs/BaseColorInput.azsli"
|
||||
#include "MaterialInputs/RoughnessInput.azsli"
|
||||
@@ -93,8 +95,23 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
}
|
||||
|
||||
// Callback function for ParallaxMapping.azsli
|
||||
float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
return SampleDepthOrHeightMap(MaterialSrg::m_depthInverted, MaterialSrg::m_depthMap, MaterialSrg::m_sampler, uv, uv_ddx, uv_ddy);
|
||||
}
|
||||
|
||||
|
||||
COMMON_OPTIONS_PARALLAX()
|
||||
|
||||
bool ShouldHandleParallax()
|
||||
{
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scattering is enabled.
|
||||
return !o_enableSubsurfaceScattering && o_parallax_feature_enabled && o_useDepthMap;
|
||||
}
|
||||
|
||||
bool ShouldHandleParallaxInDepthShaders()
|
||||
{
|
||||
// The depth pass shaders need to calculate parallax when the result could affect the depth buffer, or when
|
||||
// parallax could affect texel clipping.
|
||||
return ShouldHandleParallax() && (o_parallax_enablePixelDepthOffset || o_opacity_mode == OpacityMode::Cutout);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include "./StandardPBR_Common.azsli"
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/ParallaxMapping.azsli>
|
||||
@@ -56,7 +55,7 @@ VSDepthOutput MainVS(VSInput IN)
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
OUT.m_worldPosition = worldPosition.xyz;
|
||||
|
||||
@@ -75,6 +74,23 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
{
|
||||
PSDepthOutput OUT;
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor, MaterialSrg::m_depthOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, OUT.m_depth);
|
||||
}
|
||||
|
||||
// Alpha
|
||||
float2 baseColorUV = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
@@ -82,39 +98,5 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
{
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
float3 tangent = tangents[MaterialSrg::m_parallaxUvIndex];
|
||||
float3 bitangent = bitangents[MaterialSrg::m_parallaxUvIndex];
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
float3 tangentOffset = GetParallaxOffset( MaterialSrg::m_depthFactor,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex],
|
||||
ViewSrg::m_worldPosition.xyz - IN.m_worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrix);
|
||||
|
||||
PixelDepthOffset pdo = CalcPixelDepthOffset(MaterialSrg::m_depthFactor,
|
||||
tangentOffset,
|
||||
IN.m_worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrixInverse,
|
||||
ObjectSrg::GetWorldMatrix(),
|
||||
ViewSrg::m_viewProjectionMatrix);
|
||||
OUT.m_depth = pdo.m_depth;
|
||||
}
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ COMMON_OPTIONS_NORMAL()
|
||||
COMMON_OPTIONS_CLEAR_COAT()
|
||||
COMMON_OPTIONS_OCCLUSION()
|
||||
COMMON_OPTIONS_EMISSIVE()
|
||||
COMMON_OPTIONS_PARALLAX()
|
||||
// Note COMMON_OPTIONS_PARALLAX is in StandardPBR_Common.azsli because it's needed by all StandardPBR shaders.
|
||||
|
||||
// Alpha
|
||||
#include "MaterialInputs/AlphaInput.azsli"
|
||||
@@ -94,7 +94,10 @@ VSOutput StandardPbr_ForwardPassVS(VSInput IN)
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
VertexHelper(IN, OUT, worldPosition, o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset);
|
||||
// Shadow coords will be calculated in the pixel shader in this case
|
||||
bool skipShadowCoords = ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
|
||||
|
||||
VertexHelper(IN, OUT, worldPosition, skipShadowCoords);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -123,15 +126,18 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
// ------- Depth & Parallax -------
|
||||
|
||||
depth = IN.m_position.z;
|
||||
|
||||
bool displacementIsClipped = false;
|
||||
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scatteirng is enabled
|
||||
if(!o_enableSubsurfaceScattering && o_parallax_feature_enabled && o_useDepthMap)
|
||||
if(ShouldHandleParallax())
|
||||
{
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor,
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor, MaterialSrg::m_depthOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth);
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth, displacementIsClipped);
|
||||
|
||||
// Adjust directional light shadow coorinates for parallax correction
|
||||
if(o_parallax_enablePixelDepthOffset)
|
||||
@@ -166,6 +172,11 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float3 sampledColor = GetBaseColorInput(MaterialSrg::m_baseColorMap, MaterialSrg::m_sampler, baseColorUv, MaterialSrg::m_baseColor.rgb, o_baseColor_useTexture);
|
||||
float3 baseColor = BlendBaseColor(sampledColor, MaterialSrg::m_baseColor.rgb, MaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode, o_baseColor_useTexture);
|
||||
|
||||
if(o_parallax_highlightClipping && displacementIsClipped)
|
||||
{
|
||||
ApplyParallaxClippingHighlight(baseColor);
|
||||
}
|
||||
|
||||
// ------- Metallic -------
|
||||
|
||||
float metallic = 0;
|
||||
|
||||
@@ -41,8 +41,10 @@ function ProcessEditor(context)
|
||||
if(not enable or textureMap == nil) then
|
||||
visibility = MaterialPropertyVisibility_Hidden
|
||||
end
|
||||
|
||||
|
||||
context:SetMaterialPropertyVisibility("parallax.factor", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.offset", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.showClipping", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.invert", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.algorithm", visibility)
|
||||
context:SetMaterialPropertyVisibility("parallax.quality", visibility)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include "StandardPBR_Common.azsli"
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/ParallaxMapping.azsli>
|
||||
#include <Atom/Features/MatrixUtility.azsli>
|
||||
@@ -56,7 +55,7 @@ VertexOutput MainVS(VertexInput IN)
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
OUT.m_worldPosition = worldPosition.xyz;
|
||||
|
||||
@@ -76,28 +75,9 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
{
|
||||
PSDepthOutput OUT;
|
||||
|
||||
// Alpha
|
||||
float2 baseColorUV = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
float alpha = SampleAlpha(MaterialSrg::m_baseColorMap, MaterialSrg::m_opacityMap, baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
OUT.m_depth = IN.m_position.z;
|
||||
|
||||
float3 dirToCamera;
|
||||
if(ViewSrg::m_projectionMatrix[0].w)
|
||||
{
|
||||
// orthographic projection (directional light)
|
||||
// No view position, use light direction
|
||||
dirToCamera = ViewSrg::m_viewMatrix[2].xyz;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirToCamera = ViewSrg::m_worldPosition.xyz - IN.m_worldPosition;
|
||||
}
|
||||
|
||||
if(o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset)
|
||||
if(ShouldHandleParallaxInDepthShaders())
|
||||
{
|
||||
static const float ShadowMapDepthBias = 0.000001;
|
||||
|
||||
@@ -106,31 +86,22 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
float3 tangent = tangents[MaterialSrg::m_parallaxUvIndex];
|
||||
float3 bitangent = bitangents[MaterialSrg::m_parallaxUvIndex];
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
float3 tangentOffset = GetParallaxOffset( MaterialSrg::m_depthFactor,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex],
|
||||
dirToCamera,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrix);
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor, MaterialSrg::m_depthOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, OUT.m_depth);
|
||||
|
||||
PixelDepthOffset pdo = CalcPixelDepthOffset(MaterialSrg::m_depthFactor,
|
||||
tangentOffset,
|
||||
IN.m_worldPosition,
|
||||
tangent,
|
||||
bitangent,
|
||||
IN.m_normal,
|
||||
uvMatrixInverse,
|
||||
ObjectSrg::GetWorldMatrix(),
|
||||
ViewSrg::m_viewProjectionMatrix);
|
||||
|
||||
OUT.m_depth = pdo.m_depth + ShadowMapDepthBias;
|
||||
OUT.m_depth += ShadowMapDepthBias;
|
||||
}
|
||||
|
||||
// Alpha
|
||||
float2 baseColorUV = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
|
||||
float2 opacityUV = IN.m_uv[MaterialSrg::m_opacityMapUvIndex];
|
||||
float alpha = SampleAlpha(MaterialSrg::m_baseColorMap, MaterialSrg::m_opacityMap, baseColorUV, opacityUV, MaterialSrg::m_sampler, o_opacity_source);
|
||||
|
||||
CheckClipping(alpha, MaterialSrg::m_opacityFactor);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -18,39 +18,147 @@ option bool o_parallax_enablePixelDepthOffset;
|
||||
|
||||
option enum class ParallaxAlgorithm {Basic, Steep, POM, Relief, Contact} o_parallax_algorithm;
|
||||
option enum class ParallaxQuality {Low, Medium, High, Ultra} o_parallax_quality;
|
||||
|
||||
option bool o_parallax_feature_enabled;
|
||||
option bool o_parallax_highlightClipping;
|
||||
option bool o_parallax_shadow;
|
||||
|
||||
// I tried to make this an enum class, but ran into some DXC bug when compiling to SPIRV.
|
||||
enum DepthResultCode
|
||||
{
|
||||
DepthResultCode_Invalid,
|
||||
DepthResultCode_Normalized, //!< The result is in range [0,1], where 0 is the top of the heightmap and 1 is the bottom of the heightmap.
|
||||
DepthResultCode_Absolute //!< The result is tangent space units (the same as world units if there's no mesh scaling), where 0 is at the mesh surface and positive values are below the surface.
|
||||
};
|
||||
|
||||
//! The return value for the GetDepth() callback function below.
|
||||
struct DepthResult
|
||||
{
|
||||
DepthResultCode m_resultCode;
|
||||
float m_depth;
|
||||
};
|
||||
|
||||
//! Convenience function for making a DepthResult with Code::Normalized
|
||||
DepthResult DepthResultNormalized(float depth)
|
||||
{
|
||||
DepthResult result;
|
||||
result.m_resultCode = DepthResultCode_Normalized;
|
||||
result.m_depth = depth;
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Convenience function for making a DepthResult with Code::Absolute
|
||||
DepthResult DepthResultAbsolute(float depth)
|
||||
{
|
||||
DepthResult result;
|
||||
result.m_resultCode = DepthResultCode_Absolute;
|
||||
result.m_depth = depth;
|
||||
return result;
|
||||
}
|
||||
|
||||
//! The client shader must define this function.
|
||||
//! This allows the client shader to implement special depth map sampling, for example procedurally generating or blending depth maps.
|
||||
//! In simple cases though, the implementation of GetDepth() can simply call SampleDepthOrHeightMap().
|
||||
//! @param uv the UV coordinates to use for sampling
|
||||
//! @param uv_ddx will be set to ddx_fine(uv)
|
||||
//! @param uv_ddy will be set to ddy_fine(uv)
|
||||
float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy);
|
||||
//! @return see struct DepthResult
|
||||
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy);
|
||||
|
||||
//! Convenience function that can be used to implement GetDepth().
|
||||
//! @param isHeightmap indicates whether to sample the map is a height map rather than a depth map.
|
||||
float SampleDepthOrHeightMap(bool isHeightmap, Texture2D map, sampler mapSampler, float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
//! @return see struct DepthResult. In this case it will always contain a Code::Normalized result.
|
||||
DepthResult SampleDepthOrHeightMap(bool isHeightmap, Texture2D map, sampler mapSampler, float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
return abs((isHeightmap * 1.0) - map.SampleGrad(mapSampler, uv, uv_ddx, uv_ddy).r);
|
||||
DepthResult result;
|
||||
result.m_resultCode = DepthResultCode_Normalized;
|
||||
result.m_depth = abs((isHeightmap * 1.0) - map.SampleGrad(mapSampler, uv, uv_ddx, uv_ddy).r);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Calls GetDepth() and then normalizes the result if it isn't normalized already.
|
||||
//! @param startDepth is the high point, which corresponds to a normalized depth value of 0.
|
||||
//! @param stopDepth is the low point, which corresponds to a normalized depth value of 1.
|
||||
//! @param inverseDepthRange is an optimization, and must be set to "1.0 / (stopDepth - startDepth)".
|
||||
//! @param uv the UV coordinates to use for sampling
|
||||
//! @param uv_ddx must be set to ddx_fine(uv)
|
||||
//! @param uv_ddy must be set to ddy_fine(uv)
|
||||
//! @param a depth value in the range [0,1]
|
||||
float GetNormalizedDepth(float startDepth, float stopDepth, float inverseDepthRange, float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
// startDepth can be less than 0, representing a displacement above the mesh surface.
|
||||
// But since we don't currently support any vertex displacement, negative depth values would cause various
|
||||
// problems especially when PDO is enabled, like parallax surfaces clipping through foreground geometry, and parallax
|
||||
// surfaces disappearing at low angles. So we clamp all depth values to a minimum of 0.
|
||||
|
||||
float normalizedDepth = 0.0;
|
||||
|
||||
DepthResult depthResult = GetDepth(uv, uv_ddx, uv_ddy);
|
||||
|
||||
if(stopDepth - startDepth > 0.0001)
|
||||
{
|
||||
if(DepthResultCode_Normalized == depthResult.m_resultCode)
|
||||
{
|
||||
float minNormalizedDepth = -startDepth * inverseDepthRange;
|
||||
normalizedDepth = max(depthResult.m_depth, minNormalizedDepth);
|
||||
}
|
||||
else if(DepthResultCode_Absolute == depthResult.m_resultCode)
|
||||
{
|
||||
float clampedAbsoluteDepth = max(depthResult.m_depth, 0.0);
|
||||
normalizedDepth = (clampedAbsoluteDepth - startDepth) * inverseDepthRange;
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedDepth;
|
||||
}
|
||||
|
||||
float GetNormalizedDepth(float startDepth, float stopDepth, float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
float inverseDepthRange = 1.0 / (stopDepth - startDepth);
|
||||
return GetNormalizedDepth(startDepth, stopDepth, inverseDepthRange, uv, uv_ddx, uv_ddy);
|
||||
}
|
||||
|
||||
void ApplyParallaxClippingHighlight(inout float3 baseColor)
|
||||
{
|
||||
baseColor = lerp(baseColor, float3(1.0, 0.0, 1.0), 0.5);
|
||||
}
|
||||
|
||||
struct ParallaxOffset
|
||||
{
|
||||
float3 m_offsetTS; //!< represents the intersection point relative to the geometry surface, in tangent space.
|
||||
bool m_isClipped; //!< Indicates whether the result is being clipped by the geometry surface, mainly for debug rendering. Only set when o_parallax_highlightClipping is true.
|
||||
};
|
||||
|
||||
// dirToCameraTS should be in tangent space and normalized
|
||||
// From Reat-Time Rendering 3rd edition, p.192
|
||||
float3 BasicParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraTS)
|
||||
ParallaxOffset BasicParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraTS)
|
||||
{
|
||||
// the amount to shift
|
||||
float2 delta = dirToCameraTS.xy * GetDepth(uv, ddx_fine(uv), ddy_fine(uv)) * depthFactor;
|
||||
float2 delta = dirToCameraTS.xy * GetNormalizedDepth(0, depthFactor, uv, ddx_fine(uv), ddy_fine(uv)) * depthFactor;
|
||||
|
||||
float3 offset = float3(0,0,0);
|
||||
offset.xy -= delta;
|
||||
return offset;
|
||||
ParallaxOffset result;
|
||||
|
||||
result.m_offsetTS = float3(0,0,0);
|
||||
result.m_offsetTS.xy -= delta;
|
||||
result.m_isClipped = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// dirToCameraTS and dirToLightTS should be in tangent space and normalized
|
||||
// Adapt from CryEngine shader shadelib.cfi and POM function in https://github.com/a-riccardi/shader-toy
|
||||
// Performs ray intersection against a surface with a heightmap.
|
||||
// Adapted from CryEngine shader shadelib.cfi and POM function in https://github.com/a-riccardi/shader-toy
|
||||
// check https://github.com/UPBGE/blender/issues/1009 for more details.
|
||||
float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraTS, float3 dirToLightTS, int numSteps, inout float parallaxShadowAttenuation)
|
||||
// @param depthFactor - scales the heightmap in tangent space units (which normally ends up being world units).
|
||||
// @param depthOffset - offsets the heighmap up or down in tangent space units (which normally ends up being world units).
|
||||
// @param uv - the UV coordinates on the surface, where the search will begin, used to sample the heightmap.
|
||||
// @param dirToCameraTS - normalized direction to the camera, in tangent space.
|
||||
// @param dirToLightTS - normalized direction to a light source, in tangent space, for self-shadowing (if enabled via o_parallax_shadow).
|
||||
// @param numSteps - the number of steps to take when marching along the ray searching for intersection.
|
||||
// @param parallaxShadowAttenuation - returns a factor for attenuating a light source, for self-shadowing (if enabled via o_parallax_shadow).
|
||||
ParallaxOffset AdvancedParallaxMapping(float depthFactor, float depthOffset, float2 uv, float3 dirToCameraTS, float3 dirToLightTS, int numSteps, inout float parallaxShadowAttenuation)
|
||||
{
|
||||
ParallaxOffset result;
|
||||
result.m_isClipped = false;
|
||||
|
||||
float dirToCameraZInverse = 1.0 / dirToCameraTS.z;
|
||||
float step = 1.0 / numSteps;
|
||||
float currentStep = 0.0;
|
||||
@@ -61,21 +169,38 @@ float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
float2 ddx_uv = ddx_fine(uv);
|
||||
float2 ddy_uv = ddy_fine(uv);
|
||||
|
||||
float currentSample = GetDepth(uv, ddx_uv, ddy_uv);
|
||||
float prevSample;
|
||||
float3 parallaxOffset = float3(0,0,0);
|
||||
float depthSearchStart = -depthOffset;
|
||||
float depthSearchEnd = depthSearchStart + depthFactor;
|
||||
|
||||
float inverseDepthFactor = 1.0 / depthFactor;
|
||||
|
||||
// find the intersect step
|
||||
// This is the relative position at which we begin searching for intersection.
|
||||
// It is adjusted according to the depthOffset, raising or lowering the whole surface by depthOffset units.
|
||||
float3 parallaxOffset = dirToCameraTS.xyz * dirToCameraZInverse * depthOffset;
|
||||
|
||||
// Get an initial heightmap sample to start the intersection search, starting at our initial parallaxOffset position.
|
||||
float currentSample = GetNormalizedDepth(depthSearchStart, depthSearchEnd, inverseDepthFactor, uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
float prevSample;
|
||||
|
||||
// Note that when depthOffset < 0, we could actually narrow the search so that instead of going through the entire [depthSearchStart,depthSearchEnd] range
|
||||
// of the heightmap, we could go through the range [0,depthSearchEnd]. This would give more accurate results and fewer artifacts
|
||||
// in case where the magnitude of depthOffset is significant. But for the sake of simplicity we currently search the whole range in all cases.
|
||||
|
||||
// Do a basic search for the intersect step
|
||||
while(currentSample > currentStep)
|
||||
{
|
||||
currentStep += step;
|
||||
parallaxOffset += delta;
|
||||
|
||||
prevSample = currentSample;
|
||||
currentSample = GetDepth(uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
currentSample = GetNormalizedDepth(depthSearchStart, depthSearchEnd, inverseDepthFactor, uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
}
|
||||
|
||||
// Depending on the algorithm, we refine the result of the above search
|
||||
switch(o_parallax_algorithm)
|
||||
{
|
||||
case ParallaxAlgorithm::Steep:
|
||||
break; // This algorithm just relies on the course intersection test loop above
|
||||
case ParallaxAlgorithm::POM:
|
||||
{
|
||||
if(currentStep > 0.0)
|
||||
@@ -108,7 +233,7 @@ float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
parallaxOffset += reliefDelta * depthSign;
|
||||
currentStep += reliefStep * depthSign;
|
||||
|
||||
currentSample = GetDepth(uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
currentSample = GetNormalizedDepth(depthSearchStart, depthSearchEnd, inverseDepthFactor, uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -136,7 +261,7 @@ float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
parallaxOffset += adjustedDelta;
|
||||
prevSample = currentSample;
|
||||
|
||||
currentSample = GetDepth(uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
currentSample = GetNormalizedDepth(depthSearchStart, depthSearchEnd, inverseDepthFactor, uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -144,6 +269,30 @@ float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Even though we do a bunch of clamping above when calling GetClampedDepth(), there are still cases where the parallax offset
|
||||
// can be noticeably above the surface and still needs to be clamped here. The main case is when depthFactor==0 and depthOffset>1.
|
||||
if(parallaxOffset.z > 0.0)
|
||||
{
|
||||
parallaxOffset = float3(0,0,0);
|
||||
}
|
||||
|
||||
if (o_parallax_highlightClipping)
|
||||
{
|
||||
// The most accurate way to report clipping is to sample the heightmap one last time at the final adjusted UV.
|
||||
// (trying to do it based on parallaxOffset.z values just leads to too many edge cases)
|
||||
|
||||
DepthResult depthResult = GetDepth(uv + parallaxOffset.xy, ddx_uv, ddy_uv);
|
||||
|
||||
if(DepthResultCode_Normalized == depthResult.m_resultCode)
|
||||
{
|
||||
result.m_isClipped = lerp(depthSearchStart, depthSearchEnd, depthResult.m_depth) < 0;
|
||||
}
|
||||
else if(DepthResultCode_Absolute == depthResult.m_resultCode)
|
||||
{
|
||||
result.m_isClipped = depthResult.m_depth < 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
if(o_parallax_shadow && any(dirToLightTS))
|
||||
{
|
||||
@@ -168,7 +317,7 @@ float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
}
|
||||
|
||||
shadowUV += shadowDelta;
|
||||
currentSample = GetDepth(shadowUV, ddx_uv, ddy_uv);
|
||||
currentSample = GetNormalizedDepth(depthSearchStart, depthSearchEnd, inverseDepthFactor, shadowUV, ddx_uv, ddy_uv);
|
||||
currentStep -= step;
|
||||
}
|
||||
|
||||
@@ -181,12 +330,13 @@ float3 AdvancedParallaxMapping(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
parallaxShadowAttenuation = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return parallaxOffset;
|
||||
|
||||
result.m_offsetTS = parallaxOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
// return offset in tangent space
|
||||
float3 CalculateParallaxOffset(float depthFactor, float2 uv, float3 dirToCameraTS, float3 dirToLightTS, inout float parallaxShadowAttenuation)
|
||||
ParallaxOffset CalculateParallaxOffset(float depthFactor, float depthOffset, float2 uv, float3 dirToCameraTS, float3 dirToLightTS, inout float parallaxShadowAttenuation)
|
||||
{
|
||||
if(o_parallax_algorithm == ParallaxAlgorithm::Basic)
|
||||
{
|
||||
@@ -194,27 +344,34 @@ float3 CalculateParallaxOffset(float depthFactor, float2 uv, float3 dirToCameraT
|
||||
}
|
||||
else
|
||||
{
|
||||
float3 parallaxOffset;
|
||||
ParallaxOffset parallaxOffset;
|
||||
switch(o_parallax_quality)
|
||||
{
|
||||
case ParallaxQuality::Low:
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, uv, dirToCameraTS, dirToLightTS, 16, parallaxShadowAttenuation);
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, depthOffset, uv, dirToCameraTS, dirToLightTS, 16, parallaxShadowAttenuation);
|
||||
break;
|
||||
case ParallaxQuality::Medium:
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, uv, dirToCameraTS, dirToLightTS, 32, parallaxShadowAttenuation);
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, depthOffset, uv, dirToCameraTS, dirToLightTS, 32, parallaxShadowAttenuation);
|
||||
break;
|
||||
case ParallaxQuality::High:
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, uv, dirToCameraTS, dirToLightTS, 64, parallaxShadowAttenuation);
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, depthOffset, uv, dirToCameraTS, dirToLightTS, 64, parallaxShadowAttenuation);
|
||||
break;
|
||||
case ParallaxQuality::Ultra:
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, uv, dirToCameraTS, dirToLightTS, 128, parallaxShadowAttenuation);
|
||||
parallaxOffset = AdvancedParallaxMapping(depthFactor, depthOffset, uv, dirToCameraTS, dirToLightTS, 128, parallaxShadowAttenuation);
|
||||
break;
|
||||
}
|
||||
return parallaxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
float3 GetParallaxOffset( float depthFactor,
|
||||
// Performs ray intersection against a surface with a heightmap, to determine an offset amount required for a parallax effect.
|
||||
// @param depthFactor - scales the heightmap in tangent space units (which normally ends up being world units).
|
||||
// @param depthOffset - offsets the heighmap up or down in tangent space units (which normally ends up being world units).
|
||||
// @param uv - the UV coordinates on the surface, where the search will begin, used to sample the heightmap.
|
||||
// @param dirToCameraTS - normalized direction to the camera, in tangent space.
|
||||
// @param dirToLightTS - normalized direction to a light source, in tangent space, for self-shadowing (if enabled via o_parallax_shadow).
|
||||
ParallaxOffset GetParallaxOffset( float depthFactor,
|
||||
float depthOffset,
|
||||
float2 uv,
|
||||
float3 dirToCameraWS,
|
||||
float3 tangentWS,
|
||||
@@ -236,7 +393,7 @@ float3 GetParallaxOffset( float depthFactor,
|
||||
float4 dirToCameraTransformed = mul(uv3DTransform, float4(dirToCameraTS, 0.0));
|
||||
|
||||
float dummy = 1;
|
||||
return CalculateParallaxOffset(depthFactor, uv, normalize(dirToCameraTransformed.xyz), float3(0,0,0), dummy);
|
||||
return CalculateParallaxOffset(depthFactor, depthOffset, uv, normalize(dirToCameraTransformed.xyz), float3(0,0,0), dummy);
|
||||
}
|
||||
|
||||
struct PixelDepthOffset
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"description": "",
|
||||
"materialType": "Materials/Types/StandardPBR.materialtype",
|
||||
"parentMaterial": "",
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"baseColor": {
|
||||
"textureMap": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_bc.png"
|
||||
},
|
||||
"opacity": {
|
||||
"alphaSource": "Split",
|
||||
"mode": "Cutout",
|
||||
"textureMap": "TestData/Textures/checker8x8_512.png"
|
||||
},
|
||||
"parallax": {
|
||||
"algorithm": "POM",
|
||||
"enable": true,
|
||||
"factor": 0.10000000149011612,
|
||||
"quality": "High",
|
||||
"textureMap": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_disp.png"
|
||||
},
|
||||
"uv": {
|
||||
"scale": 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,12 +121,12 @@ void GetSurfaceShape(float2 uv, out float depth, out float3 normal)
|
||||
}
|
||||
|
||||
// Callback function for ParallaxMapping.azsli
|
||||
float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
float depth;
|
||||
float3 normal;
|
||||
GetSurfaceShape(uv, depth, normal);
|
||||
return depth;
|
||||
return DepthResultNormalized(depth);
|
||||
}
|
||||
|
||||
ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN)
|
||||
@@ -136,15 +136,18 @@ ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN)
|
||||
0,1,0,
|
||||
0,0,1 };
|
||||
|
||||
float3 tangentOffset = GetParallaxOffset( AutoBrickSrg::m_lineDepth,
|
||||
IN.m_uv,
|
||||
ViewSrg::m_worldPosition.xyz - IN.m_worldPosition,
|
||||
IN.m_tangent,
|
||||
IN.m_bitangent,
|
||||
IN.m_normal,
|
||||
identityUvMatrix);
|
||||
float depthOffset = 0.0;
|
||||
|
||||
ParallaxOffset tangentOffset = GetParallaxOffset( AutoBrickSrg::m_lineDepth,
|
||||
depthOffset,
|
||||
IN.m_uv,
|
||||
ViewSrg::m_worldPosition.xyz - IN.m_worldPosition,
|
||||
IN.m_tangent,
|
||||
IN.m_bitangent,
|
||||
IN.m_normal,
|
||||
identityUvMatrix);
|
||||
|
||||
IN.m_uv += tangentOffset.xy;
|
||||
IN.m_uv += tangentOffset.m_offsetTS.xy;
|
||||
|
||||
float3 baseColor = float3(1,1,1);
|
||||
const float noise = AutoBrickSrg::m_noise.Sample(AutoBrickSrg::m_sampler, IN.m_uv).r;
|
||||
|
||||
@@ -101,6 +101,11 @@ AZ::RPI::WindowContextSharedPtr AZ::FFont::GetDefaultWindowContext() const
|
||||
|
||||
bool AZ::FFont::InitFont(AZ::RPI::Scene* renderScene)
|
||||
{
|
||||
if (!renderScene)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto initializationState = InitializationState::Uninitialized;
|
||||
// Do an atomic transition to Initializing if we're in the Uninitialized state.
|
||||
// Otherwise, check the current state.
|
||||
@@ -111,11 +116,6 @@ bool AZ::FFont::InitFont(AZ::RPI::Scene* renderScene)
|
||||
return initializationState == InitializationState::Initialized;
|
||||
}
|
||||
|
||||
if (!renderScene)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create and initialize DynamicDrawContext for font draw
|
||||
AZ::RPI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(renderScene);
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ namespace LandscapeCanvasEditor
|
||||
|
||||
static const QStringList preferredCategories = {
|
||||
"Vegetation",
|
||||
"Rendering"
|
||||
"Atom"
|
||||
};
|
||||
|
||||
// There are a couple of cases where we prefer certain categories of Components
|
||||
|
||||
Vendored
+10
-8
@@ -549,15 +549,17 @@ finally {
|
||||
message:"${currentBuild.currentResult}:${BUILD_URL}:${env.RECREATE_VOLUME}:${env.CLEAN_OUTPUT_DIRECTORY}:${env.CLEAN_ASSETS}"
|
||||
)
|
||||
}
|
||||
step([
|
||||
$class: 'Mailer',
|
||||
notifyEveryUnstableBuild: true,
|
||||
sendToIndividuals: true,
|
||||
recipients: emailextrecipients([
|
||||
[$class: 'CulpritsRecipientProvider'],
|
||||
[$class: 'RequesterRecipientProvider']
|
||||
node('controller') {
|
||||
emailRecipients = [[$class: 'RequesterRecipientProvider']]
|
||||
if (env.WATCHED_BRANCHES.tokenize(',').contains(branchName)) {
|
||||
emailRecipients.add([$class: 'CulpritsRecipientProvider'])
|
||||
}
|
||||
step([
|
||||
$class: 'Mailer',
|
||||
notifyEveryUnstableBuild: true,
|
||||
recipients: emailextrecipients(emailRecipients)
|
||||
])
|
||||
])
|
||||
}
|
||||
} catch(Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user