Rasagar/Library/PackageCache/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/MaterialPostProcessor.cs
2024-08-26 23:07:20 +03:00

1291 lines
65 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Callbacks;
using UnityEditor.Rendering.Analytics;
using UnityEditor.Rendering.HighDefinition.Analytics;
using UnityEngine;
using UnityEditor.ShaderGraph;
using UnityEngine.Rendering.HighDefinition;
using UnityEditor.Rendering.HighDefinition.ShaderGraph;
// Material property names
using static UnityEngine.Rendering.HighDefinition.HDMaterial;
using static UnityEngine.Rendering.HighDefinition.HDMaterialProperties;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.HighDefinition
{
class MaterialModificationProcessor : AssetModificationProcessor
{
static readonly string s_ShaderGraphExtensionMeta = $".{ShaderGraphImporter.Extension}.meta";
static readonly string s_ShaderGraphExtension = $".{ShaderGraphImporter.Extension}";
const string k_MaterialExtension = ".mat";
static void OnWillCreateAsset(string asset)
{
if (asset.HasExtension(k_MaterialExtension))
{
MaterialPostprocessor.s_CreatedAssets.Add(asset);
return;
}
// For .shadergraph assets, this is tricky since the callback will be for the .meta
// file only as we don't create it with AssetDatabase.CreateAsset but later AddObjectToAsset
// to the .shadergraph via the importer context.
// At the time the meta file is created, the .shadergraph is already present
// but Load*AtPAth(), GetMainAssetTypeAtPath() etc. won't find anything.
// The GUID is already present though, and we actually use those facts to infer we
// have a newly created shadergraph.
//
// HDMetaData subasset will be included after SG creation anyway so unlike for materials
// (cf .mat with AssetVersion in OnPostprocessAllAssets) we dont need to manually add a subasset.
// For adding them to MaterialPostprocessor.s_ImportedAssetThatNeedSaving for SaveAssetsToDisk()
// to make them editable (flag for checkout), we still detect those here, but not sure this is
// helpful as right now, even on re-import, a .shadergraph multijson is not rewritten, so only
// /Library side serialized data is actually changed (including the generated .shader that can
// also change which is why we run shadergraph reimports), and re-import from the same .shadergraph
// should be idempotent.
// In other words, there shouldn't be anything to checkout for the .shadergraph per se.
//
if (asset.HasExtension(s_ShaderGraphExtensionMeta))
{
var sgPath = System.IO.Path.ChangeExtension(asset, null);
var importer = AssetImporter.GetAtPath(sgPath);
var guid = AssetDatabase.AssetPathToGUID(sgPath);
if (!String.IsNullOrEmpty(guid) && importer == null)
{
MaterialPostprocessor.s_CreatedAssets.Add(sgPath);
return;
}
}
// Like stated above, doesnt happen:
if (asset.HasExtension(s_ShaderGraphExtension))
{
MaterialPostprocessor.s_CreatedAssets.Add(asset);
return;
}
}
}
class MaterialReimporter : Editor
{
static bool s_NeedToCheckProjSettingExistence = true;
static bool s_AutoReimportProjectShaderGraphsOnVersionUpdate = false;
internal static bool s_ReimportShaderGraphDependencyOnMaterialUpdate = true;
static internal void ReimportAllMaterials()
{
AssetReimportUtils.ReimportAll<Material>(out var duration, out var numberOfAssetsReimported);
AssetReimporterAnalytic.Send<Material>(duration, numberOfAssetsReimported);
MaterialPostprocessor.s_NeedsSavingAssets = true;
}
static internal void ReimportAllHDShaderGraphs()
{
AssetReimportUtils.ReimportAll<Shader>(out var duration, out var numberOfAssetsReimported, path => CheckHDShaderGraphVersionsForUpgrade(path));
AssetReimporterAnalytic.Send<Shader>(duration, numberOfAssetsReimported);
MaterialPostprocessor.s_NeedsSavingAssets = true;
}
internal static bool CheckHDShaderGraphVersionsForUpgrade(string assetPath, Shader shader = null, bool ignoreNonHDRPShaderGraphs = false)
{
bool upgradeNeeded = false;
shader = shader ?? (Shader)AssetDatabase.LoadAssetAtPath(assetPath, typeof(Shader));
if (ignoreNonHDRPShaderGraphs)
{
// Note: this might still be an HDRP shadergraph but old, without HDMetaData,
// eg using a masternode.
if (!HDShaderUtils.IsHDRPShaderGraph(shader))
{
return false;
}
}
else
{
if (!GraphUtil.IsShaderGraphAsset(shader))
return false;
}
GUID subTargetGUID;
if (shader.TryGetMetadataOfType<HDMetadata>(out var hdMetaData))
{
subTargetGUID = hdMetaData.subTargetGuid;
}
else
{
// If HDMetaData doesn't even exist, if it is an HDRP shadergraph,
// we're sure it's an old one (masternode based)
return true;
}
if (subTargetGUID.Empty())
{
upgradeNeeded = true;
// If subTargetGUID doesn't have any values, it means the SG was last imported
// pre-plugin materials aware, need upgrade
return upgradeNeeded;
}
bool isSubTargetPlugin = HDShaderUtils.GetMaterialPluginSubTarget(subTargetGUID, out IPluginSubTargetMaterialUtils subTargetMaterialUtils);
upgradeNeeded |= hdMetaData.hdSubTargetVersion < MigrationDescription.LastVersion<ShaderGraphVersion>();
if (isSubTargetPlugin)
{
// For potential subtarget-specific versioning - ie for plugin subtargets, a single version is enough:
// When the active subtarget is changed for the HDTarget, the shadergraph is thus reserialized and HDMetaData
// is also rewritten.
// This is in contrast with the subasset AssetVersion in materials having a dictionary of versions by GUID.
// This is needed because a shader can be changed on a material without any hooks to update it, so the material
// postprocessor which updates the .mat version on behalf of the shaders must make sure to not mis-interpret a version
// from a previous plugin shader. That's why the AssetVersion asset tracks a dictionary of current (material) versions
// by guid. (The .version field is of course the main HDRP versioning line as given by k_Migrations in MaterialPostProcessor)
upgradeNeeded |= (hdMetaData.subTargetSpecificVersion < subTargetMaterialUtils.latestSubTargetVersion);
}
return upgradeNeeded;
}
[InitializeOnLoadMethod]
static void RegisterUpgraderReimport()
{
EditorApplication.update += () =>
{
if (Time.renderedFrameCount > 0)
{
if (!HDRenderPipeline.isReady)
return;
bool reimportAllHDShaderGraphsTriggered = false;
bool reimportAllMaterialsTriggered = false;
bool fileExist = true;
// We check the file existence only once to avoid IO operations every frame.
if (s_NeedToCheckProjSettingExistence)
{
fileExist = System.IO.File.Exists(HDProjectSettings.filePath);
s_NeedToCheckProjSettingExistence = false;
}
//This method is called at opening and when HDRP package change (update of manifest.json)
int curMaterialVersion = HDProjectSettings.materialVersionForUpgrade;
bool scanMaterialsForUpgradeNeeded = (curMaterialVersion < MaterialPostprocessor.k_Migrations.Length)
|| (HDProjectSettings.pluginSubTargetLastSeenMaterialVersionsSum < HDShaderUtils.GetHDPluginSubTargetMaterialVersionsSum());
var curHDSubTargetVersion = HDProjectSettings.hdShaderGraphLastSeenVersion;
bool scanHDShaderGraphsForUpgradeNeeded = (curHDSubTargetVersion < MigrationDescription.LastVersion<ShaderGraphVersion>())
|| (HDProjectSettings.pluginSubTargetLastSeenSubTargetVersionsSum < HDShaderUtils.GetHDPluginSubTargetVersionsSum());
// First test if scan for shadergraph version upgrade might be needed (triggered through their importer)
// We do shadergraphs first as the HDMetaData object might need to be updated and the material update might depend
// on it.
// Note: this auto-update is disabled by default for now.
if (s_AutoReimportProjectShaderGraphsOnVersionUpdate && scanHDShaderGraphsForUpgradeNeeded)
{
string commandLineOptions = System.Environment.CommandLine;
bool inTestSuite = commandLineOptions.Contains("-testResults");
if (!inTestSuite && fileExist && !Application.isBatchMode)
{
EditorUtility.DisplayDialog("HDRP ShaderGraph scan for upgrade", "The ShaderGraphs with HDRP SubTarget in your Project were created using an older version of the High Definition Render Pipeline (HDRP)." +
" Unity must upgrade them to be compatible with your current version of HDRP. \n" +
" Unity will re-import all of the HDRP ShaderGraphs in your project, save them to disk, and check them out in source control if needed.\n" +
" Please see the Material upgrade guide in the HDRP documentation for more information.", "Ok");
}
// When we open a project from scratch all the material have been converted and we don't need to do it two time.
// However if we update with an open editor from the package manager we must call reimport.
// As we can't know, we are always calling reimport resulting in unecessary work when opening a project.
ReimportAllHDShaderGraphs();
reimportAllHDShaderGraphsTriggered = true;
}
// we do else here, as we want to first call SaveAssetsToDisk() for shadergraphs, as it updates the HDProjectSettings version sentinels
// (tocheck: it's probably safe to also do materials right after)
else if (scanMaterialsForUpgradeNeeded)
{
string commandLineOptions = System.Environment.CommandLine;
bool inTestSuite = commandLineOptions.Contains("-testResults");
if (!inTestSuite && fileExist && !Application.isBatchMode)
{
EditorUtility.DisplayDialog("HDRP Material upgrade", "The Materials in your Project were created using an older version of the High Definition Render Pipeline (HDRP)." +
" Unity must upgrade them to be compatible with your current version of HDRP. \n" +
" Unity will re-import all of the Materials in your project, save the upgraded Materials to disk, and check them out in source control if needed.\n" +
" Please see the Material upgrade guide in the HDRP documentation for more information.", "Ok");
}
// When we open a project from scratch all the material have been converted and we don't need to do it two time.
// However if we update with an open editor from the package manager we must call reimport.
// As we can't know, we are always calling reimport resulting in unecessary work when opening a project.
ReimportAllMaterials();
reimportAllMaterialsTriggered = true;
}
// Note: A reimport all above should really have gone through all .mat or .shadergraph, because the SaveAssetsToDisk() call will update
// our versions in HDProjectSettings on which we base the version change detection and trigger the scan for reimport.
// We can still have these two flags set at the same time, however, if the user multi-selects .mat and .shadergraph,
// as the MaterialPostProcessor.OnPostprocessAllAssets() will be called for both and set both of those flags if needed.
// This should be safe however since by the time we reach this point here, we already checked if we needed a re-import scan just
// above.
if (MaterialPostprocessor.s_NeedsSavingAssets)
{
MaterialPostprocessor.SaveAssetsToDisk(updateMaterialLastSeenVersions: reimportAllMaterialsTriggered, updateShaderGraphLastSeenVersions: reimportAllHDShaderGraphsTriggered);
reimportAllHDShaderGraphsTriggered = false;
reimportAllMaterialsTriggered = false;
}
}
};
}
}
class MaterialPostprocessor : AssetPostprocessor
{
internal static List<string> s_CreatedAssets = new List<string>();
internal static List<string> s_ImportedAssetThatNeedSaving = new List<string>();
internal static Dictionary<string, int> s_ImportedMaterialCounter = new Dictionary<string, int>();
internal static bool s_NeedsSavingAssets = false;
// Important: This should only be called by the RegisterUpgraderReimport(), ie the shadegraph/material version
// change detection and project rescan function since SaveAssetsToDisk() here will update the lastseen versions
// that the upgrader uses to detect version changes.
static internal void SaveAssetsToDisk(bool updateMaterialLastSeenVersions = true, bool updateShaderGraphLastSeenVersions = false)
{
foreach (var asset in s_ImportedAssetThatNeedSaving)
{
AssetDatabase.MakeEditable(asset);
}
AssetDatabase.SaveAssets();
//to prevent data loss, only update the last saved version trackers if user applied change and assets are written to
if (updateShaderGraphLastSeenVersions)
{
HDProjectSettings.hdShaderGraphLastSeenVersion = MigrationDescription.LastVersion<ShaderGraphVersion>();
HDProjectSettings.UpdateLastSeenSubTargetVersionsOfPluginSubTargets();
}
if (updateMaterialLastSeenVersions)
{
HDProjectSettings.materialVersionForUpgrade = MaterialPostprocessor.k_Migrations.Length;
HDProjectSettings.UpdateLastSeenMaterialVersionsOfPluginSubTargets();
}
s_ImportedAssetThatNeedSaving.Clear();
s_NeedsSavingAssets = false;
}
void OnPostprocessMaterial(Material material)
{
if (!HDShaderUtils.IsHDRPShader(material.shader, upgradable: true))
return;
HDShaderUtils.ResetMaterialKeywords(material);
}
static readonly string s_ShaderGraphExtensionMeta = $".{ShaderGraphImporter.Extension}.meta";
static readonly string s_ShaderGraphExtension = $".{ShaderGraphImporter.Extension}";
const string k_MaterialExtension = ".mat";
[RunAfterClass(typeof(HDRenderPipelineGlobalSettingsPostprocessor))]
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
using (var diffusionProfileRegisterer = new VolumeUtils.DiffusionProfileRegisterScope())
{
foreach (var asset in importedAssets)
{
// We intercept shadergraphs just to add them to s_ImportedAssetThatNeedSaving to make them editable when we save assets
if (asset.HasExtension(s_ShaderGraphExtension))
{
bool justCreated = s_CreatedAssets.Contains(asset);
if (!justCreated)
{
s_ImportedAssetThatNeedSaving.Add(asset);
s_NeedsSavingAssets = true;
}
else
{
s_CreatedAssets.Remove(asset);
}
continue;
}
else if (!asset.HasExtension(k_MaterialExtension))
continue;
// Materials (.mat) post processing
var material = (Material)AssetDatabase.LoadAssetAtPath(asset, typeof(Material));
if (material == null)
continue;
// Register Diffuse Profiles
diffusionProfileRegisterer.RegisterReferencedDiffusionProfilesFromMaterial(material);
if (MaterialReimporter.s_ReimportShaderGraphDependencyOnMaterialUpdate && GraphUtil.IsShaderGraphAsset(material.shader))
{
// Check first if the HDRP shadergraph assigned needs a migration:
// Here ignoreNonHDRPShaderGraphs = false is useful to not ignore non HDRP ShaderGraphs as
// the detection is based on the presence of the "HDMetaData" object and old HDRP ShaderGraphs don't have these,
// so we can conservatively force a re-import of any ShaderGraphs. Unity might not have reimported such ShaderGraphs
// based on declared source dependencies by the ShaderGraphImporter because these might have moved / changed
// for old ones. We can cover these cases here.
//
// Note we could also check this dependency in ReimportAllMaterials but in case a user manually re-imports a material,
// (ie the OnPostprocessAllAssets call here is not generated from ReimportAllMaterials())
// we would miss re-importing that dependency.
if (MaterialReimporter.CheckHDShaderGraphVersionsForUpgrade("", material.shader, ignoreNonHDRPShaderGraphs: false))
{
s_ImportedMaterialCounter.TryGetValue(asset, out var importCounter);
s_ImportedMaterialCounter[asset] = ++importCounter;
// CheckHDShaderGraphVersionsForUpgrade always return true if a ShaderGraph don't have an HDMetaData attached
// we need a check to avoid importing the same assets over and over again.
if (importCounter > 2)
continue;
var shaderPath = AssetDatabase.GetAssetPath(material.shader.GetInstanceID());
AssetDatabase.ImportAsset(shaderPath);
// Restart the material import instead of proceeding otherwise the shadergraph will be processed after
// (the above ImportAsset(shaderPath) returns before the actual re-importing taking place).
AssetDatabase.ImportAsset(asset);
continue;
}
}
if (!HDShaderUtils.IsHDRPShader(material.shader, upgradable: true))
continue;
(ShaderID id, GUID subTargetGUID) = HDShaderUtils.GetShaderIDsFromShader(material.shader);
var latestVersion = k_Migrations.Length;
bool isMaterialUsingPlugin = HDShaderUtils.GetMaterialPluginSubTarget(subTargetGUID, out IPluginSubTargetMaterialUtils subTargetMaterialUtils);
var wasUpgraded = false;
var assetVersions = AssetDatabase.LoadAllAssetsAtPath(asset);
AssetVersion assetVersion = null;
foreach (var subAsset in assetVersions)
{
if (subAsset != null && subAsset.GetType() == typeof(AssetVersion))
{
assetVersion = subAsset as AssetVersion;
break;
}
}
//subasset not found
if (!assetVersion)
{
wasUpgraded = true;
assetVersion = ScriptableObject.CreateInstance<AssetVersion>();
assetVersion.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.NotEditable;
if (s_CreatedAssets.Contains(asset))
{
//just created
s_CreatedAssets.Remove(asset);
assetVersion.version = latestVersion;
if (isMaterialUsingPlugin)
{
assetVersion.hdPluginSubTargetMaterialVersions.Add(subTargetGUID, subTargetMaterialUtils.latestMaterialVersion);
}
//[TODO: remove comment once fixed]
//due to FB 1175514, this not work. It is being fixed though.
//delayed call of the following work in some case and cause infinite loop in other cases.
AssetDatabase.AddObjectToAsset(assetVersion, asset);
// Init material in case it's used before an inspector window is opened
HDShaderUtils.ResetMaterialKeywords(material);
}
else
{
//asset exist prior migration
assetVersion.version = 0;
if (isMaterialUsingPlugin)
{
assetVersion.hdPluginSubTargetMaterialVersions.Add(subTargetGUID, (int)(PluginMaterial.GenericVersions.NeverMigrated));
}
AssetDatabase.AddObjectToAsset(assetVersion, asset);
}
}
// TODO: Maybe systematically remove from s_CreateAssets just in case
//upgrade
while (assetVersion.version >= 0 && assetVersion.version < latestVersion)
{
k_Migrations[assetVersion.version](material, id);
assetVersion.version++;
wasUpgraded = true;
}
if (isMaterialUsingPlugin)
{
int hdPluginMaterialVersion = (int)(PluginMaterial.GenericVersions.NeverMigrated);
bool neverMigrated = (assetVersion.hdPluginSubTargetMaterialVersions.Count == 0)
|| (false == assetVersion.hdPluginSubTargetMaterialVersions.TryGetValue(subTargetGUID, out hdPluginMaterialVersion));
if (neverMigrated)
{
assetVersion.hdPluginSubTargetMaterialVersions.Add(subTargetGUID, hdPluginMaterialVersion);
}
if (hdPluginMaterialVersion < subTargetMaterialUtils.latestMaterialVersion)
{
if (subTargetMaterialUtils.MigrateMaterial(material, hdPluginMaterialVersion))
{
assetVersion.hdPluginSubTargetMaterialVersions[subTargetGUID] = subTargetMaterialUtils.latestMaterialVersion;
wasUpgraded = true;
}
}
}
if (wasUpgraded)
{
EditorUtility.SetDirty(assetVersion);
s_ImportedAssetThatNeedSaving.Add(asset);
s_NeedsSavingAssets = true;
}
}
}
}
// Note: It is not possible to separate migration step by kind of shader
// used. This is due that user can change shader that material reflect.
// And when user do this, the material is not reimported and we have no
// hook on this event.
// So we must have migration step that work on every materials at once.
// Which also means that if we want to update only one shader, we need
// to bump all materials version...
static internal Action<Material, ShaderID>[] k_Migrations = new Action<Material, ShaderID>[]
{
StencilRefactor,
ZWriteForTransparent,
RenderQueueUpgrade,
ShaderGraphStack,
MoreMaterialSurfaceOptionFromShaderGraph,
AlphaToMaskUIFix,
MigrateDecalRenderQueue,
ExposedDecalInputsFromShaderGraph,
FixIncorrectEmissiveColorSpace,
ExposeRefraction,
MetallicRemapping,
ForceForwardEmissiveForDeferred,
UnlitStencilTag,
};
#region Migrations
//example migration method:
//static void Example(Material material, HDShaderUtils.ShaderID id)
//{
// const string kSupportDecals = "_SupportDecals";
// var serializedMaterial = new SerializedObject(material);
// if (!TryFindProperty(serializedMaterial, kSupportDecals, SerializedType.Integer, out var property, out _, out _))
// return;
// // Caution: order of operation is important, we need to keep the current value of the property (if done after it is 0)
// // then we remove it and apply the result
// // then we can modify the material (otherwise the material change are lost)
// bool supportDecal = property.floatValue == 1.0f;
// RemoveSerializedInt(serializedMaterial, kSupportDecals);
// serializedMaterial.ApplyModifiedProperties();
// // We need to reset the custom RenderQueue to take into account the move to specific RenderQueue for Opaque with Decal.
// // this should be handled correctly with reset below
// HDShaderUtils.ResetMaterialKeywords(material);
//}
//}
static void StencilRefactor(Material material, ShaderID id)
{
HDShaderUtils.ResetMaterialKeywords(material);
}
static void ZWriteForTransparent(Material material, ShaderID id)
{
// For transparent materials, the ZWrite property that is now used is _TransparentZWrite.
if (material.GetSurfaceType() == SurfaceType.Transparent)
material.SetFloat(kTransparentZWrite, material.GetZWrite() ? 1.0f : 0.0f);
HDShaderUtils.ResetMaterialKeywords(material);
}
#endregion
static void RenderQueueUpgrade(Material material, ShaderID id)
{
// Replace previous ray tracing render queue for opaque to regular opaque with raytracing
if (material.renderQueue == ((int)UnityEngine.Rendering.RenderQueue.GeometryLast + 20))
{
material.renderQueue = (int)HDRenderQueue.Priority.Opaque;
material.SetFloat(kRayTracing, 1.0f);
}
// Replace previous ray tracing render queue for transparent to regular transparent with raytracing
else if (material.renderQueue == 3900)
{
material.renderQueue = (int)HDRenderQueue.Priority.Transparent;
material.SetFloat(kRayTracing, 1.0f);
}
// In order for the ray tracing keyword to be taken into account, we need to make it dirty so that the parameter is created first
HDShaderUtils.ResetMaterialKeywords(material);
// For shader graphs, there is an additional pass we need to do
if (material.HasProperty("_RenderQueueType"))
{
int renderQueueType = (int)material.GetFloat("_RenderQueueType");
switch (renderQueueType)
{
// This was ray tracing opaque, should go back to opaque
case 3:
{
renderQueueType = 1;
}
break;
// If it was in the transparent range, reduce it by 1
case 4:
case 5:
case 6:
case 7:
{
renderQueueType = renderQueueType - 1;
}
break;
// If it was in the ray tracing transparent, should go back to transparent
case 8:
{
renderQueueType = renderQueueType - 4;
}
break;
// If it was in overlay should be reduced by 2
case 10:
{
renderQueueType = renderQueueType - 2;
}
break;
// background, opaque and AfterPostProcessOpaque are not impacted
default:
break;
}
// Push it back to the material
material.SetFloat("_RenderQueueType", (float)renderQueueType);
}
HDShaderUtils.ResetMaterialKeywords(material);
}
// properties in this tab should be properties from Unlit or PBR cross pipeline shader
// that are suppose to be synchronize with the Material during upgrade
readonly static string[] s_ShadergraphStackFloatPropertiesToSynchronize =
{
"_SurfaceType",
"_BlendMode",
"_DstBlend",
"_SrcBlend",
"_AlphaDstBlend",
"_AlphaSrcBlend",
"_AlphaCutoff",
"_AlphaCutoffEnable",
"_DoubleSidedEnable",
"_DoubleSidedNormalMode",
"_ZWrite", // Needed to fix older bug
"_RenderQueueType" // Needed as seems to not reset correctly
};
static void ShaderGraphStack(Material material, ShaderID id)
{
Shader shader = material.shader;
if (shader.IsShaderGraphAsset())
{
if (shader.TryGetMetadataOfType<HDMetadata>(out var obj))
{
// Material coming from old cross pipeline shader (Unlit and PBR) are not synchronize correctly with their
// shader graph. This code below ensure it is
if (obj.migrateFromOldCrossPipelineSG) // come from PBR or Unlit cross pipeline SG?
{
var defaultProperties = new Material(material.shader);
foreach (var floatToSync in s_ShadergraphStackFloatPropertiesToSynchronize)
if (material.HasProperty(floatToSync))
material.SetFloat(floatToSync, defaultProperties.GetFloat(floatToSync));
defaultProperties = null;
// Postprocess now that material is correctly sync
bool isTransparent = material.HasProperty("_SurfaceType") && material.GetFloat("_SurfaceType") > 0.0f;
bool alphaTest = material.HasProperty("_AlphaCutoffEnable") && material.GetFloat("_AlphaCutoffEnable") > 0.0f;
material.renderQueue = isTransparent ? (int)HDRenderQueue.Priority.Transparent :
alphaTest ? (int)HDRenderQueue.Priority.OpaqueAlphaTest : (int)HDRenderQueue.Priority.Opaque;
material.SetFloat("_RenderQueueType", isTransparent ? (float)HDRenderQueue.RenderQueueType.Transparent : (float)HDRenderQueue.RenderQueueType.Opaque);
}
}
}
HDShaderUtils.ResetMaterialKeywords(material);
}
static void MoreMaterialSurfaceOptionFromShaderGraph(Material material, ShaderID id)
{
if (material.IsShaderGraph())
{
// Synchronize properties we exposed from SG to the material
ResetFloatProperty(kReceivesSSR);
ResetFloatProperty(kReceivesSSRTransparent);
ResetFloatProperty(kEnableDecals);
ResetFloatProperty(kEnableBlendModePreserveSpecularLighting);
ResetFloatProperty(kTransparentWritingMotionVec);
ResetFloatProperty(kAddPrecomputedVelocity);
ResetFloatProperty(kDepthOffsetEnable);
}
void ResetFloatProperty(string propName)
{
int propIndex = material.shader.FindPropertyIndex(propName);
if (propIndex == -1)
return;
float defaultValue = material.shader.GetPropertyDefaultFloatValue(propIndex);
material.SetFloat(propName, defaultValue);
}
HDShaderUtils.ResetMaterialKeywords(material);
}
static void AlphaToMaskUIFix(Material material, ShaderID id)
{
// Not used anymore, alpha to mask option is removed
}
static void MigrateDecalRenderQueue(Material material, ShaderID id)
{
const string kSupportDecals = "_SupportDecals";
// Take the opportunity to remove _SupportDecals from Unlit as it is not suppose to be here
if (HDShaderUtils.IsUnlitHDRPShader(material.shader))
{
var serializedMaterial = new SerializedObject(material);
if (TryFindProperty(serializedMaterial, kSupportDecals, SerializedType.Integer, out var property, out _, out _))
{
RemoveSerializedInt(serializedMaterial, kSupportDecals);
serializedMaterial.ApplyModifiedProperties();
}
}
if (material.HasProperty(kSupportDecals))
{
bool supportDecal = material.GetFloat(kSupportDecals) > 0.0f;
if (supportDecal)
{
// Update material render queue to be in Decal render queue based on the value of decal property (see HDRenderQueue.cs)
if (material.renderQueue == ((int)UnityEngine.Rendering.RenderQueue.Geometry))
{
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry + 225;
}
else if (material.renderQueue == ((int)UnityEngine.Rendering.RenderQueue.AlphaTest))
{
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest + 25;
}
}
}
HDShaderUtils.ResetMaterialKeywords(material);
}
static void ExposedDecalInputsFromShaderGraph(Material material, ShaderID id)
{
if (id == ShaderID.Decal)
{
// In order for the new properties (kAffectsAlbedo...) to be taken into account, we need to make it dirty so that the parameter is created first
HDShaderUtils.ResetMaterialKeywords(material);
var serializedMaterial = new SerializedObject(material);
// Note: the property must not exist in the .shader for RemoveSerializedFloat to work (otherwise it will be re-added)
const string kAlbedoMode = "_AlbedoMode";
float albedoMode = 1.0f;
if (TryFindProperty(serializedMaterial, kAlbedoMode, SerializedType.Float, out var propertyAlbedoMode, out _, out _))
{
albedoMode = propertyAlbedoMode.floatValue;
RemoveSerializedFloat(serializedMaterial, kAlbedoMode);
}
// For normal map we don't remove the property _NormalMap but just check if there is a texture assign and then enable _AffectNormal
const string kNormalMap = "_NormalMap";
float normalMap = 0.0f;
if (TryFindProperty(serializedMaterial, kNormalMap, SerializedType.Texture, out var propertyNormalTexture, out _, out _))
{
normalMap = propertyNormalTexture.FindPropertyRelative("m_Texture").objectReferenceValue != null ? 1.0f : 0.0f;
}
// For normal map we don't remove the property _NormalMap but just check if there is a texture assign and then enable _AffectNormal
const string kMaskMap = "_MaskMap";
float maskMap = 0.0f;
if (TryFindProperty(serializedMaterial, kMaskMap, SerializedType.Texture, out var propertyMaskMapTexture, out _, out _))
{
maskMap = propertyMaskMapTexture.FindPropertyRelative("m_Texture").objectReferenceValue != null ? 1.0f : 0.0f;
}
const string kMaskmapMetal = "_MaskmapMetal";
float maskMapMetal = 0.0f;
if (TryFindProperty(serializedMaterial, kMaskmapMetal, SerializedType.Float, out var propertyMaskMapMetal, out _, out _))
{
maskMapMetal = propertyMaskMapMetal.floatValue;
RemoveSerializedFloat(serializedMaterial, kMaskmapMetal);
}
const string kMaskmapAO = "_MaskmapAO";
float maskMapAO = 0.0f;
if (TryFindProperty(serializedMaterial, kMaskmapAO, SerializedType.Float, out var propertyMaskMapAO, out _, out _))
{
maskMapAO = propertyMaskMapAO.floatValue;
RemoveSerializedFloat(serializedMaterial, kMaskmapAO);
}
const string kMaskmapSmoothness = "_MaskmapSmoothness";
float maskMapSmoothness = 0.0f;
if (TryFindProperty(serializedMaterial, kMaskmapSmoothness, SerializedType.Float, out var propertyMaskMapSmoothness, out _, out _))
{
maskMapSmoothness = propertyMaskMapSmoothness.floatValue;
RemoveSerializedFloat(serializedMaterial, kMaskmapSmoothness);
}
const string kEmissive = "_Emissive";
float emissive = 0.0f;
if (TryFindProperty(serializedMaterial, kEmissive, SerializedType.Float, out var propertyEmissive, out _, out _))
{
emissive = propertyEmissive.floatValue;
RemoveSerializedFloat(serializedMaterial, kEmissive);
}
// Not used anymore, just removed
const string kMaskBlendMode = "_MaskBlendMode";
if (TryFindProperty(serializedMaterial, kMaskBlendMode, SerializedType.Float, out var propertyUnused, out _, out _))
{
RemoveSerializedFloat(serializedMaterial, kMaskBlendMode);
}
serializedMaterial.ApplyModifiedProperties();
// Now apply old value to new properties
const string kAffectAlbedo = "_AffectAlbedo";
material.SetFloat(kAffectAlbedo, albedoMode);
const string kAffectNormal = "_AffectNormal";
material.SetFloat(kAffectNormal, normalMap);
const string kAffectSmoothness = "_AffectSmoothness";
material.SetFloat(kAffectSmoothness, maskMapSmoothness * maskMap);
const string kAffectMetal = "_AffectMetal";
material.SetFloat(kAffectMetal, maskMapMetal * maskMap);
const string kAffectAO = "_AffectAO";
material.SetFloat(kAffectAO, maskMapAO * maskMap);
const string kAffectEmission = "_AffectEmission";
material.SetFloat(kAffectEmission, emissive);
// We can't erase obsolete disabled pass from already existing Material, so we need to re-enable all of them
const string s_MeshDecalsMStr = "DBufferMesh_M";
const string s_MeshDecalsSStr = "DBufferMesh_S";
const string s_MeshDecalsMSStr = "DBufferMesh_MS";
const string s_MeshDecalsAOStr = "DBufferMesh_AO";
const string s_MeshDecalsMAOStr = "DBufferMesh_MAO";
const string s_MeshDecalsAOSStr = "DBufferMesh_AOS";
const string s_MeshDecalsMAOSStr = "DBufferMesh_MAOS";
const string s_MeshDecals3RTStr = "DBufferMesh_3RT";
const string s_MeshDecalsForwardEmissive = "Mesh_Emissive";
material.SetShaderPassEnabled(s_MeshDecalsMStr, true);
material.SetShaderPassEnabled(s_MeshDecalsSStr, true);
material.SetShaderPassEnabled(s_MeshDecalsMSStr, true);
material.SetShaderPassEnabled(s_MeshDecalsAOStr, true);
material.SetShaderPassEnabled(s_MeshDecalsMAOStr, true);
material.SetShaderPassEnabled(s_MeshDecalsAOSStr, true);
material.SetShaderPassEnabled(s_MeshDecalsMAOSStr, true);
material.SetShaderPassEnabled(s_MeshDecals3RTStr, true);
material.SetShaderPassEnabled(s_MeshDecalsForwardEmissive, true);
}
if (id == ShaderID.SG_Decal)
{
// We can't erase obsolete disabled pass from already existing Material, so we need to re-enable all of them
const string s_ShaderGraphMeshDecals4RT = "ShaderGraph_DBufferMesh4RT";
const string s_ShaderGraphMeshDecals3RT = "ShaderGraph_DBufferMesh3RT";
const string s_ShaderGraphMeshDecalForwardEmissive = "ShaderGraph_MeshEmissive";
material.SetShaderPassEnabled(s_ShaderGraphMeshDecals4RT, true);
material.SetShaderPassEnabled(s_ShaderGraphMeshDecals3RT, true);
material.SetShaderPassEnabled(s_ShaderGraphMeshDecalForwardEmissive, true);
}
if (id == ShaderID.Decal || id == ShaderID.SG_Decal)
{
HDShaderUtils.ResetMaterialKeywords(material);
}
}
static void FixIncorrectEmissiveColorSpace(Material material, ShaderID id)
{
// kEmissiveColorLDR wasn't correctly converted to linear color space.
// so here we adjust the value of kEmissiveColorLDR to compensate. But only if not using a HDR Color
const string kUseEmissiveIntensity = "_UseEmissiveIntensity";
if (material.HasProperty(kUseEmissiveIntensity) && material.GetInt(kUseEmissiveIntensity) == 1)
{
const string kEmissiveColorLDR = "_EmissiveColorLDR";
const string kEmissiveColor = "_EmissiveColor";
const string kEmissiveIntensity = "_EmissiveIntensity";
if (material.HasProperty(kEmissiveColorLDR) && material.HasProperty(kEmissiveIntensity) && material.HasProperty(kEmissiveColor))
{
// Important: The color picker for kEmissiveColorLDR is LDR and in sRGB color space but Unity don't perform any color space conversion in the color
// picker BUT only when sending the color data to the shader... So as we are doing our own calculation here in C#, we must do the conversion ourselves.
Color emissiveColorLDR = material.GetColor(kEmissiveColorLDR);
Color emissiveColorLDRsRGB = new Color(Mathf.LinearToGammaSpace(emissiveColorLDR.r), Mathf.LinearToGammaSpace(emissiveColorLDR.g), Mathf.LinearToGammaSpace(emissiveColorLDR.b));
material.SetColor(kEmissiveColorLDR, emissiveColorLDRsRGB);
}
// Reset the value of kEmissiveColor
material.UpdateEmissiveColorFromIntensityAndEmissiveColorLDR();
}
}
static void ExposeRefraction(Material material, ShaderID id)
{
// Lit SG now have a shader feature for refraction instead of an hardcoded material
if (id == ShaderID.SG_Lit)
{
// Sync the default refraction model from the shader graph to the shader
// We need to do this because the material may already have a refraction model information (from the Lit)
// In order to not break the rendering of the material, we patch the refraction model:
if (material.HasProperty(kRefractionModel))
{
var refractionModel = material.shader.GetPropertyDefaultFloatValue(material.shader.FindPropertyIndex(kRefractionModel));
material.SetFloat(kRefractionModel, refractionModel);
}
HDShaderUtils.ResetMaterialKeywords(material);
}
}
static void MetallicRemapping(Material material, ShaderID id)
{
const string kMetallicRemapMax = "_MetallicRemapMax";
// Lit shaders now have metallic remapping for the mask map
if (id == ShaderID.Lit || id == ShaderID.LitTesselation
|| id == ShaderID.LayeredLit || id == ShaderID.LayeredLitTesselation)
{
const string kMetallic = "_Metallic";
if (material.HasProperty(kMetallic) && material.HasProperty(kMetallicRemapMax))
{
var metallic = material.GetFloat(kMetallic);
material.SetFloat(kMetallicRemapMax, metallic);
}
}
else if (id == ShaderID.Decal)
{
HDShaderUtils.ResetMaterialKeywords(material);
var serializedMaterial = new SerializedObject(material);
const string kMetallicScale = "_MetallicScale";
float metallicScale = 1.0f;
if (TryFindProperty(serializedMaterial, kMetallicScale, SerializedType.Float, out var propertyMetallicScale, out _, out _))
{
metallicScale = propertyMetallicScale.floatValue;
RemoveSerializedFloat(serializedMaterial, kMetallicScale);
}
serializedMaterial.ApplyModifiedProperties();
material.SetFloat(kMetallicRemapMax, metallicScale);
}
}
// This function below is not used anymore - the code have been removed - however we must maintain the function to keep already converted Material coherent
// As it doesn't do anything special, there is no problem to let it
static void ForceForwardEmissiveForDeferred(Material material, ShaderID id)
{
// Force Forward emissive for deferred pass is only setup for Lit shader
if (id == ShaderID.SG_Lit || id == ShaderID.Lit || id == ShaderID.LitTesselation
|| id == ShaderID.LayeredLit || id == ShaderID.LayeredLitTesselation)
{
HDShaderUtils.ResetMaterialKeywords(material);
}
}
#region Serialization_API
//Methods in this region interact on the serialized material
//without filtering on what used shader knows
enum SerializedType
{
Boolean,
Integer,
Float,
Vector,
Color,
Texture
}
// do not use directly in migration function
static bool TryFindBase(SerializedObject material, SerializedType type, out SerializedProperty propertyBase)
{
propertyBase = material.FindProperty("m_SavedProperties");
switch (type)
{
case SerializedType.Boolean:
case SerializedType.Integer:
case SerializedType.Float:
propertyBase = propertyBase.FindPropertyRelative("m_Floats");
return true;
case SerializedType.Color:
case SerializedType.Vector:
propertyBase = propertyBase.FindPropertyRelative("m_Colors");
return true;
case SerializedType.Texture:
propertyBase = propertyBase.FindPropertyRelative("m_TexEnvs");
return true;
}
return false;
}
static SerializedProperty FindBase(SerializedObject material, SerializedType type)
{
if (!TryFindBase(material, type, out var propertyBase))
throw new ArgumentException($"Unknown SerializedType {type}");
return propertyBase;
}
// do not use directly in migration function
static bool TryFindProperty(SerializedObject material, string propertyName, SerializedType type, out SerializedProperty property, out int indexOf, out SerializedProperty propertyBase)
{
propertyBase = FindBase(material, type);
property = null;
int maxSearch = propertyBase.arraySize;
indexOf = 0;
for (; indexOf < maxSearch; ++indexOf)
{
property = propertyBase.GetArrayElementAtIndex(indexOf);
if (property.FindPropertyRelative("first").stringValue == propertyName)
break;
}
if (indexOf == maxSearch)
return false;
property = property.FindPropertyRelative("second");
return true;
}
static (SerializedProperty property, int index, SerializedProperty parent) FindProperty(SerializedObject material, string propertyName, SerializedType type)
{
if (!TryFindProperty(material, propertyName, type, out var property, out var index, out var parent))
throw new ArgumentException($"Unknown property: {propertyName}");
return (property, index, parent);
}
static Color GetSerializedColor(SerializedObject material, string propertyName)
=> FindProperty(material, propertyName, SerializedType.Color)
.property.colorValue;
static bool GetSerializedBoolean(SerializedObject material, string propertyName)
=> FindProperty(material, propertyName, SerializedType.Boolean)
.property.floatValue > 0.5f;
static int GetSerializedInt(SerializedObject material, string propertyName)
=> (int)FindProperty(material, propertyName, SerializedType.Integer)
.property.floatValue;
static Vector2Int GetSerializedVector2Int(SerializedObject material, string propertyName)
{
var property = FindProperty(material, propertyName, SerializedType.Vector).property;
return new Vector2Int(
(int)property.FindPropertyRelative("r").floatValue,
(int)property.FindPropertyRelative("g").floatValue);
}
static Vector3Int GetSerializedVector3Int(SerializedObject material, string propertyName)
{
var property = FindProperty(material, propertyName, SerializedType.Vector).property;
return new Vector3Int(
(int)property.FindPropertyRelative("r").floatValue,
(int)property.FindPropertyRelative("g").floatValue,
(int)property.FindPropertyRelative("b").floatValue);
}
static float GetSerializedFloat(SerializedObject material, string propertyName)
=> FindProperty(material, propertyName, SerializedType.Float)
.property.floatValue;
static Vector2 GetSerializedVector2(SerializedObject material, string propertyName)
{
var property = FindProperty(material, propertyName, SerializedType.Vector).property;
return new Vector2(
property.FindPropertyRelative("r").floatValue,
property.FindPropertyRelative("g").floatValue);
}
static Vector3 GetSerializedVector3(SerializedObject material, string propertyName)
{
var property = FindProperty(material, propertyName, SerializedType.Vector).property;
return new Vector3(
property.FindPropertyRelative("r").floatValue,
property.FindPropertyRelative("g").floatValue,
property.FindPropertyRelative("b").floatValue);
}
static Vector4 GetSerializedVector4(SerializedObject material, string propertyName)
{
var property = FindProperty(material, propertyName, SerializedType.Vector).property;
return new Vector4(
property.FindPropertyRelative("r").floatValue,
property.FindPropertyRelative("g").floatValue,
property.FindPropertyRelative("b").floatValue,
property.FindPropertyRelative("a").floatValue);
}
static (Texture texture, Vector2 scale, Vector2 offset) GetSerializedTexture(SerializedObject material, string propertyName)
{
var property = FindProperty(material, propertyName, SerializedType.Texture).property;
return (
property.FindPropertyRelative("m_Texture").objectReferenceValue as Texture,
property.FindPropertyRelative("m_Scale").vector2Value,
property.FindPropertyRelative("m_Offset").vector2Value);
}
static void RemoveSerializedColor(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Color);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedBoolean(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Boolean);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedInt(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Integer);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedVector2Int(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Vector);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedVector3Int(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Vector);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedFloat(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Float);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedVector2(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Vector);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedVector3(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Vector);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedVector4(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Vector);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void RemoveSerializedTexture(SerializedObject material, string propertyName)
{
var res = FindProperty(material, propertyName, SerializedType.Texture);
res.parent.DeleteArrayElementAtIndex(res.index);
}
static void AddSerializedColor(SerializedObject material, string name, Color value)
{
var propertyBase = FindBase(material, SerializedType.Color);
int lastPos = propertyBase.arraySize;
propertyBase.InsertArrayElementAtIndex(lastPos);
var newProperty = propertyBase.GetArrayElementAtIndex(lastPos);
newProperty.FindPropertyRelative("first").stringValue = name;
newProperty.FindPropertyRelative("second").colorValue = value;
}
static void AddSerializedBoolean(SerializedObject material, string name, bool value)
{
var propertyBase = FindBase(material, SerializedType.Boolean);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
newProperty.FindPropertyRelative("second").floatValue = value ? 1f : 0f;
}
static void AddSerializedInt(SerializedObject material, string name, int value)
{
var propertyBase = FindBase(material, SerializedType.Integer);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
newProperty.FindPropertyRelative("second").floatValue = value;
}
static void AddSerializedVector2Int(SerializedObject material, string name, Vector2Int value)
{
var propertyBase = FindBase(material, SerializedType.Vector);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("r").floatValue = value.x;
container.FindPropertyRelative("g").floatValue = value.y;
container.FindPropertyRelative("b").floatValue = 0;
container.FindPropertyRelative("a").floatValue = 0;
}
static void AddSerializedVector3Int(SerializedObject material, string name, Vector3Int value)
{
var propertyBase = FindBase(material, SerializedType.Vector);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("r").floatValue = value.x;
container.FindPropertyRelative("g").floatValue = value.y;
container.FindPropertyRelative("b").floatValue = value.z;
container.FindPropertyRelative("a").floatValue = 0;
}
static void AddSerializedFloat(SerializedObject material, string name, float value)
{
var propertyBase = FindBase(material, SerializedType.Float);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
newProperty.FindPropertyRelative("second").floatValue = value;
}
static void AddSerializedVector2(SerializedObject material, string name, Vector2 value)
{
var propertyBase = FindBase(material, SerializedType.Vector);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("r").floatValue = value.x;
container.FindPropertyRelative("g").floatValue = value.y;
container.FindPropertyRelative("b").floatValue = 0;
container.FindPropertyRelative("a").floatValue = 0;
}
static void AddSerializedVector3(SerializedObject material, string name, Vector3 value)
{
var propertyBase = FindBase(material, SerializedType.Vector);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("r").floatValue = value.x;
container.FindPropertyRelative("g").floatValue = value.y;
container.FindPropertyRelative("b").floatValue = value.z;
container.FindPropertyRelative("a").floatValue = 0;
}
static void AddSerializedVector4(SerializedObject material, string name, Vector4 value)
{
var propertyBase = FindBase(material, SerializedType.Vector);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("r").floatValue = value.x;
container.FindPropertyRelative("g").floatValue = value.y;
container.FindPropertyRelative("b").floatValue = value.z;
container.FindPropertyRelative("a").floatValue = value.w;
}
static void AddSerializedTexture(SerializedObject material, string name, Texture texture, Vector2 scale, Vector2 offset)
{
var propertyBase = FindBase(material, SerializedType.Texture);
propertyBase.InsertArrayElementAtIndex(0);
var newProperty = propertyBase.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = name;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("m_Texture").objectReferenceValue = texture;
container.FindPropertyRelative("m_Scale").vector2Value = scale;
container.FindPropertyRelative("m_Offset").vector2Value = offset;
}
static void RenameSerializedScalar(SerializedObject material, string oldName, string newName)
{
var res = FindProperty(material, oldName, SerializedType.Float);
var value = res.property.floatValue;
res.parent.InsertArrayElementAtIndex(0);
var newProperty = res.parent.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = newName;
newProperty.FindPropertyRelative("second").floatValue = value;
res.parent.DeleteArrayElementAtIndex(res.index + 1);
}
static void RenameSerializedVector(SerializedObject material, string oldName, string newName)
{
var res = FindProperty(material, oldName, SerializedType.Vector);
var valueX = res.property.FindPropertyRelative("r").floatValue;
var valueY = res.property.FindPropertyRelative("g").floatValue;
var valueZ = res.property.FindPropertyRelative("b").floatValue;
var valueW = res.property.FindPropertyRelative("a").floatValue;
res.parent.InsertArrayElementAtIndex(0);
var newProperty = res.parent.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = newName;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("r").floatValue = valueX;
container.FindPropertyRelative("g").floatValue = valueY;
container.FindPropertyRelative("b").floatValue = valueZ;
container.FindPropertyRelative("a").floatValue = valueW;
res.parent.DeleteArrayElementAtIndex(res.index + 1);
}
static void RenameSerializedTexture(SerializedObject material, string oldName, string newName)
{
var res = FindProperty(material, oldName, SerializedType.Texture);
var texture = res.property.FindPropertyRelative("m_Texture").objectReferenceValue;
var scale = res.property.FindPropertyRelative("m_Scale").vector2Value;
var offset = res.property.FindPropertyRelative("m_Offset").vector2Value;
res.parent.InsertArrayElementAtIndex(0);
var newProperty = res.parent.GetArrayElementAtIndex(0);
newProperty.FindPropertyRelative("first").stringValue = newName;
var container = newProperty.FindPropertyRelative("second");
container.FindPropertyRelative("m_Texture").objectReferenceValue = texture;
container.FindPropertyRelative("m_Scale").vector2Value = scale;
container.FindPropertyRelative("m_Offset").vector2Value = offset;
res.parent.DeleteArrayElementAtIndex(res.index + 1);
}
static void UnlitStencilTag(Material material, ShaderID id)
{
if (id == ShaderID.Unlit || id == ShaderID.SG_Unlit)
HDShaderUtils.ResetMaterialKeywords(material);
}
#endregion
}
}