diff --git a/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Editor/Unity.GraphicTests.Performance.HDRP.Editor.asmdef b/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Editor/Unity.GraphicTests.Performance.HDRP.Editor.asmdef index 820afce0043..0bb43e8b6b6 100644 --- a/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Editor/Unity.GraphicTests.Performance.HDRP.Editor.asmdef +++ b/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Editor/Unity.GraphicTests.Performance.HDRP.Editor.asmdef @@ -1,13 +1,14 @@ { "name": "Unity.GraphicTests.Performance.HDRP.Editor", + "rootNamespace": "", "references": [ - "GUID:91836b14885b8a34196f4aa8303d7793", - "GUID:457756d89b35d2941b3e7b37b4ece6f1", - "GUID:df380645f10b7bc4b97d4f5eb6303d95", - "GUID:295068ed467c2ce4a9cda3833065f650", - "GUID:27619889b8ba8c24980f49ee34dbb44a", - "GUID:cbbcbe5a7206638449ebcb9382eeb3a8", - "GUID:78bd2ddd6e276394a9615c203e574844" + "Unity.PerformanceTesting", + "Unity.RenderPipelines.HighDefinition.Runtime", + "Unity.RenderPipelines.Core.Runtime", + "Unity.GraphicTests.Performance.Runtime", + "UnityEngine.TestRunner", + "Unity.GraphicTests.Performance.Editor", + "Unity.RenderPipelines.HighDefinition.Editor" ], "includePlatforms": [ "Editor" diff --git a/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Runtime/Unity.GraphicTests.Performance.HDRP.Runtime.asmdef b/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Runtime/Unity.GraphicTests.Performance.HDRP.Runtime.asmdef index f7b8e309f0a..6eba98a33f9 100644 --- a/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Runtime/Unity.GraphicTests.Performance.HDRP.Runtime.asmdef +++ b/TestProjects/HDRP_PerformanceTests/Assets/PerformanceTests/Runtime/Unity.GraphicTests.Performance.HDRP.Runtime.asmdef @@ -1,13 +1,14 @@ { "name": "Unity.GraphicTests.Performance.HDRP.Runtime", + "rootNamespace": "", "references": [ - "GUID:91836b14885b8a34196f4aa8303d7793", + "Unity.PerformanceTesting", "GUID:c081bc530f560634bb5c21d4b323a7f1", - "GUID:27619889b8ba8c24980f49ee34dbb44a", - "GUID:0acc523941302664db1f4e527237feb3", - "GUID:df380645f10b7bc4b97d4f5eb6303d95", - "GUID:457756d89b35d2941b3e7b37b4ece6f1", - "GUID:295068ed467c2ce4a9cda3833065f650" + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "Unity.RenderPipelines.Core.Runtime", + "Unity.RenderPipelines.HighDefinition.Runtime", + "Unity.GraphicTests.Performance.Runtime" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/TestProjects/HDRP_PerformanceTests/ProjectSettings/EditorSettings.asset b/TestProjects/HDRP_PerformanceTests/ProjectSettings/EditorSettings.asset index e0fd18aa585..f6c454911fe 100644 --- a/TestProjects/HDRP_PerformanceTests/ProjectSettings/EditorSettings.asset +++ b/TestProjects/HDRP_PerformanceTests/ProjectSettings/EditorSettings.asset @@ -19,13 +19,17 @@ EditorSettings: m_ProjectGenerationRootNamespace: m_EnableTextureStreamingInEditMode: 1 m_EnableTextureStreamingInPlayMode: 1 + m_EnableRoslynAnalyzers: 0 m_AsyncShaderCompilation: 0 m_CachingShaderPreprocessor: 0 m_EnterPlayModeOptionsEnabled: 1 m_EnterPlayModeOptions: 3 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 m_UseLegacyProbeSampleCount: 1 m_SerializeInlineMappingsOnOneLine: 0 - m_DisableCookiesInLightmapper: 1 + m_DisableCookiesInLightmapper: 0 m_AssetPipelineMode: 1 m_CacheServerMode: 0 m_CacheServerEndpoint: diff --git a/TestProjects/HDRP_PerformanceTests/ProjectSettings/VersionControlSettings.asset b/TestProjects/HDRP_PerformanceTests/ProjectSettings/VersionControlSettings.asset index 322ab770338..dca288142fc 100644 Binary files a/TestProjects/HDRP_PerformanceTests/ProjectSettings/VersionControlSettings.asset and b/TestProjects/HDRP_PerformanceTests/ProjectSettings/VersionControlSettings.asset differ diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1451_AxF_SVBRDF.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1451_AxF_SVBRDF.png index 88a60523d17..ff06ddbabcf 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1451_AxF_SVBRDF.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1451_AxF_SVBRDF.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85c86928826be465c0f14d45a60544c42c0aba791a2ded36d550cadf02cec70e -size 179315 +oid sha256:6c6581b8e33ab626b9808797111d008ac1600511ed76e9ca461b6ee396bb2e69 +size 158548 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1451_AxF_SVBRDF.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1451_AxF_SVBRDF.png index 4f803762ef3..ff06ddbabcf 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1451_AxF_SVBRDF.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1451_AxF_SVBRDF.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:838374849052e359a1a6c82358b09d6cb4aef9e4c3a4ca18c4fd557c4eb76e96 -size 179345 +oid sha256:6c6581b8e33ab626b9808797111d008ac1600511ed76e9ca461b6ee396bb2e69 +size 158548 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1451_AxF_SVBRDF.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1451_AxF_SVBRDF.png index 135943d7d17..2aa608243c4 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1451_AxF_SVBRDF.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1451_AxF_SVBRDF.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6356dfbde86322518395e93d3736d81290495d8d58204229daab30c2bf53f017 -size 176835 +oid sha256:ecef3f2e6051f448e65294d4f41a2865747b011add065ea252cba869654ed80e +size 175929 diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index f2976683c90..6e5014a17a9 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -147,6 +147,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added CPU and GPU timings for ray tracing effects. - Added support to combine RTSSS and RTGI (1248733). - Added IES Profile support for Point, Spot and Rectangular-Area lights +- Added support for multiple mapping modes in AxF. ### Fixed - Fix when rescale probe all direction below zero (1219246) @@ -675,6 +676,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fixing the internsity being applied to RTAO too early leading to unexpected results (1254626). - Fix issue that caused sky to incorrectly render when using a custom projection matrix. - Fixed null reference exception when using depth pre/post pass in shadergraph with alpha clip in the material. +- Appropriately constraint blend distance of reflection probe while editing with the inspector (case 1248931) +- Fixed AxF handling of roughness for Blinn-Phong type materials +- Fixed AxF UI errors when surface type is switched to transparent +- Fixed a serialization issue, preventing quality level parameters to undo/redo and update scene view on change. ### Changed - Improve MIP selection for decals on Transparents diff --git a/com.unity.render-pipelines.high-definition/Documentation~/AxF-Shader.md b/com.unity.render-pipelines.high-definition/Documentation~/AxF-Shader.md index 116b81ce63b..795ed6788ab 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/AxF-Shader.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/AxF-Shader.md @@ -58,7 +58,8 @@ Note: The AxF Importer imports every Texture as half float, linear, sRGB gamut ( | **Property** | **Description** | | --------------------- | ------------------------------------------------------------ | -| **Main Tiling & Offset** | Sets the tiling rate (xy) and offsets (zw) for every Texture in the **Surface Inputs** section. HDRP uses these values to tile the Textures along the xy-axes of the Material’s surface, in the object's tangent space. Each texture property can also specify additional tiling and offset values that are applied on top of these main values (Texture property-specific tiling rates are multiplied and offsets are added to the main values set here) | +| **Mapping Mode** | Controls the texture mapping mode of the material for all textures.
• **UV0..UV3**: Like in Lit, uses a UV set from UV0 to UV3 vertex attributes. Note that UV1 is used for baked lightmaps in Unity, so it isn't recommended to use this set.
• **PlanarXY,YZ,ZX**: Uses planar mapping along the specified plane.
• **Triplanar**: Uses triplanar mapping.
• **Planar Space**: When a planar or triplanar mapping mode is selected, you can select whether the coordinates used are world space or object space using the "planar space" option set to (respectively) "world" or "local". | +| **Main Tiling & Offset** | Sets the tiling rate (xy) and offsets (zw) for every Texture in the **Surface Inputs** section. HDRP uses these values to tile the Textures along the xy-axes of the Material’s surface, in the object's tangent space. Each texture property can also specify additional tiling and offset values that are applied on top of these main values (Texture property-specific tiling rates are multiplied and offsets are added to the main values set here). These additional tiling and offsets appear next to each texture property on the same line. | | **BRDF Type** | Controls the main AxF Material representation.
• **SVBRDF**: For information on the properties Unity makes visible when you select this option, see [BRDF Type - SVBRDF](#SVBRDF).
•**CAR_PAINT**: For information on the properties Unity makes visible when you select this option, see [BRDF Type - CAR_PAINT](#CAR_PAINT). | diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Drawers.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Drawers.cs index 3cba949c92c..81286155f03 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Drawers.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Drawers.cs @@ -233,7 +233,6 @@ public static void DrawCustomSettings(SerializedHDProbe serialized, Editor owner public static void DrawInfluenceSettings(SerializedHDProbe serialized, Editor owner) { - var provider = new TProvider(); InfluenceVolumeUI.Draw(serialized.probeSettings.influence, owner); } diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/Volume/InfluenceVolumeUI.Drawers.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/Volume/InfluenceVolumeUI.Drawers.cs index 9e4443bbc2e..f1f9eb3f08e 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/Volume/InfluenceVolumeUI.Drawers.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/Volume/InfluenceVolumeUI.Drawers.cs @@ -173,18 +173,10 @@ static void Drawer_AdvancedBlendDistance(SerializedInfluenceVolume serialized, b } else { - float scalar = editorSimplifiedModeBlendDistance.floatValue; - if (!(Mathf.Approximately(blendDistancePositive.vector3Value.x, scalar) - && Mathf.Approximately(blendDistancePositive.vector3Value.y, scalar) - && Mathf.Approximately(blendDistancePositive.vector3Value.z, scalar) - && Mathf.Approximately(blendDistanceNegative.vector3Value.x, scalar) - && Mathf.Approximately(blendDistanceNegative.vector3Value.y, scalar) - && Mathf.Approximately(blendDistanceNegative.vector3Value.z, scalar))) - { - blendDistancePositive.vector3Value = blendDistanceNegative.vector3Value = new Vector3(scalar, scalar, scalar); - serialized.Apply(); - SceneView.RepaintAll(); //update gizmo - } + var scalar = Mathf.Min(editorSimplifiedModeBlendDistance.floatValue, Mathf.Min(maxBlendDistance.x, maxBlendDistance.y, maxBlendDistance.z)); + blendDistancePositive.vector3Value = blendDistanceNegative.vector3Value = new Vector3(scalar, scalar, scalar); + serialized.Apply(); + SceneView.RepaintAll(); //update gizmo } if (serialized.editorAdvancedModeEnabled.boolValue) diff --git a/com.unity.render-pipelines.high-definition/Editor/Material/AxF/AxFGUI.cs b/com.unity.render-pipelines.high-definition/Editor/Material/AxF/AxFGUI.cs index 51c0ab3c4a5..6b8320c8a02 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Material/AxF/AxFGUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Material/AxF/AxFGUI.cs @@ -15,6 +15,18 @@ internal enum AxfBrdfType BTF, } + internal enum AxFMappingMode + { + UV0, + UV1, + UV2, + UV3, + PlanarXY, + PlanarYZ, + PlanarZX, + Triplanar, + } + /// /// GUI for HDRP AxF materials /// @@ -50,6 +62,34 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro const string kEnableGeometricSpecularAA = "_EnableGeometricSpecularAA"; const string kSpecularOcclusionMode = "_SpecularOcclusionMode"; // match AdvancedOptionsUIBlock.kSpecularOcclusionMode : TODO move both to HDStringConstants. + const string kMappingMode = "_MappingMode"; + const string kMappingMask = "_MappingMask"; + const string kPlanarSpace = "_PlanarSpace"; + + static public Vector4 AxFMappingModeToMask(AxFMappingMode mappingMode) + { + Vector4 mask = Vector4.zero; + if (mappingMode <= AxFMappingMode.UV3) + { + float X,Y,Z,W; + X = (mappingMode == AxFMappingMode.UV0) ? 1.0f : 0.0f; + Y = (mappingMode == AxFMappingMode.UV1) ? 1.0f : 0.0f; + Z = (mappingMode == AxFMappingMode.UV2) ? 1.0f : 0.0f; + W = (mappingMode == AxFMappingMode.UV3) ? 1.0f : 0.0f; + mask = new Vector4(X, Y, Z, W); + } + else if (mappingMode < AxFMappingMode.Triplanar) + { + float X,Y,Z,W; + X = (mappingMode == AxFMappingMode.PlanarYZ) ? 1.0f : 0.0f; + Y = (mappingMode == AxFMappingMode.PlanarZX) ? 1.0f : 0.0f; + Z = (mappingMode == AxFMappingMode.PlanarXY) ? 1.0f : 0.0f; + W = 0.0f; + mask = new Vector4(X, Y, Z, W); + } + return mask; + } + // All Setup Keyword functions must be static. It allow to create script to automatically update the shaders with a script if code change static public void SetupMaterialKeywordsAndPass(Material material) { @@ -62,11 +102,43 @@ static public void SetupMaterialKeywordsAndPass(Material material) CoreUtils.SetKeyword(material, "_AXF_BRDF_TYPE_CAR_PAINT", BRDFType == AxfBrdfType.CAR_PAINT); CoreUtils.SetKeyword(material, "_AXF_BRDF_TYPE_BTF", BRDFType == AxfBrdfType.BTF); + + // Mapping Modes: + AxFMappingMode mappingMode = (AxFMappingMode)material.GetFloat(kMappingMode); + + // Make sure the mask is synched: + material.SetVector(kMappingMask, AxFMappingModeToMask(mappingMode)); + + bool mappingIsPlanar = (mappingMode >= AxFMappingMode.PlanarXY) && (mappingMode < AxFMappingMode.Triplanar); + bool planarIsLocal = (material.GetFloat(kPlanarSpace) > 0.0f); + + CoreUtils.SetKeyword(material, "_MAPPING_PLANAR", mappingIsPlanar); + CoreUtils.SetKeyword(material, "_MAPPING_TRIPLANAR", mappingMode == AxFMappingMode.Triplanar); + + if (mappingIsPlanar || mappingMode == AxFMappingMode.Triplanar) + { + CoreUtils.SetKeyword(material, "_PLANAR_LOCAL", planarIsLocal); + } + + // Note: for ShaderPass defines for vertmesh/varyingmesh setup, we still use the same + // defines _REQUIRE_UV2 and _REQUIRE_UV3, and thus if eg _REQUIRE_UV3 is defined, _REQUIRE_UV2 will + // be assumed to be needed. But here in the AxFData sampling code, we use these to indicate precisely + // the single set used (if not using planar/triplanar) only and thus add _REQUIRE_UV1. + // Extra UVs might be transfered but we only need and support a single set at a time for the whole material. + CoreUtils.SetKeyword(material, "_REQUIRE_UV1", mappingMode == AxFMappingMode.UV1); + CoreUtils.SetKeyword(material, "_REQUIRE_UV2", mappingMode == AxFMappingMode.UV2); + CoreUtils.SetKeyword(material, "_REQUIRE_UV3", mappingMode == AxFMappingMode.UV3); + // Keywords for opt-out of decals and SSR: bool decalsEnabled = material.HasProperty(kEnableDecals) && material.GetFloat(kEnableDecals) > 0.0f; CoreUtils.SetKeyword(material, "_DISABLE_DECALS", decalsEnabled == false); - bool ssrEnabled = material.HasProperty(kEnableSSR) && material.GetFloat(kEnableSSR) > 0.0f; - CoreUtils.SetKeyword(material, "_DISABLE_SSR", ssrEnabled == false); + bool ssrEnabled = false; + if (material.GetSurfaceType() == SurfaceType.Transparent) + ssrEnabled = material.HasProperty(kReceivesSSRTransparent) ? material.GetFloat(kReceivesSSRTransparent) != 0 : false; + else + ssrEnabled = material.HasProperty(kReceivesSSR) ? material.GetFloat(kReceivesSSR) != 0 : false; + CoreUtils.SetKeyword(material, "_DISABLE_SSR", material.HasProperty(kReceivesSSR) && material.GetFloat(kReceivesSSR) == 0.0f); + CoreUtils.SetKeyword(material, "_DISABLE_SSR_TRANSPARENT", material.HasProperty(kReceivesSSRTransparent) && material.GetFloat(kReceivesSSRTransparent) == 0.0); CoreUtils.SetKeyword(material, "_ENABLE_GEOMETRIC_SPECULAR_AA", material.HasProperty(kEnableGeometricSpecularAA) && material.GetFloat(kEnableGeometricSpecularAA) > 0.0f); CoreUtils.SetKeyword(material, "_SPECULAR_OCCLUSION_NONE", material.HasProperty(kSpecularOcclusionMode) && material.GetFloat(kSpecularOcclusionMode) == 0.0f); diff --git a/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/AxfSurfaceInputsUIBlock.cs b/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/AxfSurfaceInputsUIBlock.cs index 8eb4b33413a..48716415aee 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/AxfSurfaceInputsUIBlock.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/AxfSurfaceInputsUIBlock.cs @@ -20,6 +20,10 @@ public class Styles { public const string header = "Surface Inputs"; + public static GUIContent mappingModeText = new GUIContent("Mapping Mode"); + public static GUIContent planarSpaceText = new GUIContent("Planar Space"); + + public static GUIContent materialTilingOffsetText = new GUIContent("Main Tiling & Offset"); ///////////////////////////////////////////////////////////////////////////////////////////////// // SVBRDF Parameters public static GUIContent diffuseColorMapText = new GUIContent("Diffuse Color"); @@ -110,10 +114,20 @@ enum SvbrdfFresnelVariant SCHLICK, // Schlick's Approximation (1994) } static readonly string[] SvbrdfFresnelVariantNames = Enum.GetNames(typeof(SvbrdfFresnelVariant)); + static readonly string[] MappingModeNames = Enum.GetNames(typeof(AxFMappingMode)); ///////////////////////////////////////////////////////////////////////////////////////////////// // Generic Parameters - + + static string m_MappingModeText = "_MappingMode"; + MaterialProperty m_MappingMode = null; + + static string m_MappingMaskText = "_MappingMask"; + MaterialProperty m_MappingMask = null; + + static string m_PlanarSpaceText = "_PlanarSpace"; + MaterialProperty m_PlanarSpace = null; + MaterialProperty m_MaterialTilingOffset = null; MaterialProperty m_DiffuseColorMapST = null; MaterialProperty m_SpecularColorMapST = null; @@ -234,6 +248,10 @@ public AxfSurfaceInputsUIBlock(Expandable expandableBit) public override void LoadMaterialProperties() { + m_MappingMode = FindProperty(m_MappingModeText); + m_MappingMask = FindProperty(m_MappingMaskText); + m_PlanarSpace = FindProperty(m_PlanarSpaceText); + m_MaterialTilingOffset = FindProperty(m_MaterialTilingOffsetText); m_DiffuseColorMapST = FindProperty(m_DiffuseColorMapText + tilingOffsetPropNameSuffix); @@ -344,7 +362,27 @@ public static void ExtractFlags(uint flags, void DrawAxfSurfaceOptionsGUI() { - materialEditor.ShaderProperty(m_MaterialTilingOffset, "Main Tiling & Offset"); + //materialEditor.ShaderProperty(m_MappingMode, Styles.mappingModeText); + EditorGUI.BeginChangeCheck(); + float val = EditorGUILayout.Popup(Styles.mappingModeText, (int)m_MappingMode.floatValue, MappingModeNames); + if (EditorGUI.EndChangeCheck()) + { + Material material = materialEditor.target as Material; + Undo.RecordObject(material, "Change Mapping Mode"); + m_MappingMode.floatValue = val; + } + + AxFMappingMode mappingMode = (AxFMappingMode)m_MappingMode.floatValue; + m_MappingMask.vectorValue = AxFGUI.AxFMappingModeToMask(mappingMode); + + if (mappingMode >= AxFMappingMode.PlanarXY) + { + ++EditorGUI.indentLevel; + materialEditor.ShaderProperty(m_PlanarSpace, Styles.planarSpaceText); + --EditorGUI.indentLevel; + } + + materialEditor.ShaderProperty(m_MaterialTilingOffset, Styles.materialTilingOffsetText); AxfBrdfType AxF_BRDFType = (AxfBrdfType)m_AxF_BRDFType.floatValue; AxF_BRDFType = (AxfBrdfType)EditorGUILayout.Popup("BRDF Type", (int)AxF_BRDFType, AxfBrdfTypeNames); diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/ScalableSettingLevelParameterEditor.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/ScalableSettingLevelParameterEditor.cs index a41b0d596e9..de006eccc07 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/ScalableSettingLevelParameterEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/ScalableSettingLevelParameterEditor.cs @@ -22,13 +22,14 @@ public override bool OnGUI(SerializedDataParameter parameter, GUIContent title) rect.y += 2; rect.width -= 3; - o.levelAndOverride = SerializedScalableSettingValueUI.LevelFieldGUI( + var levelAndOverride = SerializedScalableSettingValueUI.LevelFieldGUI( rect, title, ScalableSettingSchema.GetSchemaOrNull(ScalableSettingSchemaId.With3Levels), level, useOverride ); + value.intValue = ScalableSettingLevelParameter.GetScalableSettingLevelParameterValue(levelAndOverride.level, levelAndOverride.useOverride); return true; } } diff --git a/com.unity.render-pipelines.high-definition/Editor/Upgraders/UpgradeStandardShaderMaterials.cs b/com.unity.render-pipelines.high-definition/Editor/Upgraders/UpgradeStandardShaderMaterials.cs index 3caefc2fd49..e474ad3aa5c 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Upgraders/UpgradeStandardShaderMaterials.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Upgraders/UpgradeStandardShaderMaterials.cs @@ -35,6 +35,29 @@ internal static void UpgradeMaterialsSelection() { MaterialUpgrader.UpgradeSelection(GetHDUpgraders(), "Upgrade to HD Material"); } + + [MenuItem("Edit/Render Pipeline/Upgrade Scene Terrains to High Definition Terrains", priority = CoreUtils.editMenuPriority2)] + static void UpgradeSceneTerrainsToHighDefinitionTerrains(MenuCommand menuCommand) + { + var LegacyDefaultTerrainMat = AssetDatabase.GetBuiltinExtraResource("Default-Terrain-Standard.mat"); + var HDRPTerrainMat = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDTerrainMaterial.mat"); + var terrainArray = UnityEngine.GameObject.FindObjectsOfType(); + + if(terrainArray.Length == 0) + { + Debug.LogWarning("No terrains were found in the scene."); + return; + } + + foreach (Terrain currentTerrain in terrainArray) + { + if(currentTerrain.materialTemplate == LegacyDefaultTerrainMat) + { + currentTerrain.materialTemplate = HDRPTerrainMat; + } + } + } + [MenuItem("Edit/Render Pipeline/Multiply Unity Builtin Directional Light Intensity to match High Definition", priority = CoreUtils.editMenuPriority2)] internal static void UpgradeLights() diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs index 2d161eea64e..f72002d77cb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs @@ -80,12 +80,35 @@ public struct SurfaceData public float anisotropyAngle; // Car Paint Variables - [SurfaceDataAttributes("Flakes UV")] - public Vector2 flakesUV; - - [SurfaceDataAttributes("Flakes Mip")] - public float flakesMipLevel; - + [SurfaceDataAttributes("Flakes UV (or PlanarZY)")] + public Vector2 flakesUVZY; + [SurfaceDataAttributes("Flakes PlanarXZ")] + public Vector2 flakesUVXZ; + [SurfaceDataAttributes("Flakes PlanarXY")] + public Vector2 flakesUVXY; + + [SurfaceDataAttributes("Flakes Mip (and for PlanarZY)")] + public float flakesMipLevelZY; + [SurfaceDataAttributes("Flakes Mip for PlanarXZ")] + public float flakesMipLevelXZ; + [SurfaceDataAttributes("Flakes Mip for PlanarXY")] + public float flakesMipLevelXY; + [SurfaceDataAttributes("Flakes Triplanar Weights")] + public Vector3 flakesTriplanarWeights; + + // if non null, we will prefer gradients (to be used statically only!) + [SurfaceDataAttributes("Flakes ddx (and for PlanarZY)")] + public Vector2 flakesDdxZY; + [SurfaceDataAttributes("Flakes ddy (and for PlanarZY)")] + public Vector2 flakesDdyZY; + [SurfaceDataAttributes("Flakes ddx for PlanarXZ")] + public Vector2 flakesDdxXZ; + [SurfaceDataAttributes("Flakes ddy for PlanarXZ")] + public Vector2 flakesDdyXZ; + [SurfaceDataAttributes("Flakes ddx for PlanarXY")] + public Vector2 flakesDdxXY; + [SurfaceDataAttributes("Flakes ddy for PlanarXY")] + public Vector2 flakesDdyXY; // BTF Variables // Clearcoat @@ -127,11 +150,19 @@ public struct BSDFData public float height_mm; // Car Paint Variables - [SurfaceDataAttributes("")] - public Vector2 flakesUV; - - [SurfaceDataAttributes("Flakes Mip")] - public float flakesMipLevel; + public Vector2 flakesUVZY; + public Vector2 flakesUVXZ; + public Vector2 flakesUVXY; + public float flakesMipLevelZY; + public float flakesMipLevelXZ; + public float flakesMipLevelXY; + public Vector3 flakesTriplanarWeights; + public Vector2 flakesDdxZY; // if non null, we will prefer gradients (to be used statically only!) + public Vector2 flakesDdyZY; + public Vector2 flakesDdxXZ; + public Vector2 flakesDdyXZ; + public Vector2 flakesDdxXY; + public Vector2 flakesDdyXY; // BTF Variables diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs.hlsl index 7362aefc55d..208c45de74c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.cs.hlsl @@ -29,13 +29,24 @@ #define DEBUGVIEW_AXF_SURFACEDATA_SPECULAR_LOBE (1208) #define DEBUGVIEW_AXF_SURFACEDATA_HEIGHT (1209) #define DEBUGVIEW_AXF_SURFACEDATA_ANISOTROPIC_ANGLE (1210) -#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_UV (1211) -#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP (1212) -#define DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_COLOR (1213) -#define DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_NORMAL (1214) -#define DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_IOR (1215) -#define DEBUGVIEW_AXF_SURFACEDATA_GEOMETRIC_NORMAL (1216) -#define DEBUGVIEW_AXF_SURFACEDATA_GEOMETRIC_NORMAL_VIEW_SPACE (1217) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_UV_(OR_PLANAR_ZY) (1211) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_PLANAR_XZ (1212) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_PLANAR_XY (1213) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP_(AND_FOR_PLANAR_ZY) (1214) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP_FOR_PLANAR_XZ (1215) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP_FOR_PLANAR_XY (1216) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_TRIPLANAR_WEIGHTS (1217) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDX_(AND_FOR_PLANAR_ZY) (1218) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDY_(AND_FOR_PLANAR_ZY) (1219) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDX_FOR_PLANAR_XZ (1220) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDY_FOR_PLANAR_XZ (1221) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDX_FOR_PLANAR_XY (1222) +#define DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDY_FOR_PLANAR_XY (1223) +#define DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_COLOR (1224) +#define DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_NORMAL (1225) +#define DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_IOR (1226) +#define DEBUGVIEW_AXF_SURFACEDATA_GEOMETRIC_NORMAL (1227) +#define DEBUGVIEW_AXF_SURFACEDATA_GEOMETRIC_NORMAL_VIEW_SPACE (1228) // // UnityEngine.Rendering.HighDefinition.AxF+BSDFData: static fields @@ -51,13 +62,24 @@ #define DEBUGVIEW_AXF_BSDFDATA_FRESNEL_F0 (1258) #define DEBUGVIEW_AXF_BSDFDATA_ROUGHNESS (1259) #define DEBUGVIEW_AXF_BSDFDATA_HEIGHT_MM (1260) -#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_UV (1261) -#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP (1262) -#define DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_COLOR (1263) -#define DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_NORMAL_WS (1264) -#define DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_IOR (1265) -#define DEBUGVIEW_AXF_BSDFDATA_GEOMETRIC_NORMAL (1266) -#define DEBUGVIEW_AXF_BSDFDATA_GEOMETRIC_NORMAL_VIEW_SPACE (1267) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_UVZY (1261) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_UVXZ (1262) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_UVXY (1263) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP_LEVEL_ZY (1264) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP_LEVEL_XZ (1265) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP_LEVEL_XY (1266) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_TRIPLANAR_WEIGHTS (1267) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDX_ZY (1268) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDY_ZY (1269) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDX_XZ (1270) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDY_XZ (1271) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDX_XY (1272) +#define DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDY_XY (1273) +#define DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_COLOR (1274) +#define DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_NORMAL_WS (1275) +#define DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_IOR (1276) +#define DEBUGVIEW_AXF_BSDFDATA_GEOMETRIC_NORMAL (1277) +#define DEBUGVIEW_AXF_BSDFDATA_GEOMETRIC_NORMAL_VIEW_SPACE (1278) // Generated from UnityEngine.Rendering.HighDefinition.AxF+SurfaceData // PackingRules = Exact @@ -73,8 +95,19 @@ struct SurfaceData float3 specularLobe; float height_mm; float anisotropyAngle; - float2 flakesUV; - float flakesMipLevel; + float2 flakesUVZY; + float2 flakesUVXZ; + float2 flakesUVXY; + float flakesMipLevelZY; + float flakesMipLevelXZ; + float flakesMipLevelXY; + float3 flakesTriplanarWeights; + float2 flakesDdxZY; + float2 flakesDdyZY; + float2 flakesDdxXZ; + float2 flakesDdyXZ; + float2 flakesDdxXY; + float2 flakesDdyXY; float3 clearcoatColor; float3 clearcoatNormalWS; float clearcoatIOR; @@ -95,8 +128,19 @@ struct BSDFData float3 fresnelF0; float3 roughness; float height_mm; - float2 flakesUV; - float flakesMipLevel; + float2 flakesUVZY; + float2 flakesUVXZ; + float2 flakesUVXY; + float flakesMipLevelZY; + float flakesMipLevelXZ; + float flakesMipLevelXY; + float3 flakesTriplanarWeights; + float2 flakesDdxZY; + float2 flakesDdyZY; + float2 flakesDdxXZ; + float2 flakesDdyXZ; + float2 flakesDdxXY; + float2 flakesDdyXY; float3 clearcoatColor; float3 clearcoatNormalWS; float clearcoatIOR; @@ -145,11 +189,44 @@ void GetGeneratedSurfaceDataDebug(uint paramId, SurfaceData surfacedata, inout f case DEBUGVIEW_AXF_SURFACEDATA_ANISOTROPIC_ANGLE: result = surfacedata.anisotropyAngle.xxx; break; - case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_UV: - result = float3(surfacedata.flakesUV, 0.0); + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_UV_(OR_PLANAR_ZY): + result = float3(surfacedata.flakesUVZY, 0.0); break; - case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP: - result = surfacedata.flakesMipLevel.xxx; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_PLANAR_XZ: + result = float3(surfacedata.flakesUVXZ, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_PLANAR_XY: + result = float3(surfacedata.flakesUVXY, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP_(AND_FOR_PLANAR_ZY): + result = surfacedata.flakesMipLevelZY.xxx; + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP_FOR_PLANAR_XZ: + result = surfacedata.flakesMipLevelXZ.xxx; + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_MIP_FOR_PLANAR_XY: + result = surfacedata.flakesMipLevelXY.xxx; + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_TRIPLANAR_WEIGHTS: + result = surfacedata.flakesTriplanarWeights; + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDX_(AND_FOR_PLANAR_ZY): + result = float3(surfacedata.flakesDdxZY, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDY_(AND_FOR_PLANAR_ZY): + result = float3(surfacedata.flakesDdyZY, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDX_FOR_PLANAR_XZ: + result = float3(surfacedata.flakesDdxXZ, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDY_FOR_PLANAR_XZ: + result = float3(surfacedata.flakesDdyXZ, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDX_FOR_PLANAR_XY: + result = float3(surfacedata.flakesDdxXY, 0.0); + break; + case DEBUGVIEW_AXF_SURFACEDATA_FLAKES_DDY_FOR_PLANAR_XY: + result = float3(surfacedata.flakesDdyXY, 0.0); break; case DEBUGVIEW_AXF_SURFACEDATA_CLEARCOAT_COLOR: result = surfacedata.clearcoatColor; @@ -209,11 +286,44 @@ void GetGeneratedBSDFDataDebug(uint paramId, BSDFData bsdfdata, inout float3 res case DEBUGVIEW_AXF_BSDFDATA_HEIGHT_MM: result = bsdfdata.height_mm.xxx; break; - case DEBUGVIEW_AXF_BSDFDATA_FLAKES_UV: - result = float3(bsdfdata.flakesUV, 0.0); + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_UVZY: + result = float3(bsdfdata.flakesUVZY, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_UVXZ: + result = float3(bsdfdata.flakesUVXZ, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_UVXY: + result = float3(bsdfdata.flakesUVXY, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP_LEVEL_ZY: + result = bsdfdata.flakesMipLevelZY.xxx; + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP_LEVEL_XZ: + result = bsdfdata.flakesMipLevelXZ.xxx; + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP_LEVEL_XY: + result = bsdfdata.flakesMipLevelXY.xxx; + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_TRIPLANAR_WEIGHTS: + result = bsdfdata.flakesTriplanarWeights; + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDX_ZY: + result = float3(bsdfdata.flakesDdxZY, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDY_ZY: + result = float3(bsdfdata.flakesDdyZY, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDX_XZ: + result = float3(bsdfdata.flakesDdxXZ, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDY_XZ: + result = float3(bsdfdata.flakesDdyXZ, 0.0); + break; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDX_XY: + result = float3(bsdfdata.flakesDdxXY, 0.0); break; - case DEBUGVIEW_AXF_BSDFDATA_FLAKES_MIP: - result = bsdfdata.flakesMipLevel.xxx; + case DEBUGVIEW_AXF_BSDFDATA_FLAKES_DDY_XY: + result = float3(bsdfdata.flakesDdyXY, 0.0); break; case DEBUGVIEW_AXF_BSDFDATA_CLEARCOAT_COLOR: result = bsdfdata.clearcoatColor; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl index bf318142059..1b3bac4efa5 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.hlsl @@ -71,6 +71,15 @@ # define IF_FLAKES_JUST_BTF(a) (a) #endif +#ifdef _MAPPING_TRIPLANAR +# define NB_FLAKES_RND_SHIFTS 3 +# define FLAKES_SHIFT_IDX_PLANAR_ZY (0) +# define FLAKES_SHIFT_IDX_PLANAR_XZ (1) +# define FLAKES_SHIFT_IDX_PLANAR_XY (2) +#else +# define NB_FLAKES_RND_SHIFTS 1 +#endif + // Define this to sample the environment maps/LTC samples for each lobe, instead of a single sample with an average lobe #define USE_COOK_TORRANCE_MULTI_LOBES 1 #define MAX_CT_LOBE_COUNT 3 @@ -81,6 +90,43 @@ // Helper functions/variable specific to this material //----------------------------------------------------------------------------- +void FillFlakesBSDFData(SurfaceData surfaceData, inout BSDFData bsdfData) +{ +#ifdef _MAPPING_TRIPLANAR + bsdfData.flakesUVZY = surfaceData.flakesUVZY; + bsdfData.flakesUVXZ = surfaceData.flakesUVXZ; + bsdfData.flakesUVXY = surfaceData.flakesUVXY; + bsdfData.flakesMipLevelZY = surfaceData.flakesMipLevelZY; + bsdfData.flakesMipLevelXZ = surfaceData.flakesMipLevelXZ; + bsdfData.flakesMipLevelXY = surfaceData.flakesMipLevelXY; + bsdfData.flakesTriplanarWeights = surfaceData.flakesTriplanarWeights; + + bsdfData.flakesDdxZY = surfaceData.flakesDdxZY; + bsdfData.flakesDdyZY = surfaceData.flakesDdyZY; + bsdfData.flakesDdxXZ = surfaceData.flakesDdxXZ; + bsdfData.flakesDdyXZ = surfaceData.flakesDdyXZ; + bsdfData.flakesDdxXY = surfaceData.flakesDdxXY; + bsdfData.flakesDdyXY = surfaceData.flakesDdyXY; +#else + // NOTE: When not triplanar UVZY has one uv set or one planar coordinate set, + // and this planar coordinate set isn't necessarily ZY, we just reuse this field + // as a common one. + bsdfData.flakesUVZY = surfaceData.flakesUVZY; + bsdfData.flakesMipLevelZY = surfaceData.flakesMipLevelZY; + bsdfData.flakesDdxZY = surfaceData.flakesDdxZY; + bsdfData.flakesDdyZY = surfaceData.flakesDdyZY; + bsdfData.flakesUVXZ = 0; + bsdfData.flakesUVXY = 0; + bsdfData.flakesMipLevelXZ = 0; + bsdfData.flakesMipLevelXY = 0; + bsdfData.flakesTriplanarWeights = 0; + bsdfData.flakesDdxXZ = 0; + bsdfData.flakesDdyXZ = 0; + bsdfData.flakesDdxXY = 0; + bsdfData.flakesDdyXY = 0; +#endif +} + // AxF splits the chromaticity and f0 from the usual "SpecularColor" convention // to just be a chromatic f0. // CARPAINT2 has a different way to handle colors and must be accounted for too. @@ -686,7 +732,7 @@ float OrenNayar(in float3 n, in float3 v, in float3 l, in float roughness) BSDFData ConvertSurfaceDataToBSDFData(uint2 positionSS, SurfaceData surfaceData) { BSDFData bsdfData; - // ZERO_INITIALIZE(BSDFData, data); + ZERO_INITIALIZE(BSDFData, bsdfData); bsdfData.ambientOcclusion = surfaceData.ambientOcclusion; bsdfData.specularOcclusion = surfaceData.specularOcclusion; @@ -711,14 +757,12 @@ BSDFData ConvertSurfaceDataToBSDFData(uint2 positionSS, SurfaceData surfaceData) bsdfData.clearcoatIOR = surfaceData.clearcoatIOR; // Useless but pass along anyway - bsdfData.flakesUV = surfaceData.flakesUV; - bsdfData.flakesMipLevel = surfaceData.flakesMipLevel; + FillFlakesBSDFData(surfaceData, bsdfData); //----------------------------------------------------------------------------- #elif defined(_AXF_BRDF_TYPE_CAR_PAINT) bsdfData.diffuseColor = surfaceData.diffuseColor; - bsdfData.flakesUV = surfaceData.flakesUV; - bsdfData.flakesMipLevel = surfaceData.flakesMipLevel; + FillFlakesBSDFData(surfaceData, bsdfData); bsdfData.clearcoatColor = 1.0; // Not provided, assume white... bsdfData.clearcoatIOR = surfaceData.clearcoatIOR; bsdfData.clearcoatNormalWS = HasClearcoat() ? surfaceData.clearcoatNormalWS : surfaceData.normalWS; @@ -810,9 +854,52 @@ uint SampleFlakesLUT(uint index) // return pipoLUT[min(11, _index)]; } -float3 SamplesFlakes(float2 UV, uint sliceIndex, float mipLevel) -{ - return _CarPaint2_BTFFlakeMapScale * SAMPLE_TEXTURE2D_ARRAY_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, UV, sliceIndex, mipLevel).xyz; +float3 SamplesFlakes(float2 offsets[NB_FLAKES_RND_SHIFTS], uint sliceIndex, BSDFData bsdfData) +{ + // We can't use SAMPLE_TEXTURE2D_ARRAY, the compiler can't unroll in that case, and the lightloop is built with unroll + // That's why we calculate gradients or LOD earlier. + // TODO: The LOD code path (useFlakesMipLevel == true) is kept for a possible performance/appearance trade-off + // (less VGPR for LOD) and also for (future) raytracing, it is easier to substitute an approximate single LOD value + // than a full 2x2 Jacobian. + float3 val = 0; + bool useFlakesMipLevel = all(bsdfData.flakesDdxZY == (float2)0); // should be known statically! + +#ifdef _MAPPING_TRIPLANAR + val += bsdfData.flakesTriplanarWeights.x * + (useFlakesMipLevel ? + SAMPLE_TEXTURE2D_ARRAY_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVZY + offsets[FLAKES_SHIFT_IDX_PLANAR_ZY], + sliceIndex, bsdfData.flakesMipLevelZY).xyz + : SAMPLE_TEXTURE2D_ARRAY_GRAD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVZY + offsets[FLAKES_SHIFT_IDX_PLANAR_ZY], + sliceIndex, bsdfData.flakesDdxZY, bsdfData.flakesDdyZY).xyz ); + + val += bsdfData.flakesTriplanarWeights.y * + (useFlakesMipLevel ? + SAMPLE_TEXTURE2D_ARRAY_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVXZ + offsets[FLAKES_SHIFT_IDX_PLANAR_XZ], + sliceIndex, bsdfData.flakesMipLevelXZ).xyz + : SAMPLE_TEXTURE2D_ARRAY_GRAD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVXZ + offsets[FLAKES_SHIFT_IDX_PLANAR_XZ], + sliceIndex, bsdfData.flakesDdxXZ, bsdfData.flakesDdyXZ).xyz ); + val += bsdfData.flakesTriplanarWeights.z * + (useFlakesMipLevel ? + SAMPLE_TEXTURE2D_ARRAY_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVXY + offsets[FLAKES_SHIFT_IDX_PLANAR_XY], + sliceIndex, bsdfData.flakesMipLevelXY).xyz + : SAMPLE_TEXTURE2D_ARRAY_GRAD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVXY + offsets[FLAKES_SHIFT_IDX_PLANAR_XY], + sliceIndex, bsdfData.flakesDdxXY, bsdfData.flakesDdyXY).xyz ); + val *= _CarPaint2_BTFFlakeMapScale; +#else + val = _CarPaint2_BTFFlakeMapScale * + (useFlakesMipLevel ? + SAMPLE_TEXTURE2D_ARRAY_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVZY + offsets[0], sliceIndex, bsdfData.flakesMipLevelZY).xyz + : SAMPLE_TEXTURE2D_ARRAY_GRAD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, + bsdfData.flakesUVZY + offsets[0], sliceIndex, bsdfData.flakesDdxZY, bsdfData.flakesDdyZY).xyz ); +#endif + return val; } // @@ -820,9 +907,6 @@ float3 SamplesFlakes(float2 UV, uint sliceIndex, float mipLevel) // float3 CarPaint_BTF(float thetaH, float thetaD, BSDFData bsdfData) { - float2 UV = bsdfData.flakesUV; - float mipLevel = bsdfData.flakesMipLevel; - // thetaH sampling defines the angular sampling, i.e. angular flake lifetime float binIndexH = _CarPaint2_FlakeNumThetaF * (2.0 * thetaH / PI) + 0.5; // TODO: doc says to use NumThetaF for both, check if this isn't a typo float binIndexD = _CarPaint2_FlakeNumThetaF * (2.0 * thetaD / PI) + 0.5; @@ -836,8 +920,9 @@ float3 CarPaint_BTF(float thetaH, float thetaD, BSDFData bsdfData) float thetaD_weight = binIndexD - thetaD_low; // To allow lower thetaD samplings while preserving flake lifetime, "virtual" thetaD patches are generated by shifting existing ones - float2 offset_l = 0; - float2 offset_h = 0; + // NB_FLAKES_RND_SHIFTS = 1 if not triplanar; otherwise this is in case we want a randomization that takes planar coordinate index into account + float2 offset_l[NB_FLAKES_RND_SHIFTS] = (float2[NB_FLAKES_RND_SHIFTS])0; + float2 offset_h[NB_FLAKES_RND_SHIFTS] = (float2[NB_FLAKES_RND_SHIFTS])0; // Organization of the flake BTF slice array and LUT: // @@ -943,8 +1028,10 @@ float3 CarPaint_BTF(float thetaH, float thetaD, BSDFData bsdfData) // Access flake texture - make sure to stay in the correct slices (no slip over) if (thetaD_low < _CarPaint2_FlakeMaxThetaI) { - float2 UVl = UV + offset_l; - float2 UVh = UV + offset_h; + // These are spatial UVs, we let SampleFlakes deal with them in case of triplanar, + // and just submit the random shift offsets (TODO "virtual" angular patches) + //float2 UVl = UV + offset_l; + //float2 UVh = UV + offset_h; uint LUT0 = SampleFlakesLUT(thetaD_low); uint LUT1 = SampleFlakesLUT(thetaD_high); @@ -954,10 +1041,10 @@ float3 CarPaint_BTF(float thetaH, float thetaD, BSDFData bsdfData) if (LUT0 + thetaH_low < LUT0_limit) { - H0_D0 = SamplesFlakes(UVl, LUT0 + thetaH_low, mipLevel); + H0_D0 = SamplesFlakes(offset_l, LUT0 + thetaH_low, bsdfData); if (LUT0 + thetaH_high < LUT0_limit) { - H1_D0 = SamplesFlakes(UVl, LUT0 + thetaH_high, mipLevel); + H1_D0 = SamplesFlakes(offset_l, LUT0 + thetaH_high, bsdfData); } } // else it means that the calculated index for that thetaD_low and the thetaH_low @@ -974,10 +1061,10 @@ float3 CarPaint_BTF(float thetaH, float thetaD, BSDFData bsdfData) { if (LUT1 + thetaH_low < LUT2) { - H0_D1 = SamplesFlakes(UVh, LUT1 + thetaH_low, mipLevel); + H0_D1 = SamplesFlakes(offset_h, LUT1 + thetaH_low, bsdfData); if (LUT1 + thetaH_high < LUT2) { - H1_D1 = SamplesFlakes(UVh, LUT1 + thetaH_high, mipLevel); + H1_D1 = SamplesFlakes(offset_h, LUT1 + thetaH_high, bsdfData); } } // else, same thing as our comment above @@ -1088,7 +1175,8 @@ PreLightData GetPreLightData(float3 viewWS_Clearcoat, PositionInputs posInput preLightData.iblPerceptualRoughness = PerceptualRoughnessBeckmannToGGX(preLightData.iblPerceptualRoughness); break; - // case 1: // @TODO: Support Blinn-Phong FGD? + case 1: //Phong + case 4: //Blinn-Phong : just approximate with Cook-Torrance which uses a Beckmann distribution case 2: GetPreIntegratedFGDCookTorranceAndLambert(NdotV_UnderCoat, preLightData.iblPerceptualRoughness, tempF0, preLightData.specularFGD, preLightData.diffuseFGD, specularReflectivity); preLightData.specularFGD *= GetPreIntegratedFGDCookTorranceSampleMutiplier(); @@ -1099,8 +1187,6 @@ PreLightData GetPreLightData(float3 viewWS_Clearcoat, PositionInputs posInput GetPreIntegratedFGDGGXAndLambert(NdotV_UnderCoat, preLightData.iblPerceptualRoughness, tempF0, preLightData.specularFGD, preLightData.diffuseFGD, specularReflectivity); break; - // case 4: // @TODO: Support Blinn-Phong FGD? - default: // Use GGX by default GetPreIntegratedFGDGGXAndLambert(NdotV_UnderCoat, preLightData.iblPerceptualRoughness, tempF0, preLightData.specularFGD, preLightData.diffuseFGD, specularReflectivity); break; @@ -1269,14 +1355,6 @@ PreLightData GetPreLightData(float3 viewWS_Clearcoat, PositionInputs posInput case 1: // BLINN-PHONG case 4: // PHONG; { - // According to https://computergraphics.stackexchange.com/questions/1515/what-is-the-accepted-method-of-converting-shininess-to-roughness-and-vice-versa - // float exponent = 2/roughness^4 - 2; - // - float exponent = PerceptualRoughnessToRoughness(preLightData.iblPerceptualRoughness); - float roughness = pow(max(0.0, 2.0 / (exponent + 2)), 1.0 / 4.0); - // todo_modes todo_pseudorefract: cant use undercoat like that - //float2 UV = LTCGetSamplingUV(NdotV_UnderCoat, RoughnessToPerceptualRoughness(roughness)); - float2 UV = LTCGetSamplingUV(NdotV_Clearcoat, RoughnessToPerceptualRoughness(roughness)); preLightData.ltcTransformSpecular = LTCSampleMatrix(UV, LTC_MATRIX_INDEX_COOK_TORRANCE); break; } @@ -1485,7 +1563,8 @@ float3 ComputeWard(float3 H, float LdotH, float NdotL, float NdotV, PreLightData float3 ComputeBlinnPhong(float3 H, float LdotH, float NdotL, float NdotV, PreLightData preLightData, BSDFData bsdfData) { - float2 exponents = exp2(bsdfData.roughness.xy); + // See AxFGetRoughnessFromSpecularLobeTexture in AxFData + float2 exponents = 2 * rcp(max(0.0001,(bsdfData.roughness.xy*bsdfData.roughness.xy))) - 2; // Evaluate normal distribution function float3 tsH = float3(dot(H, bsdfData.tangentWS), dot(H, bsdfData.biTangentWS), dot(H, bsdfData.normalWS)); @@ -2026,7 +2105,7 @@ DirectLighting EvaluateBSDF_Line( LightLoopContext lightLoopContext, ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformFlakes); ltcValue *= lightData.specularDimmer; - lighting.specular += ltcValue * preLightData.singleFlakesComponent; //preLightData.flakesFGD * CarPaint_BTF(thetaH, thetaD, bsdfData); + lighting.specular += ltcValue * preLightData.singleFlakesComponent; #endif @@ -2242,7 +2321,7 @@ DirectLighting EvaluateBSDF_Rect(LightLoopContext lightLoopContext, ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformFlakes)); ltcValue *= lightData.specularDimmer; - lighting.specular += ltcValue * preLightData.singleFlakesComponent; //preLightData.flakesFGD * CarPaint_BTF(thetaH, thetaD, bsdfData); + lighting.specular += ltcValue * preLightData.singleFlakesComponent; #endif @@ -2499,7 +2578,6 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // Sample flakes //TODO_FLAKES float flakesMipLevel = 0; // Flakes are supposed to be perfect mirrors - //envLighting += preLightData.flakesFGD * CarPaint_BTF(thetaH, thetaD, bsdfData) * SampleEnv(lightLoopContext, lightData.envIndex, lightWS_UnderCoat, flakesMipLevel, lightData.rangeCompressionFactorCompensation).xyz; envLighting += preLightData.singleFlakesComponent * SampleEnv(lightLoopContext, lightData.envIndex, envSamplingDirForBottomLayer, flakesMipLevel, lightData.rangeCompressionFactorCompensation).xyz; #else // USE_COOK_TORRANCE_MULTI_LOBES @@ -2512,7 +2590,6 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, envLighting = preLightData.specularCTFGDSingleLobe * GetSpecularIndirectDimmer(); //TODO_FLAKES - //envLighting += preLightData.flakesFGD * CarPaint_BTF(thetaH, thetaD, bsdfData); envLighting += preLightData.singleFlakesComponent; envLighting *= preLD.xyz; weight *= preLD.w; // Used by planar reflection to discard pixel diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader index 773e56a909d..c79b757d885 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader @@ -7,6 +7,13 @@ Shader "HDRP/AxF" ///////////////////////////////////////////////////////////////////////////// // General Parameters + // UI Only: transfered to _MappingMask + // BUG! 6 values work, not 7 -_- + //[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3, PlanarXY, 4, PlanarYZ, 5, PlanarZX, 6, Triplanar, 7)] _MappingMode("Mapping Mode", Float) = 0 + [HideInInspector] _MappingMode("Mapping Mode", Float) = 0 + [HideInInspector] _MappingMask("MappingMask", Vector) = (1, 0, 0, 0) + // UI Only: + [Enum(World, 0, Local, 1)] _PlanarSpace("Planar/Triplanar space", Float) = 0 // Tilings and offsets _Material_SO( "Main Material Tiling & Offset", Vector) = (1, 1, 0, 0) @@ -135,7 +142,7 @@ Shader "HDRP/AxF" [ToggleUI] _SupportDecals("Support Decals", Float) = 1.0 [ToggleUI] _ReceivesSSR("Receives SSR", Float) = 1.0 - + [ToggleUI] _ReceivesSSRTransparent("Receives SSR Transparent", Float) = 0.0 [ToggleUI] _AddPrecomputedVelocity("AddPrecomputedVelocity", Float) = 0.0 } @@ -152,12 +159,17 @@ Shader "HDRP/AxF" #pragma shader_feature_local _ _SPECULAR_OCCLUSION_NONE //_SPECULAR_OCCLUSION_FROM_BENT_NORMAL_MAP + #pragma shader_feature_local _ _MAPPING_PLANAR _MAPPING_TRIPLANAR + #pragma shader_feature_local _ _REQUIRE_UV1 _REQUIRE_UV2 _REQUIRE_UV3 + #pragma shader_feature_local _ _PLANAR_LOCAL + #pragma shader_feature_local _ALPHATEST_ON #pragma shader_feature_local _ALPHATOMASK_ON #pragma shader_feature_local _DOUBLESIDED_ON #pragma shader_feature_local _DISABLE_DECALS #pragma shader_feature_local _DISABLE_SSR + #pragma shader_feature_local _DISABLE_SSR_TRANSPARENT #pragma shader_feature_local _ENABLE_GEOMETRIC_SPECULAR_AA #pragma shader_feature_local _ADD_PRECOMPUTED_VELOCITY diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFData.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFData.hlsl index 1854d742dc1..5a58b7cdeed 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFData.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFData.hlsl @@ -1,12 +1,428 @@ +//------------------------------------------------------------------------------------- +// Defines +//------------------------------------------------------------------------------------- +// Gradients are now required: +#define SURFACE_GRADIENT // Note: this affects Material/MaterialUtilities.hlsl's GetNormalWS() and makes it expect a surface gradient. + +//to test #define FLAKES_TILE_BEFORE_SCALE +#define AXF_REUSE_SCREEN_DDXDDY +// ...ie use _GRAD sampling for everything and calculate those only one time: +// offset doesn't change derivatives, and scales just scales them, so we can cache them. + +// The compiler can't unroll the lightloop if flakes are sampled inside it, so we need to cache either LOD +// or derivatives. We prefer the later, as the CalculateLevelOfDetail will not work when anisotropic filtering +// is used, and AxF materials textures often have trilinear filtering set. +#define FLAKES_USE_DDXDDY + +#define AXF_USES_RG_NORMAL_MAPS // else, RGB + //------------------------------------------------------------------------------------- // Fill SurfaceData/Builtin data function //------------------------------------------------------------------------------------- +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMapping.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/BuiltinUtilities.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialUtilities.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Decal/DecalUtilities.hlsl" +//----------------------------------------------------------------------------- +// Texture Mapping +//----------------------------------------------------------------------------- +#ifdef AXF_USES_RG_NORMAL_MAPS +#define AXF_DERIVATIVE_NORMAL UnpackDerivativeNormalRGorAG +#else +#define AXF_DERIVATIVE_NORMAL UnpackDerivativeNormalRGB +#endif + // Note: the scaling _Material_SO.xy should already be in texuv, but NOT the bias. -#define AXF_TRANSFORM_TEXUV(texuv, name) ((texuv.xy) * name##_SO.xy + name##_SO.zw + _Material_SO.zw) +#define AXF_TRANSFORM_TEXUV_BYNAME(texuv, name) ((texuv.xy) * name##_SO.xy + name##_SO.zw + _Material_SO.zw) +#define AXF_GET_SINGE_SCALE_OFFSET(name) (name##_SO) +#define AXF_TRANSFORM_TEXUV(texuv, scaleOffset) ((texuv.xy) * scaleOffset.xy + scaleOffset.zw + _Material_SO.zw) + +// Note: the scaling _Material_SO.xy should already be in ddx and ddy: +#define AXF_SCALE_DDXDDY_BYNAME(vddx, name) ((vddx) * (name##_SO.xy)) + +#if 0 +#define DDX(param) ddx_fine(param) +#define DDY(param) ddy_fine(param) +#else +#define DDX(param) ddx(param) +#define DDY(param) ddy(param) +#endif + +struct TextureUVMapping +{ +#ifdef _MAPPING_TRIPLANAR + float2 uvZY; + float2 uvXZ; + float2 uvXY; + float3 triplanarWeights; + float2 ddxZY; + float2 ddyZY; + float2 ddxXZ; + float2 ddyXZ; + float2 ddxXY; + float2 ddyXY; +#else + float2 uvBase; // uv0..uv3 or a planar set (ZY, XZ or XY) + float2 ddxBase; + float2 ddyBase; +#endif + + float3 vertexNormalWS; + float3 vertexTangentWS; + float3 vertexBitangentWS; +}; + +void InitTextureUVMapping(FragInputs input, out TextureUVMapping uvMapping) +{ + float2 uvZY; + float2 uvXZ; + float2 uvXY; + float2 uv3 = 0; + + // Set uv* variables above: they will contain a set of uv0...3 or a planar set: +#if (defined(_MAPPING_PLANAR) || defined(_MAPPING_TRIPLANAR)) + // planar/triplanar + uv3 = 0; + +#ifdef _PLANAR_LOCAL + // If we use local planar mapping, convert to local space + GetTriplanarCoordinate(TransformWorldToObject(input.positionRWS), uvXZ, uvXY, uvZY); +#else + GetTriplanarCoordinate(GetAbsolutePositionWS(input.positionRWS), uvXZ, uvXY, uvZY); +#endif + + // Note: if only planar mapping is selected, we don't apply AxF main material tiling scale here, + // we select one set with _MappingMask into the uvBase and scale that. + +#ifdef _MAPPING_TRIPLANAR + // In that case, we will need to store the 3 sets of planar coordinates: + // (Apply AxF's main material tiling scale also) + uvMapping.uvZY = uvZY * _Material_SO.xy; + uvMapping.uvXZ = uvXZ * _Material_SO.xy; + uvMapping.uvXY = uvXY * _Material_SO.xy; + + uvMapping.ddxZY = DDX(uvMapping.uvZY); + uvMapping.ddyZY = DDY(uvMapping.uvZY); + uvMapping.ddxXZ = DDX(uvMapping.uvXZ); + uvMapping.ddyXZ = DDY(uvMapping.uvXZ); + uvMapping.ddxXY = DDX(uvMapping.uvXY); + uvMapping.ddyXY = DDY(uvMapping.uvXY); + +#endif + +#else // #if (defined(_MAPPING_PLANAR) || defined(_MAPPING_TRIPLANAR)) + + // No planar and no triplanar: uvZY will alias uv0, uvXZ uv1 and uvXY uv2 and _MappingMask will select one: + uv3 = input.texCoord3.xy; + uvZY = input.texCoord0.xy; + uvXZ = input.texCoord1.xy; + uvXY = input.texCoord2.xy; +#endif // #if (defined(_MAPPING_PLANAR) || defined(_MAPPING_TRIPLANAR)) + + // Set uvBase if not triplanar from the uv* variables above +#ifndef _MAPPING_TRIPLANAR + // No triplanar: uvBase will store the selected single uv or planar coordinate set using _MappingMask: + uvMapping.uvBase = _MappingMask.x * uvZY + // texCoord0 if no planar + _MappingMask.y * uvXZ + // texCoord1 if no planar + _MappingMask.z * uvXY + // texCoord2 if no planar + _MappingMask.w * uv3; // _MappingMask.w should be 0 anyway if planar, but we force uv3 to 0 + + // Apply AxF's main material tiling scale: + uvMapping.uvBase *= _Material_SO.xy; + + uvMapping.ddxBase = DDX(uvMapping.uvBase); + uvMapping.ddyBase = DDY(uvMapping.uvBase); + +#endif + + // Calculate triplanar weights, interpreting "local planar space" for coordinates + // as applying to the normal (used for weighting the samples fetched from those planar coords) also. +#ifdef _MAPPING_TRIPLANAR + float3 vertexNormal = input.tangentToWorld[2].xyz; +#ifdef _PLANAR_LOCAL + // If we use local planar mapping, convert to local space + vertexNormal = TransformWorldToObjectDir(vertexNormal); +#endif + uvMapping.triplanarWeights = ComputeTriplanarWeights(vertexNormal); +#endif + + // Use surface gradients to build an extra TBN is using anything other than UV0 + // Otherwise, use the vertex stage provided TBN as default: + + float3 vertexNormalWS = input.tangentToWorld[2]; + uvMapping.vertexNormalWS = vertexNormalWS; + uvMapping.vertexTangentWS = input.tangentToWorld[0]; + uvMapping.vertexBitangentWS = input.tangentToWorld[1]; + +#if (defined(_REQUIRE_UV1)||defined(_REQUIRE_UV2)||defined(_REQUIRE_UV3)) + float3 dPdx = ddx_fine(input.positionRWS); + float3 dPdy = ddy_fine(input.positionRWS); + + float3 sigmaX = dPdx - dot(dPdx, vertexNormalWS) * vertexNormalWS; + float3 sigmaY = dPdy - dot(dPdy, vertexNormalWS) * vertexNormalWS; + //float flipSign = dot(sigmaY, cross(vertexNormalWS, sigmaX) ) ? -1.0 : 1.0; + float flipSign = dot(dPdy, cross(vertexNormalWS, dPdx)) < 0.0 ? -1.0 : 1.0; // gives same as the commented out line above + +#if defined(_REQUIRE_UV1) + SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord1.xy, uvMapping.vertexTangentWS, uvMapping.vertexBitangentWS); +#elif defined(_REQUIRE_UV2) + SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord2.xy, uvMapping.vertexTangentWS, uvMapping.vertexBitangentWS); +#elif defined(_REQUIRE_UV3) + SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord3.xy, uvMapping.vertexTangentWS, uvMapping.vertexBitangentWS); +#endif +#endif //#if (defined(_REQUIRE_UV1)||defined(_REQUIRE_UV2)||defined(_REQUIRE_UV3)) +} + +// Make sure lodBiasOrGrad is used statically! +// +#define AXF_SAMPLE_USE_LOD 1 +#define AXF_SAMPLE_USE_BIAS 2 +#define AXF_SAMPLE_USE_GRAD 3 + +// Note that scaleOffset are the texture specific ones, not the main material ones! +float4 AxfSampleTexture2D(TEXTURE2D_PARAM(textureName, samplerName), float4 scaleOffset, TextureUVMapping uvMapping, + int lodBiasOrGrad = 0, float3 lodOrBias = 0, float3x2 triDdx = (float3x2)0, float3x2 triDdy = (float3x2)0) +{ + bool useLod = lodBiasOrGrad == 1; + bool useBias = lodBiasOrGrad == 2; + bool useGrad = lodBiasOrGrad == 3; + bool useCachedDdxDdy = false; +#ifdef AXF_REUSE_SCREEN_DDXDDY + useCachedDdxDdy = false; +#endif + +#ifdef _MAPPING_TRIPLANAR + float4 val = 0; + + val += uvMapping.triplanarWeights.x + * ( useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), lodOrBias.x) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), lodOrBias.x) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), triDdx[0], triDdy[0]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), scaleOffset.xy * uvMapping.ddxZY, scaleOffset.xy * uvMapping.ddyZY) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset)) ); + val += uvMapping.triplanarWeights.y + * ( useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), lodOrBias.y) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), lodOrBias.y) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), triDdx[1], triDdy[1]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), scaleOffset.xy * uvMapping.ddxXZ, scaleOffset.xy * uvMapping.ddyXZ) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset)) ); + val += uvMapping.triplanarWeights.z + * ( useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), lodOrBias.z) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), lodOrBias.z) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), triDdx[2], triDdy[2]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), scaleOffset.xy * uvMapping.ddxXY, scaleOffset.xy * uvMapping.ddyXY) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset)) ); + + return val; +#else + return useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), lodOrBias.x) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), lodOrBias.x) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), triDdx[0], triDdy[0]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), scaleOffset.xy * uvMapping.ddxBase, scaleOffset.xy * uvMapping.ddyBase) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset)); +#endif +} + +// Normal map sampling requires special care especially for triplanar, we will use gradients for that. +// Also, AxF normal maps are encoded on 3 channels (xyz) but are still tangent space. +// Make sure useLod is used statically! +// Note that scaleOffset are the texture specific ones, not the main material ones! +float3 AxFSampleTexture2DNormalAsSurfaceGrad(TEXTURE2D_PARAM(textureName, samplerName), float4 scaleOffset, TextureUVMapping uvMapping, + int lodBiasOrGrad = 0, float3 lodOrBias = 0, float3x2 triDdx = (float3x2)0, float3x2 triDdy = (float3x2)0) +{ + float scale = 1.0; + bool useLod = lodBiasOrGrad == 1; + bool useBias = lodBiasOrGrad == 2; + bool useGrad = lodBiasOrGrad == 3; + bool useCachedDdxDdy = false; +#ifdef AXF_REUSE_SCREEN_DDXDDY + useCachedDdxDdy = true; +#endif + +#ifdef _MAPPING_TRIPLANAR + + float2 derivXplane; + float2 derivYPlane; + float2 derivZPlane; + float4 packedNormal; + derivXplane = derivYPlane = derivZPlane = float2(0.0, 0.0); + + // UnpackDerivativeNormalRGB will unpack an RGB tangent space normal map and output a corresponding height map gradient + // (We will sum those to get a volume gradient and from it a surface gradient (and/or a final normal). Both have 3 coordinates) + + packedNormal = useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), lodOrBias.x) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), lodOrBias.x) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), triDdx[0], triDdy[0]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset), scaleOffset.xy * uvMapping.ddxZY, scaleOffset.xy * uvMapping.ddyZY) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvZY, scaleOffset)); + derivXplane = uvMapping.triplanarWeights.x * AXF_DERIVATIVE_NORMAL(packedNormal, scale); + + packedNormal = useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), lodOrBias.y) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), lodOrBias.y) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), triDdx[1], triDdy[1]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset), scaleOffset.xy * uvMapping.ddxXZ, scaleOffset.xy * uvMapping.ddyXZ) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXZ, scaleOffset)); + derivYPlane = uvMapping.triplanarWeights.y * AXF_DERIVATIVE_NORMAL(packedNormal, scale); + + packedNormal = useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), lodOrBias.z) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), lodOrBias.z) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), triDdx[2], triDdy[2]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset), scaleOffset.xy * uvMapping.ddxXY, scaleOffset.xy * uvMapping.ddyXY) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvXY, scaleOffset)); + derivZPlane = uvMapping.triplanarWeights.z * AXF_DERIVATIVE_NORMAL(packedNormal, scale); + + // Important note! See SurfaceGradientFromTriplanarProjection: + // Tiling scales should NOT be negative! + + // Assume derivXplane, derivYPlane and derivZPlane sampled using (z,y), (z,x) and (x,y) respectively. + float3 volumeGrad = float3(derivZPlane.x + derivYPlane.y, derivZPlane.y + derivXplane.y, derivXplane.x + derivYPlane.x); + float3 surfaceGrad = SurfaceGradientFromVolumeGradient(uvMapping.vertexNormalWS, volumeGrad); + + // We don't need to process further operation on the gradient, but we dont resolve it to a normal immediately: + // ie by doing return SurfaceGradientResolveNormal(uvMapping.vertexNormalWS, surfaceGrad); + // This is because we use GetNormalWS() later which with #define SURFACE_GRADIENT, expects a surface gradient. + return surfaceGrad; + +#else + // No triplanar: in that case, just sample the texture, but also unpacks it as a surface gradient! See comment above + + float4 packedNormal = useLod ? SAMPLE_TEXTURE2D_LOD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), lodOrBias.x) + : useBias ? SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), lodOrBias.x) + : useGrad ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), triDdx[0], triDdy[0]) + : useCachedDdxDdy ? SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset), scaleOffset.xy * uvMapping.ddxBase, scaleOffset.xy * uvMapping.ddyBase) + : SAMPLE_TEXTURE2D(textureName, samplerName, AXF_TRANSFORM_TEXUV(uvMapping.uvBase, scaleOffset)); + float2 deriv = AXF_DERIVATIVE_NORMAL(packedNormal, scale); + +#ifndef _MAPPING_PLANAR + // No planar mapping, in that case, just use the generated (or simply cached if using uv0) TBN: + return SurfaceGradientFromTBN(deriv, uvMapping.vertexTangentWS, uvMapping.vertexBitangentWS); +#else + float3 volumeGrad; + + // We will use the mapping selector mask to know which plane we used. + // This allows us to properly build the volume gradient: + if (_MappingMask.x == 1.0) // uvZY + volumeGrad = float3(0.0, deriv.y, deriv.x); + else if (_MappingMask.y == 1.0) // uvXZ + volumeGrad = float3(deriv.y, 0.0, deriv.x); + else if (_MappingMask.z == 1.0) // uvXY + volumeGrad = float3(deriv.x, deriv.y, 0.0); + + return SurfaceGradientFromVolumeGradient(uvMapping.vertexNormalWS, volumeGrad); +#endif // if not _MAPPING_PLANAR +#endif // if triplanar. +} + +#define AXF_SAMPLE_TEXTURE2D(name, uvMapping) AxfSampleTexture2D(name, sampler##name, name##_SO, uvMapping) +#define AXF_SAMPLE_SMP_TEXTURE2D(name, samplername, uvMapping) AxfSampleTexture2D(name, samplername, name##_SO, uvMapping) +#define AXF_SAMPLE_SMP_TEXTURE2D_LOD(name, samplername, lod, uvMapping) AxfSampleTexture2D(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_LOD, lod) +#define AXF_SAMPLE_SMP_TEXTURE2D_BIAS(name, samplername, bias, uvMapping) AxfSampleTexture2D(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_BIAS, bias) + +#ifdef _MAPPING_TRIPLANAR +#define AXF_SAMPLE_SMP_TEXTURE2D_GRAD(name, samplername, triddx, triddy, uvMapping) AxfSampleTexture2D(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_GRAD, /*unused*/(float3)0, triddx, triddy) +#else +#define AXF_SAMPLE_SMP_TEXTURE2D_GRAD(name, samplername, vddx, vddy, uvMapping) AxfSampleTexture2D(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_GRAD, /*unused*/(float3)0, float3x2(vddx, (float2)0, (float2)0), float3x2(vddy, (float2)0, (float2)0)) +#endif + +#define AXF_SAMPLE_TEXTURE2D_NORMAL_AS_GRAD(name, uvMapping) AxFSampleTexture2DNormalAsSurfaceGrad(name, sampler##name, name##_SO, uvMapping) +#define AXF_SAMPLE_SMP_TEXTURE2D_NORMAL_AS_GRAD(name, samplername, uvMapping) AxFSampleTexture2DNormalAsSurfaceGrad(name, samplername, name##_SO, uvMapping) +#define AXF_SAMPLE_SMP_TEXTURE2D_LOD_NORMAL_AS_GRAD(name, samplername, lod, uvMapping) AxFSampleTexture2DNormalAsSurfaceGrad(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_LOD, lod) +#define AXF_SAMPLE_SMP_TEXTURE2D_BIAS_NORMAL_AS_GRAD(name, samplername, bias, uvMapping) AxFSampleTexture2DNormalAsSurfaceGrad(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_BIAS, bias) + +#ifdef _MAPPING_TRIPLANAR +#define AXF_SAMPLE_SMP_TEXTURE2D_GRAD_NORMAL_AS_GRAD(name, samplername, triddx, triddy, uvMapping) AxFSampleTexture2DNormalAsSurfaceGrad(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_GRAD, /*unused*/(float3)0, triddx, triddy) +#else +#define AXF_SAMPLE_SMP_TEXTURE2D_GRAD_NORMAL_AS_GRAD(name, samplername, vddx, vddy, uvMapping) AxFSampleTexture2DNormalAsSurfaceGrad(name, samplername, name##_SO, uvMapping, /*lodBiasOrGrad*/ AXF_SAMPLE_USE_GRAD, /*unused*/(float3)0, float3x2(vddx, (float2)0, (float2)0), float3x2(vddy, (float2)0, (float2)0)) +#endif + + +float2 TileFlakesUV(float2 flakesUV) +{ + // Create mirrored UVs to hide flakes tiling + // TODO_FLAKES: this isn't tiling! + if ((int(flakesUV.y) & 1) == 0) + flakesUV.x += 0.5; + else if ((uint(1000.0 + flakesUV.x) % 3) == 0) + flakesUV.y = 1.0 - flakesUV.y; + else + flakesUV.x = 1.0 - flakesUV.x; + + return flakesUV; +} + + +void SetFlakesSurfaceData(TextureUVMapping uvMapping, inout SurfaceData surfaceData) +{ + surfaceData.flakesDdxZY = surfaceData.flakesDdyZY = surfaceData.flakesDdxXZ = surfaceData.flakesDdyXZ = + surfaceData.flakesDdxXY = surfaceData.flakesDdyXY = 0; + +#ifdef _MAPPING_TRIPLANAR + float2 uv; + + uv = AXF_TRANSFORM_TEXUV_BYNAME(uvMapping.uvZY, _CarPaint2_BTFFlakeMap); + surfaceData.flakesMipLevelZY = CALCULATE_TEXTURE2D_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, uv); +#ifndef FLAKES_TILE_BEFORE_SCALE + surfaceData.flakesUVZY = TileFlakesUV(uv); +#else + surfaceData.flakesUVZY = AXF_TRANSFORM_TEXUV_BYNAME(TileFlakesUV(uvMapping.uvZY), _CarPaint2_BTFFlakeMap); +#endif + + uv = AXF_TRANSFORM_TEXUV_BYNAME(uvMapping.uvXZ, _CarPaint2_BTFFlakeMap); + surfaceData.flakesMipLevelXZ = CALCULATE_TEXTURE2D_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, uv); +#ifndef FLAKES_TILE_BEFORE_SCALE + surfaceData.flakesUVXZ = TileFlakesUV(uv); +#else + surfaceData.flakesUVXZ = AXF_TRANSFORM_TEXUV_BYNAME(TileFlakesUV(uvMapping.uvXZ), _CarPaint2_BTFFlakeMap); +#endif + + uv = AXF_TRANSFORM_TEXUV_BYNAME(uvMapping.uvXY, _CarPaint2_BTFFlakeMap); + surfaceData.flakesMipLevelXY = CALCULATE_TEXTURE2D_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, uv); +#ifndef FLAKES_TILE_BEFORE_SCALE + surfaceData.flakesUVXY = TileFlakesUV(uv); +#else + surfaceData.flakesUVXY = AXF_TRANSFORM_TEXUV_BYNAME(TileFlakesUV(uvMapping.uvXY), _CarPaint2_BTFFlakeMap); +#endif + + surfaceData.flakesTriplanarWeights = uvMapping.triplanarWeights; + +#ifdef FLAKES_USE_DDXDDY + // Filling surfaceData.flakesDdx* to nonzero values will automatically ignore surfaceData.flakesMipLevel* + // and the compiler will optimize them out (see SampleFlakes in AxF.hlsl) + surfaceData.flakesDdxZY = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddxZY, _CarPaint2_BTFFlakeMap); + surfaceData.flakesDdyZY = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddyZY, _CarPaint2_BTFFlakeMap); + surfaceData.flakesDdxXZ = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddxXZ, _CarPaint2_BTFFlakeMap); + surfaceData.flakesDdyXZ = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddyXZ, _CarPaint2_BTFFlakeMap); + surfaceData.flakesDdxXY = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddxXY, _CarPaint2_BTFFlakeMap); + surfaceData.flakesDdyXY = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddyXY, _CarPaint2_BTFFlakeMap); +#endif + +#else // TRIPLANAR + + float2 uv; + // NOTE: When not triplanar UVZY has one uv set or one planar coordinate set, + // and this planar coordinate set isn't necessarily ZY, we just reuse this field + // as a common one. + uv = AXF_TRANSFORM_TEXUV_BYNAME(uvMapping.uvBase, _CarPaint2_BTFFlakeMap); + surfaceData.flakesMipLevelZY = CALCULATE_TEXTURE2D_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, uv); +#ifndef FLAKES_TILE_BEFORE_SCALE + surfaceData.flakesUVZY = TileFlakesUV(uv); +#else + surfaceData.flakesUVZY = AXF_TRANSFORM_TEXUV_BYNAME(TileFlakesUV(uvMapping.uvBase), _CarPaint2_BTFFlakeMap); +#endif + +#ifdef FLAKES_USE_DDXDDY + // Filling surfaceData.flakesDdx* to nonzero values will automatically ignore surfaceData.flakesMipLevel* + // and the compiler will optimize them out (see SampleFlakes in AxF.hlsl) + surfaceData.flakesDdxZY = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddxBase, _CarPaint2_BTFFlakeMap); + surfaceData.flakesDdyZY = AXF_SCALE_DDXDDY_BYNAME(uvMapping.ddyBase, _CarPaint2_BTFFlakeMap); +#endif + + surfaceData.flakesUVXZ = surfaceData.flakesUVXY = 0; + surfaceData.flakesMipLevelXZ = surfaceData.flakesMipLevelXY = 0; + surfaceData.flakesTriplanarWeights = 0; +#endif +} void ApplyDecalToSurfaceData(DecalSurfaceData decalSurfaceData, inout SurfaceData surfaceData) { @@ -48,6 +464,29 @@ void ApplyDecalToSurfaceData(DecalSurfaceData decalSurfaceData, inout SurfaceDat #endif } +bool HasPhongTypeBRDF() +{ + uint type = ((_SVBRDF_BRDFType >> 1) & 7); + return type == 1 || type == 4; +} + +float2 AxFGetRoughnessFromSpecularLobeTexture(float2 specularLobe) +{ + // For Blinn-Phong, AxF encodes specularLobe.xy as log2(shiniExp_xy) so + // shiniExp = exp2(abs(specularLobe.xy)) + // A good fit for a corresponding Beckmann roughness is + // roughnessBeckmann^2 = 2 /(shiniExp + 2) + // See eg + // http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html + // http://simonstechblog.blogspot.com/2011/12/microfacet-brdf.html + + // We thus have + // roughnessBeckmann = sqrt(2) * rsqrt(exp2(abs(specularLobe.xy)) + 2); + // shiniExp = 2 * rcp(max(0.0001,(roughnessBeckmann*roughnessBeckmann))) - 2; + + return (HasPhongTypeBRDF() ? (sqrt(2) * rsqrt(exp2(abs(specularLobe)) + 2)) : specularLobe); +} + void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs posInput, out SurfaceData surfaceData, out BuiltinData builtinData) { #ifdef _DOUBLESIDED_ON @@ -58,62 +497,66 @@ void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs p ApplyDoubleSidedFlipOrMirror(input, doubleSidedConstants); // Apply double sided flip on the vertex normal - float2 UV0 = input.texCoord0.xy * _Material_SO.xy; + // Note that in uvMapping, the main scaling _Material_SO.xy has been applied: + TextureUVMapping uvMapping; + InitTextureUVMapping(input, uvMapping); + ZERO_INITIALIZE(SurfaceData, surfaceData); - //----------------------------------------------------------------------------- - // _AXF_BRDF_TYPE_SVBRDF - //----------------------------------------------------------------------------- + float alpha = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_AlphaMap, sampler_SVBRDF_AlphaMap, uvMapping).x; - float alpha = 1.0; +#ifdef _ALPHATEST_ON + // TODOTODO: Move alpha test earlier and test. + float alphaCutoff = _AlphaCutoff; + + #if SHADERPASS == SHADERPASS_SHADOWS + GENERIC_ALPHA_TEST(alpha, _UseShadowThreshold ? _AlphaCutoffShadow : alphaCutoff); + #else + GENERIC_ALPHA_TEST(alpha, alphaCutoff); + #endif +#endif surfaceData.ambientOcclusion = 1.0; surfaceData.specularOcclusion = 1.0; surfaceData.specularLobe = 0; + //----------------------------------------------------------------------------- + // _AXF_BRDF_TYPE_SVBRDF + //----------------------------------------------------------------------------- + #ifdef _AXF_BRDF_TYPE_SVBRDF - surfaceData.diffuseColor = - SAMPLE_TEXTURE2D(_SVBRDF_DiffuseColorMap, sampler_SVBRDF_DiffuseColorMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_DiffuseColorMap)).xyz; - surfaceData.specularColor = - SAMPLE_TEXTURE2D(_SVBRDF_SpecularColorMap, sampler_SVBRDF_SpecularColorMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_SpecularColorMap)).xyz; - surfaceData.specularLobe.xy = - _SVBRDF_SpecularLobeMapScale * SAMPLE_TEXTURE2D(_SVBRDF_SpecularLobeMap, sampler_SVBRDF_SpecularLobeMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_SpecularLobeMap)).xy; + surfaceData.diffuseColor = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_DiffuseColorMap, sampler_SVBRDF_DiffuseColorMap, uvMapping).xyz; + surfaceData.specularColor = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_SpecularColorMap, sampler_SVBRDF_SpecularColorMap, uvMapping).xyz; + surfaceData.specularLobe.xy = _SVBRDF_SpecularLobeMapScale * AxFGetRoughnessFromSpecularLobeTexture( + AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_SpecularLobeMap, sampler_SVBRDF_SpecularLobeMap, uvMapping).xy); // The AxF models include both a general coloring term that they call "specular color" while the f0 is actually another term, // seemingly always scalar: - surfaceData.fresnelF0 = SAMPLE_TEXTURE2D(_SVBRDF_FresnelMap, sampler_SVBRDF_FresnelMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_FresnelMap)).x; - surfaceData.height_mm = SAMPLE_TEXTURE2D(_SVBRDF_HeightMap, sampler_SVBRDF_HeightMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_HeightMap)).x * _SVBRDF_HeightMapMaxMM; + surfaceData.fresnelF0 = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_FresnelMap, sampler_SVBRDF_FresnelMap, uvMapping).x; + surfaceData.height_mm = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_HeightMap, sampler_SVBRDF_HeightMap, uvMapping).x * _SVBRDF_HeightMapMaxMM; // Our importer range remaps the [-HALF_PI, HALF_PI) range to [0,1). We map back here: surfaceData.anisotropyAngle = - HALF_PI * (2.0 * SAMPLE_TEXTURE2D(_SVBRDF_AnisoRotationMap, sampler_SVBRDF_AnisoRotationMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_AnisoRotationMap)).x - 1.0); - surfaceData.clearcoatColor = - SAMPLE_TEXTURE2D(_SVBRDF_ClearcoatColorMap, sampler_SVBRDF_ClearcoatColorMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_ClearcoatColorMap)).xyz; + HALF_PI * (2.0 * AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_AnisoRotationMap, sampler_SVBRDF_AnisoRotationMap, uvMapping).x - 1.0); + surfaceData.clearcoatColor = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_ClearcoatColorMap, sampler_SVBRDF_ClearcoatColorMap, uvMapping).xyz; // The importer transforms the IOR to an f0, we map it back here as an IOR clamped under at 1.0 // TODO: if we're reusing float textures anyway, we shouldn't need the normalization that transforming to an f0 provides. - float clearcoatF0 = SAMPLE_TEXTURE2D(_SVBRDF_ClearcoatIORMap, sampler_SVBRDF_ClearcoatIORMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_ClearcoatIORMap)).x; + float clearcoatF0 = AXF_SAMPLE_SMP_TEXTURE2D(_SVBRDF_ClearcoatIORMap, sampler_SVBRDF_ClearcoatIORMap, uvMapping).x; float sqrtF0 = sqrt(clearcoatF0); surfaceData.clearcoatIOR = max(1.0, (1.0 + sqrtF0) / (1.00001 - sqrtF0)); // We make sure it's working for F0=1 + // // TBN - GetNormalWS( - input, - 2.0 * SAMPLE_TEXTURE2D(_SVBRDF_NormalMap, sampler_SVBRDF_NormalMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_NormalMap)).xyz - 1.0, - surfaceData.normalWS, - doubleSidedConstants - ); - GetNormalWS( - input, - 2.0 * SAMPLE_TEXTURE2D(_ClearcoatNormalMap, sampler_ClearcoatNormalMap, AXF_TRANSFORM_TEXUV(UV0, _ClearcoatNormalMap)).xyz - 1.0, - surfaceData.clearcoatNormalWS, - doubleSidedConstants - ); - - alpha = SAMPLE_TEXTURE2D(_SVBRDF_AlphaMap, sampler_SVBRDF_AlphaMap, AXF_TRANSFORM_TEXUV(UV0, _SVBRDF_AlphaMap)).x; - - // Useless for SVBRDF - surfaceData.flakesUV = input.texCoord0.xy; - surfaceData.flakesMipLevel = 0.0; + // + // Note: since SURFACE_GRADIENT is enabled, resolve is done with input.tangentToWorld[2] in GetNormalWS(), + // and uvMapping uses that as vertexNormalWS. + + //Normal sampling: + GetNormalWS(input, AXF_SAMPLE_SMP_TEXTURE2D_NORMAL_AS_GRAD(_SVBRDF_NormalMap, sampler_SVBRDF_NormalMap, uvMapping).xyz, surfaceData.normalWS, doubleSidedConstants); + GetNormalWS(input, AXF_SAMPLE_SMP_TEXTURE2D_NORMAL_AS_GRAD(_ClearcoatNormalMap, sampler_ClearcoatNormalMap, uvMapping).xyz, surfaceData.clearcoatNormalWS, doubleSidedConstants); + + // Useless for SVBRDF, will be optimized out + //SetFlakesSurfaceData(uvMapping, surfaceData); //----------------------------------------------------------------------------- // _AXF_BRDF_TYPE_CAR_PAINT @@ -127,24 +570,9 @@ void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs p surfaceData.specularLobe = _CarPaint2_CTSpreads.xyz; // We may want to modify these (eg for Specular AA) surfaceData.normalWS = input.tangentToWorld[2].xyz; - GetNormalWS( - input, - 2.0 * SAMPLE_TEXTURE2D(_ClearcoatNormalMap, sampler_ClearcoatNormalMap, AXF_TRANSFORM_TEXUV(UV0, _ClearcoatNormalMap)).xyz - 1.0, - surfaceData.clearcoatNormalWS, - doubleSidedConstants - ); - - surfaceData.flakesUV = AXF_TRANSFORM_TEXUV(UV0, _CarPaint2_BTFFlakeMap); - surfaceData.flakesMipLevel = CALCULATE_TEXTURE2D_LOD(_CarPaint2_BTFFlakeMap, sampler_CarPaint2_BTFFlakeMap, surfaceData.flakesUV); + GetNormalWS(input, AXF_SAMPLE_SMP_TEXTURE2D_NORMAL_AS_GRAD(_ClearcoatNormalMap, sampler_ClearcoatNormalMap, uvMapping).xyz, surfaceData.clearcoatNormalWS, doubleSidedConstants); - // Create mirrored UVs to hide flakes tiling - // TODO_FLAKES: this isn't really tiling - if ((int(surfaceData.flakesUV.y) & 1) == 0) - surfaceData.flakesUV.x += 0.5; - else if ((uint(1000.0 + surfaceData.flakesUV.x) % 3) == 0) - surfaceData.flakesUV.y = 1.0 - surfaceData.flakesUV.y; - else - surfaceData.flakesUV.x = 1.0 - surfaceData.flakesUV.x; + SetFlakesSurfaceData(uvMapping, surfaceData); // Useless for car paint BSDF surfaceData.specularColor = 0; @@ -175,13 +603,18 @@ void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs p surfaceData.geomNormalWS = input.tangentToWorld[2]; // Finalize tangent space - surfaceData.tangentWS = input.tangentToWorld[0]; + surfaceData.tangentWS = uvMapping.vertexTangentWS; + // TODOTODO: + // This is crappy: anisotropy rotation don't mix triplanar style like scalar values because of what it represents. That's why in HDRP we use + // tangent space tangent vector maps and triplanar sample those as we do normals in the surface gradients framework! + // Better to rebuild a gradient in the proper space from each rotation, combine those gradients as normals and resolve here. if (HasAnisotropy()) { float3 tangentTS = float3(1, 0, 0); // We will keep anisotropyAngle in surfaceData for now for debug info, register will be freed // anyway by the compiler (never used again after this) sincos(surfaceData.anisotropyAngle, tangentTS.y, tangentTS.x); + float3x3 tbn = float3x3(uvMapping.vertexTangentWS, uvMapping.vertexBitangentWS, uvMapping.vertexNormalWS); surfaceData.tangentWS = TransformTangentToWorld(tangentTS, input.tangentToWorld); } @@ -203,17 +636,6 @@ void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs p // the handedness of the world space (tangentToWorld can be passed right handed while // Unity's WS is left handed, so this makes a difference here). -#ifdef _ALPHATEST_ON - // TODO: Move alpha test earlier and test. - float alphaCutoff = _AlphaCutoff; - - #if SHADERPASS == SHADERPASS_SHADOWS - GENERIC_ALPHA_TEST(alpha, _UseShadowThreshold ? _AlphaCutoffShadow : alphaCutoff); - #else - GENERIC_ALPHA_TEST(alpha, alphaCutoff); - #endif -#endif - #if defined(_ENABLE_GEOMETRIC_SPECULAR_AA) // Specular AA for geometric curvature diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFProperties.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFProperties.hlsl index d19ba0e0cad..59d7ab2b016 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFProperties.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxFProperties.hlsl @@ -51,6 +51,8 @@ SAMPLER(sampler_SVBRDF_ClearcoatIORMap); CBUFFER_START(UnityPerMaterial) + float4 _MappingMask; + // Scale/Offsets: float4 _Material_SO; // Main scale, TODO: scale - but not offset - could be moved to vertex shader and applied to uv0 diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDepthPass.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDepthPass.hlsl index 41073524c16..54d1d63f832 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDepthPass.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDepthPass.hlsl @@ -2,17 +2,60 @@ #error Undefine_SHADERPASS #endif -#ifdef _ALPHATEST_ON +// Attributes +#define REQUIRE_TANGENT_TO_WORLD defined(_PIXEL_DISPLACEMENT) +#define REQUIRE_NORMAL defined(TESSELLATION_ON) || REQUIRE_TANGENT_TO_WORLD || defined(_VERTEX_DISPLACEMENT) +#define REQUIRE_VERTEX_COLOR (defined(_VERTEX_DISPLACEMENT) || defined(_TESSELLATION_DISPLACEMENT) || (defined(LAYERED_LIT_SHADER) && (defined(_LAYER_MASK_VERTEX_COLOR_MUL) || defined(_LAYER_MASK_VERTEX_COLOR_ADD)))) + +// This first set of define allow to say which attributes will be use by the mesh in the vertex and domain shader (for tesselation) + +// Tesselation require normal +#if REQUIRE_NORMAL +#define ATTRIBUTES_NEED_NORMAL +#endif +#if REQUIRE_TANGENT_TO_WORLD +#define ATTRIBUTES_NEED_TANGENT +#endif +#if REQUIRE_VERTEX_COLOR +#define ATTRIBUTES_NEED_COLOR +#endif + +// About UV +// When UVX is present, we assume that UVX - 1 ... UV0 is present + +#if defined(_VERTEX_DISPLACEMENT) || REQUIRE_TANGENT_TO_WORLD || defined(_ALPHATEST_ON) || defined(_TESSELLATION_DISPLACEMENT) #define ATTRIBUTES_NEED_TEXCOORD0 #define ATTRIBUTES_NEED_TEXCOORD1 + #if defined(_REQUIRE_UV2) || defined(_REQUIRE_UV3) + #define ATTRIBUTES_NEED_TEXCOORD2 + #endif + #if defined(_REQUIRE_UV3) + #define ATTRIBUTES_NEED_TEXCOORD3 + #endif +#endif +// Varying - Use for pixel shader +// This second set of define allow to say which varyings will be output in the vertex (no more tesselation) +#if REQUIRE_TANGENT_TO_WORLD +#define VARYINGS_NEED_TANGENT_TO_WORLD +#endif + +#if REQUIRE_TANGENT_TO_WORLD || defined(_ALPHATEST_ON) #define VARYINGS_NEED_POSITION_WS // Required to get view vector and to get planar/triplanar mapping working #define VARYINGS_NEED_TEXCOORD0 #define VARYINGS_NEED_TEXCOORD1 - + #ifdef ATTRIBUTES_NEED_TEXCOORD2 + #define VARYINGS_NEED_TEXCOORD2 + #endif + #ifdef ATTRIBUTES_NEED_TEXCOORD3 + #define VARYINGS_NEED_TEXCOORD3 + #endif + #ifdef ATTRIBUTES_NEED_COLOR + #define VARYINGS_NEED_COLOR + #endif #elif defined(LOD_FADE_CROSSFADE) #define VARYINGS_NEED_POSITION_WS // Required to get view vector use in cross fade effect -#endif //..._ALPHATEST_ON +#endif // This include will define the various Attributes/Varyings structure #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl" diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDistortionPass.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDistortionPass.hlsl deleted file mode 100644 index 12a2bc95f54..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDistortionPass.hlsl +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SHADERPASS -#error Undefine_SHADERPASS -#endif - -// NEWLITTODO : Handling of TESSELATION, DISPLACEMENT, HEIGHTMAP, WIND - -#define ATTRIBUTES_NEED_TEXCOORD0 - -#define VARYINGS_NEED_TEXCOORD0 - -// This include will define the various Attributes/Varyings structure -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl" diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDistortionPass.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDistortionPass.hlsl.meta deleted file mode 100644 index b32a9b2863e..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/ShaderPass/AxFDistortionPass.hlsl.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 7d97a7af62e578b4fa1b4a687f9c91a1 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/GlobalPostProcessingQualitySettings.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/GlobalPostProcessingQualitySettings.cs index 5bee02315d9..f77d6923019 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/GlobalPostProcessingQualitySettings.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/GlobalPostProcessingQualitySettings.cs @@ -33,6 +33,11 @@ public ScalableSettingLevelParameter(int level, bool useOverride, bool overrideS } + internal static int GetScalableSettingLevelParameterValue(int level, bool useOverride) + { + return useOverride ? LevelCount : (int)level; + } + /// /// Level and Override. /// @@ -42,7 +47,7 @@ public ScalableSettingLevelParameter(int level, bool useOverride, bool overrideS set { var (level, useOverride) = value; - this.value = useOverride ? LevelCount : (int)level; + this.value = GetScalableSettingLevelParameterValue(level, useOverride); } } } diff --git a/com.unity.testing.graphics-performance/package.json b/com.unity.testing.graphics-performance/package.json index e0aeace4165..08bc947a33b 100644 --- a/com.unity.testing.graphics-performance/package.json +++ b/com.unity.testing.graphics-performance/package.json @@ -7,6 +7,7 @@ "description": "Provides performance framework helpers for writing tests for graphics code, such as test scene asset description, performance performance report and shader static analysis.", "keywords": ["qa", "test", "testing", "tests", "graphics", "performance"], "dependencies": { - "com.unity.test-framework.performance": "2.0.8-preview" + "com.unity.test-framework.performance": "2.0.8-preview", + "com.unity.shaderanalysis": "10.0.0-preview.1" } }