From 837d4fde3ef0865a73b9cbd35a0ca346719c2a26 Mon Sep 17 00:00:00 2001 From: Tommy Walton Date: Thu, 3 Feb 2022 11:00:52 -0800 Subject: [PATCH] Create a debug material type for displaying per-vertex data (#7220) * Create a debug material type for displaying per-vertex data Signed-off-by: Tommy Walton * PR feedback. Added color display mode, multiple uv-set support, split tangent/bitangent options into two separate enums, and added a functor for showing only the applicable properties in the UI depending on which vertex stream and uv set are selected. Signed-off-by: Tommy Walton --- .../Materials/Special/DebugVertexStreams.azsl | 154 ++++++++++++++++++ .../Special/DebugVertexStreams.material | 4 + .../Special/DebugVertexStreams.materialtype | 94 +++++++++++ .../Special/DebugVertexStreams.shader | 24 +++ .../DebugVertexStreams_IncompatibleEnums.lua | 71 ++++++++ 5 files changed, 347 insertions(+) create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl new file mode 100644 index 0000000000..b4ad624266 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl @@ -0,0 +1,154 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#define UvSetCount 2 +#include +#include +#include + +// These enums need to be kept in sync with the enum values in DebugVertexStreams_IncompatibleEnums.lua +option enum class DebugVertexStream { Normals, Tangents, Bitangents, Uvs, TangentW } o_debugVertexStream = DebugVertexStream::Normals; +option enum class TangentOptions { UseVertexData, UseSurfaceGradient} o_tangentOptions = TangentOptions::UseVertexData; +option enum class BitangentOptions { UseVertexData, UseSurfaceGradient, ReconstructBitangent} o_bitangentOptions = BitangentOptions::UseVertexData; +option enum class ColorDisplayMode {ColorSpace, UnitSpace} o_colorDisplayMode = ColorDisplayMode::ColorSpace; + +ShaderResourceGroup MaterialSrg : SRG_PerMaterial +{ + uint m_uvIndex; +} + +struct VSInput +{ + // Base fields (required by the template azsli file)... + float3 m_position : POSITION; + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; +}; + +struct VSOutput +{ + // Base fields (required by the template azsli file)... + // "centroid" is needed for SV_Depth to compile + precise linear centroid float4 m_position : SV_Position; + float3 m_normal: NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv[UvSetCount] : UV1; +}; + +VSOutput MainVS(VSInput IN) +{ + VSOutput OUT; + OUT.m_worldPosition = mul(ObjectSrg::GetWorldMatrix(), float4(IN.m_position, 1.0)).xyz; + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPosition, 1.0)); + + // Only UV0 is supported + OUT.m_uv[0] = IN.m_uv0; + OUT.m_uv[1] = IN.m_uv1; + + float4x4 objectToWorld = ObjectSrg::GetWorldMatrix(); + float3x3 objectToWorldIT = ObjectSrg::GetWorldMatrixInverseTranspose(); + + ConstructTBN(IN.m_normal, IN.m_tangent, IN.m_bitangent, objectToWorld, objectToWorldIT, OUT.m_normal, OUT.m_tangent.xyz, OUT.m_bitangent); + + OUT.m_tangent.w = IN.m_tangent.w; + return OUT; +} + +struct PixelOutput +{ + float4 m_color : SV_Target0; +}; + + +float3 OffsetColor(float3 color) +{ + if(o_colorDisplayMode == ColorDisplayMode::ColorSpace) + { + // Represent a vector in the (-1, -1, -1) to (1, 1, 1) range as a color in the (0, 0, 0) to (1, 1, 1) range + // Color key + // + x-axis: Light Coral + // - x-axis: Teal + // + y-axis: Bright Green + // - y-axis: Dark Magenta + // + z-axis: Medium Slate Blue + // - z-axis: Olive + return normalize(color) * 0.5 + 0.5; + } + else + { + // Use the normalized color, with any negative values represented as black + // + x-axis: Red + // - x-axis: Black + // + y-axis: Green + // - y-axis: Black + // + z-axis: Blue + // - z-axis: Black + return normalize(color); + } +} + +PixelOutput MainPS(VSOutput IN) +{ + PixelOutput OUT; + + float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz }; + float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz }; + + if(o_bitangentOptions == BitangentOptions::ReconstructBitangent && MaterialSrg::m_uvIndex == 0) + { + bitangents[MaterialSrg::m_uvIndex] = cross(IN.m_normal.xyz, IN.m_tangent.xyz) * sign(IN.m_tangent.w); + } + else if((o_debugVertexStream == DebugVertexStream::Tangents && o_tangentOptions == TangentOptions::UseSurfaceGradient) + || (o_debugVertexStream == DebugVertexStream::Bitangents && o_bitangentOptions == BitangentOptions::UseSurfaceGradient) + || MaterialSrg::m_uvIndex > 0) + { + const bool isBackface = false; + SurfaceGradientNormalMapping_Init(IN.m_normal, IN.m_worldPosition, isBackface); + SurfaceGradientNormalMapping_GenerateTB(IN.m_uv[MaterialSrg::m_uvIndex], tangents[MaterialSrg::m_uvIndex], bitangents[MaterialSrg::m_uvIndex]); + } + + + float3 outColor = float3(1.0, 1.0, 1.0); + switch(o_debugVertexStream) + { + case DebugVertexStream::Normals: + outColor = OffsetColor(IN.m_normal); + break; + case DebugVertexStream::Tangents: + outColor = OffsetColor(tangents[MaterialSrg::m_uvIndex]); + break; + case DebugVertexStream::Bitangents: + outColor = OffsetColor(bitangents[MaterialSrg::m_uvIndex]); + break; + case DebugVertexStream::Uvs: + // Assume a tiled uv visualization, where anything greater than 1 wraps back around to 0 + outColor = float3(frac(IN.m_uv[MaterialSrg::m_uvIndex].x), frac(IN.m_uv[MaterialSrg::m_uvIndex].y), 0.0f); + break; + case DebugVertexStream::TangentW: + float red = IN.m_tangent.w >= 0.0f ? 1.0f : 0.0f; + float green = IN.m_tangent.w <= 0.0f ? 1.0f : 0.0f; + float blue = IN.m_tangent.w == 0.0f ? 1.0f : 0.0f; + outColor = float3(red, green, blue); + break; + } + + OUT.m_color.rgb = outColor; + OUT.m_color.a = 1.0; + + return OUT; +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material new file mode 100644 index 0000000000..34171c4457 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material @@ -0,0 +1,4 @@ +{ + "materialType": "Materials/Special/DebugVertexStreams.materialtype", + "materialTypeVersion": 1 +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype new file mode 100644 index 0000000000..1377cbca8b --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype @@ -0,0 +1,94 @@ +{ + "description": "A simple default base material for Atom testing.", + "version": 1, + "propertyLayout": { + "groups": [ + { + "name": "general", + "displayName": "General Settings", + "description": "General settings." + } + ], + "properties": { + "general": [ + { + "name": "debugVertexStream", + "displayName": "Display Vertex Stream", + "description": "Display vertex stream interpolated over the triangle.", + "type": "Enum", + "defaultValue": "Normals", + "enumValues": [ "Normals", "Tangents", "Bitangents", "Uvs", "TangentW" ], + "connection": { + "type": "ShaderOption", + "name": "o_debugVertexStream" + } + }, + { + "name": "tangentOptions", + "displayName": "Tangent Options", + "description": "Use the data from the vertices or use the Surface Gradient technique for calculating tangents.", + "type": "Enum", + "defaultValue": "UseVertexData", + "enumValues": [ "UseVertexData", "UseSurfaceGradient"], + "connection": { + "type": "ShaderOption", + "name": "o_tangentOptions" + } + }, + { + "name": "bitangentOptions", + "displayName": "Bitangent Options", + "description": "Use the data from the vertices, use the Surface Gradient technique for calculating bitangents, or use the cross product to reconstruct the bitangents.", + "type": "Enum", + "defaultValue": "UseVertexData", + "enumValues": [ "UseVertexData", "UseSurfaceGradient", "ReconstructBitangent" ], + "connection": { + "type": "ShaderOption", + "name": "o_bitangentOptions" + } + }, + { + "name": "colorDisplayMode", + "displayName": "Display Mode", + "description": "Offset the vector into the 0-1 range (ColorSpace), or display the raw unit vector including negative values (UnitSpace)", + "type": "Enum", + "defaultValue": "ColorSpace", + "enumValues": [ "ColorSpace", "UnitSpace"], + "connection": { + "type": "ShaderOption", + "name": "o_colorDisplayMode" + } + }, + { + "name": "uvIndex", + "displayName": "UV Index", + "description": "UV set to display and use for tangents/bitangents.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_uvIndex" + } + } + ] + } + }, + "shaders": [ + { + "file": "Materials/Special/DebugVertexStreams.shader" + } + ], + "functors": [ + { + "type": "Lua", + "args": { + "file": "DebugVertexStreams_IncompatibleEnums.lua" + } + } + ], + "uvNameMap": { + "UV0": "Tiled", + "UV1": "Unwrapped" + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader new file mode 100644 index 0000000000..c4578971c2 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader @@ -0,0 +1,24 @@ +{ + "Source" : "DebugVertexStreams.azsl", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "DrawList" : "auxgeom", + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua new file mode 100644 index 0000000000..08ccb2217d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua @@ -0,0 +1,71 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + + +DebugVertexStream_Normals = 0 +DebugVertexStream_Tangents = 1 +DebugVertexStream_Bitangents = 2 +DebugVertexStream_Uvs = 3 +DebugVertexStream_TangentW = 4 + +function GetMaterialPropertyDependencies() + return { "general.debugVertexStream", "general.uvIndex"} +end + +function ProcessEditor(context) + local vertexStream = context:GetMaterialPropertyValue_enum("general.debugVertexStream"); + + -- Depending on which vertex stream is being visualized, only certain settings are applicable + if(vertexStream == DebugVertexStream_Normals) then + -- Normals can be viewed as colors using either method + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Enabled) + + -- Uv set and tangent/bitangent options do not impact normals + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_Tangents) then + -- Tangents can be viewed using either color display mode, and are affected by tangent options and uv index + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Enabled) + + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_Bitangents) then + -- Bitangents can be viewed using either color display mode, and are affected by tangent options and uv index + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Enabled) + + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_Uvs) then + -- Uvs are only impacted by uv index + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Enabled) + + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_TangentW) then + -- Tangent.w can only use per-vertex data, and only for the first uv set, and is only displayed one way, + -- so it is not impacted by any settings + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Hidden) + end + + -- For the second uv set, only the surface gradient technique is supported for generating tangents and bitangents + local uvSet = context:GetMaterialPropertyValue_enum("general.uvIndex"); + if(uvSet > 0) then + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + end +end