312 lines
15 KiB
C#

using System;
using UnityEngine.Rendering.HighDefinition.Attributes;
//-----------------------------------------------------------------------------
// structure definition
//-----------------------------------------------------------------------------
namespace UnityEngine.Rendering.HighDefinition
{
class AxF : RenderPipelineMaterial
{
// Misc flags:
//
// Warning: first bits are those from the importer, make sure they match.
//
// Others are for further material customization.
// Note that contrary to the usual HDRP shaders' MaterialFeatureFlags,
// these are NOT necessarily known at static time since we haven't created
// shader features for each of them to then set eg surfaceData.materialFeatures.
// For this reason, these flags are set in the same shader property than used
// by the importer, _Flags.
// Some may become static shader_features later and thus become just UI state.
[GenerateHLSL(PackingRules.Exact)]
public enum FeatureFlags
{
AxfAnisotropy = 1 << 0,
AxfClearCoat = 1 << 1,
AxfClearCoatRefraction = 1 << 2,
AxfUseHeightMap = 1 << 3,
AxfBRDFColorDiagonalClamp = 1 << 4,
//Some TODO:
AxfHonorMinRoughness = 1 << 8,
AxfHonorMinRoughnessCoat = 1 << 9, // the X-Rite viewer never shows a specular highlight on coat for dirac lights
AxfDebugTest = 1 << 23,
//Experimental:
//
// Warning: don't go over 23, or need to use float and bitcast on the UI side, and in the shader,
// use float property/uniform and bitcast in hlsl code asuint()
};
//-----------------------------------------------------------------------------
// SurfaceData
//-----------------------------------------------------------------------------
// Main structure that store the user data (i.e user input of master node in material graph)
[GenerateHLSL(PackingRules.Exact, false, false, true, 1200)]
public struct SurfaceData
{
[MaterialSharedPropertyMapping(MaterialSharedProperty.Smoothness)]
[SurfaceDataAttributes("Smoothness", precision = FieldPrecision.Real)]
public float perceptualSmoothness; // approximated for raytracing stage
[MaterialSharedPropertyMapping(MaterialSharedProperty.AmbientOcclusion)]
[SurfaceDataAttributes("Ambient Occlusion")]
public float ambientOcclusion;
[SurfaceDataAttributes("Specular Occlusion")]
public float specularOcclusion;
[MaterialSharedPropertyMapping(MaterialSharedProperty.Normal)]
[SurfaceDataAttributes(new string[] { "Normal", "Normal View Space" }, true, checkIsNormalized = true)]
public Vector3 normalWS;
[SurfaceDataAttributes("Tangent", true)]
public Vector3 tangentWS;
// SVBRDF Variables
[MaterialSharedPropertyMapping(MaterialSharedProperty.Albedo)]
[SurfaceDataAttributes("Diffuse Color", false, true)]
public Vector3 diffuseColor;
[MaterialSharedPropertyMapping(MaterialSharedProperty.Specular)]
[SurfaceDataAttributes("Specular Color", false, true)]
public Vector3 specularColor;
[SurfaceDataAttributes("Fresnel F0")]
public Vector3 fresnelF0;
[SurfaceDataAttributes("Specular Lobe")]
public Vector3 specularLobe; // .xy for SVBRDF, .xyz for CARPAINT2, for _CarPaint2_CTSpreads per lobe roughnesses
[SurfaceDataAttributes("Height")]
public float height_mm;
[SurfaceDataAttributes("Anisotropic Angle")]
public float anisotropyAngle;
// Car Paint Variables
[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
[SurfaceDataAttributes("Clearcoat Color")]
public Vector3 clearcoatColor;
[SurfaceDataAttributes("Clearcoat Normal", true)]
public Vector3 clearcoatNormalWS;
[SurfaceDataAttributes("Clearcoat IOR")]
public float clearcoatIOR;
[SurfaceDataAttributes(new string[] { "Geometric Normal", "Geometric Normal View Space" }, true, checkIsNormalized = true)]
public Vector3 geomNormalWS;
// Needed for raytracing.
// TODO: should just modify FitToStandardLit in ShaderPassRaytracingGBuffer.hlsl and callee
// to have "V" (from -incidentDir)
[SurfaceDataAttributes("View Direction", true)]
public Vector3 viewWS;
};
//-----------------------------------------------------------------------------
// BSDFData
//-----------------------------------------------------------------------------
[GenerateHLSL(PackingRules.Exact, false, false, true, 1250)]
public struct BSDFData
{
public float ambientOcclusion;
public float specularOcclusion;
[SurfaceDataAttributes(new string[] { "Normal WS", "Normal View Space" }, true, checkIsNormalized = true)]
public Vector3 normalWS;
[SurfaceDataAttributes("", true)]
public Vector3 tangentWS;
[SurfaceDataAttributes("", true)]
public Vector3 biTangentWS;
// SVBRDF Variables
public Vector3 diffuseColor;
public Vector3 specularColor;
public Vector3 fresnelF0;
public float perceptualRoughness; // approximated for SSAO
public Vector3 roughness; // .xy for SVBRDF, .xyz for CARPAINT2, for _CarPaint2_CTSpreads per lobe roughnesses
public float height_mm;
// Car Paint Variables
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
// Clearcoat
public Vector3 clearcoatColor;
[SurfaceDataAttributes("", true)]
public Vector3 clearcoatNormalWS;
public float clearcoatIOR;
[SurfaceDataAttributes(new string[] { "Geometric Normal", "Geometric Normal View Space" }, true, checkIsNormalized = true)]
public Vector3 geomNormalWS;
};
//-----------------------------------------------------------------------------
// Init precomputed texture
//-----------------------------------------------------------------------------
// For area lighting - We pack all texture inside a texture array to reduce the number of resource required
Texture2DArray m_LtcData; // 0: m_LtcGGXMatrix - RGBA;
Material m_preIntegratedFGDMaterial_Ward = null;
Material m_preIntegratedFGDMaterial_CookTorrance = null;
RenderTexture m_preIntegratedFGD_Ward = null;
RenderTexture m_preIntegratedFGD_CookTorrance = null;
private bool m_precomputedFGDTablesAreInit = false;
public static readonly int _PreIntegratedFGD_Ward = Shader.PropertyToID("_PreIntegratedFGD_Ward");
public static readonly int _PreIntegratedFGD_CookTorrance = Shader.PropertyToID("_PreIntegratedFGD_CookTorrance");
public static readonly int _AxFLtcData = Shader.PropertyToID("_AxFLtcData");
public AxF() {}
public override void Build(HDRenderPipelineAsset hdAsset, RenderPipelineResources defaultResources)
{
// Create Materials
m_preIntegratedFGDMaterial_Ward = CoreUtils.CreateEngineMaterial(defaultResources.shaders.preIntegratedFGD_WardPS);
if (m_preIntegratedFGDMaterial_Ward == null)
throw new Exception("Failed to create material for Ward BRDF pre-integration!");
m_preIntegratedFGDMaterial_CookTorrance = CoreUtils.CreateEngineMaterial(defaultResources.shaders.preIntegratedFGD_CookTorrancePS);
if (m_preIntegratedFGDMaterial_CookTorrance == null)
throw new Exception("Failed to create material for Cook-Torrance BRDF pre-integration!");
// Create render textures where we will render the FGD tables
m_preIntegratedFGD_Ward = new RenderTexture(128, 128, 0, RenderTextureFormat.ARGB2101010, RenderTextureReadWrite.Linear);
m_preIntegratedFGD_Ward.hideFlags = HideFlags.HideAndDontSave;
m_preIntegratedFGD_Ward.filterMode = FilterMode.Bilinear;
m_preIntegratedFGD_Ward.wrapMode = TextureWrapMode.Clamp;
m_preIntegratedFGD_Ward.hideFlags = HideFlags.DontSave;
m_preIntegratedFGD_Ward.name = CoreUtils.GetRenderTargetAutoName(128, 128, 1, RenderTextureFormat.ARGB2101010, "PreIntegratedFGD_Ward");
m_preIntegratedFGD_Ward.Create();
m_preIntegratedFGD_CookTorrance = new RenderTexture(128, 128, 0, RenderTextureFormat.ARGB2101010, RenderTextureReadWrite.Linear);
m_preIntegratedFGD_CookTorrance.hideFlags = HideFlags.HideAndDontSave;
m_preIntegratedFGD_CookTorrance.filterMode = FilterMode.Bilinear;
m_preIntegratedFGD_CookTorrance.wrapMode = TextureWrapMode.Clamp;
m_preIntegratedFGD_CookTorrance.hideFlags = HideFlags.DontSave;
m_preIntegratedFGD_CookTorrance.name = CoreUtils.GetRenderTargetAutoName(128, 128, 1, RenderTextureFormat.ARGB2101010, "PreIntegratedFGD_CookTorrance");
m_preIntegratedFGD_CookTorrance.Create();
// LTC data
m_LtcData = new Texture2DArray(LTCAreaLight.k_LtcLUTResolution, LTCAreaLight.k_LtcLUTResolution, 3, TextureFormat.RGBAHalf, false /*mipmap*/, true /* linear */)
{
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Bilinear,
name = CoreUtils.GetTextureAutoName(LTCAreaLight.k_LtcLUTResolution, LTCAreaLight.k_LtcLUTResolution, TextureFormat.RGBAHalf, depth: 2, dim: TextureDimension.Tex2DArray, name: "LTC_LUT")
};
// Caution: This need to match order define in AxFLTCAreaLight
LTCAreaLight.LoadLUT(m_LtcData, 0, TextureFormat.RGBAHalf, LTCAreaLight.s_LtcMatrixData_GGX);
// Warning: check /Material/AxF/AxFLTCAreaLight/LtcData.GGX2.cs: 5 columns are needed, the entries are NOT normalized!
// For now, we patch for this in LoadLUT, which should affect the loading of s_LtcGGXMatrixData for the rest of the materials
// (Lit, etc.)
m_LtcData.Apply();
// TODO BugFix:
// We still bind the original data for now, see AxFLTCAreaLight.hlsl: when using a local table, results differ,
// even if we patch the non-normalization error in the 8th column when calling the LTCInvMatrix loading routine (LoadLUT).
LTCAreaLight.instance.Build();
}
public override void Cleanup()
{
CoreUtils.Destroy(m_preIntegratedFGD_CookTorrance);
CoreUtils.Destroy(m_preIntegratedFGD_Ward);
CoreUtils.Destroy(m_preIntegratedFGDMaterial_CookTorrance);
CoreUtils.Destroy(m_preIntegratedFGDMaterial_Ward);
m_preIntegratedFGD_CookTorrance = null;
m_preIntegratedFGD_Ward = null;
m_preIntegratedFGDMaterial_Ward = null;
m_preIntegratedFGDMaterial_CookTorrance = null;
m_precomputedFGDTablesAreInit = false;
// LTC data
CoreUtils.Destroy(m_LtcData);
LTCAreaLight.instance.Cleanup();
}
public override void RenderInit(CommandBuffer cmd)
{
if (m_precomputedFGDTablesAreInit || m_preIntegratedFGDMaterial_Ward == null || m_preIntegratedFGDMaterial_CookTorrance == null)
{
return;
}
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.PreIntegradeWardCookTorrance)))
{
CoreUtils.DrawFullScreen(cmd, m_preIntegratedFGDMaterial_Ward, new RenderTargetIdentifier(m_preIntegratedFGD_Ward));
CoreUtils.DrawFullScreen(cmd, m_preIntegratedFGDMaterial_CookTorrance, new RenderTargetIdentifier(m_preIntegratedFGD_CookTorrance));
}
m_precomputedFGDTablesAreInit = true;
}
public override void Bind(CommandBuffer cmd)
{
if (m_preIntegratedFGD_Ward == null || m_preIntegratedFGD_CookTorrance == null)
{
throw new Exception("Ward & Cook-Torrance BRDF pre-integration table not available!");
}
cmd.SetGlobalTexture(_PreIntegratedFGD_Ward, m_preIntegratedFGD_Ward);
cmd.SetGlobalTexture(_PreIntegratedFGD_CookTorrance, m_preIntegratedFGD_CookTorrance);
// LTC Data
cmd.SetGlobalTexture(_AxFLtcData, m_LtcData);
LTCAreaLight.instance.Bind(cmd);
}
}
}