StationObscurum/Assets/Adobe/Substance3DForUnity/Runtime/Scripts/Utilities/MaterialUtils.cs

396 lines
14 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Adobe.Substance
{
public static class MaterialUtils
{
/// <summary>
/// Default shader for the HDRP pipeline.
/// </summary>
private const string HDRPShaderName = "HDRP/Lit";
/// <summary>
/// Default shader for the URP pipeline.
/// </summary>
private const string URPShaderName = "Universal Render Pipeline/Lit";
/// <summary>
/// Default shader for the Standard unity render pipeline.
/// </summary>
private const string StandardShaderName = "Standard";
/// <summary>
/// Table for converting substance output names to textures inputs in HDRP shaders.
/// </summary>
private static readonly IReadOnlyDictionary<string, string> HDRPOutputTable = new Dictionary<string, string>()
{
{ "basecolor", "_BaseColorMap"},
{ "diffuse", "_BaseColorMap" },
{ "mask", "_MaskMap" },
{ "normal", "_NormalMap" },
{ "height", "_HeightMap" },
{ "emissive", "_EmissiveColorMap" },
{ "specular", "_SpecularColorMap" },
{ "detailMask", "_DetailMask" },
{ "opacity", "_OpacityMap" },
{ "glossiness", "_GlossinessMap" },
{ "ambientocclusion", "_OcclusionMap" },
{ "metallic", "_MetallicGlossMap" },
{ "roughness", "_RoughnessMap" }
};
/// <summary>
/// Table for converting substance output names to textures inputs in URP shaders.
/// </summary>
private static readonly IReadOnlyDictionary<string, string> URPOutputTable = new Dictionary<string, string>()
{
{ "basecolor" , "_BaseMap" },
{ "diffuse", "_BaseMap" },
{ "normal" , "_BumpMap" },
{ "height" ,"_ParallaxMap" },
{ "emissive" , "_EmissionMap" },
{ "specular" , "_SpecGlossMap" },
{ "ambientocclusion" , "_OcclusionMap" },
{ "metallic" , "_MetallicGlossMap" },
{ "mask" , "_MaskMap" },
{ "detailMask" , "_DetailMask" },
{ "opacity" ,"_OpacityMap" },
{ "glossiness" ,"_GlossinessMap" },
{ "roughness" ,"_RoughnessMap" }
};
/// <summary>
/// Table for converting substance output names to textures inputs in unity Standard pipeline shaders.
/// </summary>
private static readonly IReadOnlyDictionary<string, string> StandardOutputTable = new Dictionary<string, string>()
{
{ "basecolor", "_MainTex" },
{ "diffuse", "_MainTex" },
{ "normal" , "_BumpMap" },
{ "height" ,"_ParallaxMap" },
{ "emissive" ,"_EmissionMap" },
{ "specular" ,"_SpecGlossMap" },
{ "specularlevel" ,"_SpecularLevelMap" },
{ "opacity", "_OpacityMap" },
{ "glossiness" ,"_GlossinessMap" },
{ "ambientocclusion" ,"_OcclusionMap" },
{ "detailmask" ,"_DetailMask" },
{ "metallic" ,"_MetallicGlossMap" },
{ "roughness" ,"_RoughnessMap" }
};
private static IReadOnlyDictionary<string, string> GetTextureMappingDictionary()
{
if (PluginPipelines.IsHDRP())
return HDRPOutputTable;
if (PluginPipelines.IsURP())
return URPOutputTable; // for now
return StandardOutputTable;
}
public static void AssignOutputTexturesToMaterial(SubstanceGraphSO graph)
{
foreach (var output in graph.Output)
{
if (output.OutputTexture == null)
continue;
Texture2D texture = output.OutputTexture;
var shaderTextureName = output.MaterialTextureTarget;
EnableShaderKeywords(graph.OutputMaterial, shaderTextureName);
graph.OutputMaterial.SetTexture(shaderTextureName, texture);
}
var smoothnessChannel = GetSmoothnessChannelAssignment(graph);
graph.OutputMaterial.SetInt("_SmoothnessTextureChannel", smoothnessChannel);
graph.OutputMaterial.SetFloat("_Glossiness", 1.0f);
graph.OutputMaterial.SetFloat("_Smoothness", 1.0f);
graph.OutputMaterial.SetFloat("_OcclusionStrength", 1.0f);
var opacityOutput = graph.Output.FirstOrDefault(a => a.IsOpacity());
}
public static string GetUnityTextureName(SubstanceOutputDescription description)
{
var dictionary = GetTextureMappingDictionary();
if (dictionary.TryGetValue(description.Channel.ToLower(), out string result))
return result;
return string.Empty;
}
private static void EnableShaderKeywords(Material material, string shaderTextureName)
{
if (shaderTextureName == "_BumpMap")
{
material.EnableKeyword("_NORMALMAP");
}
else if (shaderTextureName == "_EmissionMap")
{
// Enables emission for the material, and make the material use
// realtime emission.
material.EnableKeyword("_EMISSION");
material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;
// Update the emission color and intensity of the material.
material.SetColor("_EmissionColor", Color.white);
// Inform Unity's GI system to recalculate GI based on the new emission map.
DynamicGI.UpdateEnvironment();
}
else if (shaderTextureName == "_ParallaxMap")
{
material.EnableKeyword("_PARALLAXMAP");
}
else if (shaderTextureName == "_MetallicGlossMap")
{
if (PluginPipelines.IsURP())
material.EnableKeyword("_METALLICSPECGLOSSMAP");
else
material.EnableKeyword("_METALLICGLOSSMAP");
}
}
/// <summary>
/// Returns 1 if smoothness is assigned to _MainTex alpha channel and 0 if it is assigned to metallic map alpha channel.
/// </summary>
/// <param name="graph">Target substance graph.</param>
/// <returns>0 or 1 depending on the smoothness channel assignment. </returns>
private static int GetSmoothnessChannelAssignment(SubstanceGraphSO graph)
{
var baseColorOutput = graph.Output.FirstOrDefault(a => a.IsBaseColor());
//Check if smoothness is assigned to baseColor.
if (baseColorOutput != null)
if (baseColorOutput.AlphaChannel == "roughness" || baseColorOutput.AlphaChannel == "glossiness")
return 1;
//Check if smoothness is assigned to diffuse.
var diffuseOutput = graph.Output.FirstOrDefault(a => a.IsDiffuse());
if (diffuseOutput != null)
if (diffuseOutput.AlphaChannel == "roughness" || diffuseOutput.AlphaChannel == "glossiness")
return 1;
//Assumes it is assinged to metallic map.
return 0;
}
public static bool CheckIfStandardOutput(SubstanceOutputDescription description)
{
if (PluginPipelines.IsHDRP())
{
return CheckIfHRPStandardOutput(description);
}
else if (PluginPipelines.IsURP())
{
return CheckIfURPStandardOutput(description);
}
//Unity Standard render pipeline.
return CheckIfStandardPipelineOutput(description);
}
private static bool CheckIfURPStandardOutput(SubstanceOutputDescription description)
{
if (description == null)
return false;
if (string.IsNullOrEmpty(description.Channel))
return false;
if (string.Equals(description.Channel, "baseColor", StringComparison.OrdinalIgnoreCase)
|| string.Equals(description.Channel, "diffuse", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (!URPOutputTable.TryGetValue(description.Channel, out string shaderValue))
return false;
var material = new Material(GetStandardShader());
return material.HasProperty(shaderValue);
}
private static bool CheckIfHRPStandardOutput(SubstanceOutputDescription description)
{
if (description == null)
return false;
if (string.IsNullOrEmpty(description.Channel))
return false;
switch (description.Channel)
{
case "baseColor":
return true;
case "normal":
return true;
case "mask":
return true;
case "height":
return true;
case "emissive":
return true;
default:
return false;
}
}
private static bool CheckIfStandardPipelineOutput(SubstanceOutputDescription description)
{
if (description == null)
return false;
if (string.IsNullOrEmpty(description.Channel))
return false;
var channel = description.Channel.ToLower();
if ("basecolor" == channel)
return true;
if (!StandardOutputTable.TryGetValue(channel, out string shaderValue))
return false;
var material = new Material(GetStandardShader());
return material.HasProperty(shaderValue);
}
public static Shader GetStandardShader()
{
if (PluginPipelines.IsHDRP())
return Shader.Find(HDRPShaderName);
else if (PluginPipelines.IsURP())
return Shader.Find(URPShaderName);
return Shader.Find(StandardShaderName);
}
public static bool CheckIfBGRA(SubstanceOutputDescription description)
{
if (Application.platform == RuntimePlatform.WindowsEditor
|| Application.platform == RuntimePlatform.WindowsPlayer)
{
return false;
}
if (Application.platform == RuntimePlatform.OSXEditor
|| Application.platform == RuntimePlatform.OSXPlayer)
{
return false;
}
switch (description.Channel)
{
case "baseColor":
case "diffuse":
case "emissive":
case "normal":
return true;
default:
return false;
}
}
#region PhysicalSize
public static void ApplyPhysicalSize(Material material, Vector3 physicalSize, bool enablePhysicalSize)
{
if (PluginPipelines.IsHDRP())
ApplyPhysicalSizeHDRP(material, physicalSize, enablePhysicalSize);
}
public static Vector3 GetPhysicalSizePositionOffset(Material material)
{
if (PluginPipelines.IsHDRP())
return GetPhysicalSizePositionOffsetHDRP(material);
return new Vector3(0, 0, 0);
}
public static void SetPhysicalSizePositionOffset(Material material, Vector3 offset)
{
if (PluginPipelines.IsHDRP())
SetPhysicalSizePositionOffsetHDRP(material, offset);
}
private static void ApplyPhysicalSizeHDRP(Material material, Vector3 physicalSize, bool enablePhysicalSize)
{
if (enablePhysicalSize)
{
material.SetFloat("_UVBase", 5);
material.SetFloat("_UVEmissive", 5);
material.SetFloat("_TexWorldScale", 100);
material.EnableKeyword("_MAPPING_PLANAR");
material.EnableKeyword("_EMISSIVE_MAPPING_TRIPLANAR");
material.mainTextureScale = new Vector2(1f / physicalSize.x, 1f / physicalSize.y);
}
else
{
material.SetFloat("_UVBase", 0);
material.SetFloat("_UVEmissive", 0);
material.SetFloat("_TexWorldScale", 1);
material.DisableKeyword("_MAPPING_PLANAR");
material.DisableKeyword("_EMISSIVE_MAPPING_TRIPLANAR");
material.mainTextureScale = new Vector2(1, 1);
}
}
public static Vector3 GetPhysicalSizePositionOffsetHDRP(Material material)
{
return material.GetTextureOffset("_BaseColorMap");
}
public static void SetPhysicalSizePositionOffsetHDRP(Material material, Vector3 offset)
{
material.SetTextureOffset("_BaseColorMap", offset);
material.SetTextureOffset("_EmissiveColorMap", offset);
}
#endregion PhysicalSize
#region Live output assignment
public static void UpdateTextureTarget(Material material, Texture2D texture, string oldstring, string newString)
{
material.SetTexture(oldstring, null);
if (!string.IsNullOrEmpty(newString))
material.SetTexture(newString, texture);
}
public static void EnableEmissionIfAssigned(Material material)
{
var emissionTextureName = GetTextureMappingDictionary()["emissive"];
if (material.GetTexture(emissionTextureName) != null)
{
material.EnableKeyword("_EMISSION");
material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;
material.SetColor("_EmissionColor", Color.white);
}
else
{
material.DisableKeyword("_EMISSION");
material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.EmissiveIsBlack;
material.SetColor("_EmissionColor", Color.black);
}
}
#endregion Live output assignment
}
}