2021-09-09 20:42:29 -04:00

232 lines
11 KiB
C#

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Rendering.HighDefinition
{
sealed partial class DiffusionProfileSettings : IVersionable<DiffusionProfileSettings.Version>
{
enum Version
{
Initial, // 16 profiles per asset
DiffusionProfileRework, // one profile per asset
}
[Obsolete("Profiles are obsolete, only one diffusion profile per asset is allowed.")]
internal DiffusionProfile this[int index]
{
get => profile;
}
[SerializeField]
Version m_Version = MigrationDescription.LastVersion<Version>();
Version IVersionable<Version>.version { get => m_Version; set => m_Version = value; }
[Obsolete("Profiles are obsolete, only one diffusion profile per asset is allowed.")]
internal DiffusionProfile[] profiles;
static readonly MigrationDescription<Version, DiffusionProfileSettings> k_Migration = MigrationDescription.New(
MigrationStep.New(Version.DiffusionProfileRework, (DiffusionProfileSettings d) =>
{
#pragma warning disable 618
#if UNITY_EDITOR
if (d.profiles == null)
return;
// If the asset importer for the asset we're upgrading is null, it means that the asset
// does not exists on the disk and we don't want to upgrade these assets
string assetPath = AssetDatabase.GetAssetPath(d);
var importer = AssetImporter.GetAtPath(assetPath);
if (importer == null)
return;
var currentHDAsset = HDRenderPipeline.currentAsset;
if (currentHDAsset == null)
throw new Exception("Can't upgrade diffusion profile when the HDRenderPipeline asset is not assigned in Graphic Settings");
var defaultProfile = new DiffusionProfile(true);
// Iterate over the diffusion profile settings and generate one new asset for each
// diffusion profile which have been modified, and store them into a dictionary to be able to upgrade materials
int index = 0;
var newProfiles = new Dictionary<int, DiffusionProfileSettings>();
string assetName = Path.GetFileNameWithoutExtension(assetPath);
foreach (var profile in d.profiles)
{
if (!profile.Equals(defaultProfile))
{
newProfiles[index] = CreateNewDiffusionProfile(d, assetName, profile, index);
// Update the diffusion profile hash is required for assets that are upgraded because it will
// be assigned to materials right after the create of the asset so we don't wait for the auto hash update
UnityEditor.Rendering.HighDefinition.DiffusionProfileHashTable.UpdateDiffusionProfileHashNow(newProfiles[index]);
}
index++;
}
// We write in the main diffusion profile meta filethe list of created asset so we know where to look
// when we upgrade materials inside scenes (from the menu item)
SerializableGUIDs toJson;
toJson.assetGUIDs = new string[16];
foreach (var kp in newProfiles)
toJson.assetGUIDs[kp.Key] = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(kp.Value));
importer.userData = JsonUtility.ToJson(toJson);
// Update the diffusion profiles references in all the hd assets where this profile was set
var hdAssetsGUIDs = AssetDatabase.FindAssets("t:HDRenderPipelineAsset");
foreach (var hdAssetGUID in hdAssetsGUIDs)
{
var hdAsset = AssetDatabase.LoadAssetAtPath<HDRenderPipelineAsset>(AssetDatabase.GUIDToAssetPath(hdAssetGUID));
if (hdAsset.diffusionProfileSettings == d)
{
// Assign the new diffusion profile assets into the HD asset
hdAsset.diffusionProfileSettingsList = new DiffusionProfileSettings[newProfiles.Keys.Max() + 1];
foreach (var kp in newProfiles)
hdAsset.diffusionProfileSettingsList[kp.Key] = kp.Value;
UnityEditor.EditorUtility.SetDirty(hdAsset);
}
}
// If the diffusion profile settings we're upgrading was assigned to the HDAsset in use
// then we need to go over all materials and upgrade them
if (currentHDAsset.diffusionProfileSettings == d)
{
var materialGUIDs = AssetDatabase.FindAssets("t:Material");
foreach (var guid in materialGUIDs)
{
var mat = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(guid));
UpgradeMaterial(mat, d);
}
}
#endif
#pragma warning restore 618
})
);
#if UNITY_EDITOR
public static void UpgradeMaterial(Material mat, DiffusionProfileSettings mainProfile)
{
UpgradeMaterial(mat, mainProfile, "_DiffusionProfile", "_DiffusionProfileAsset", "_DiffusionProfileHash");
// For layered material:
UpgradeMaterial(mat, mainProfile, "_DiffusionProfile0", "_DiffusionProfileAsset0", "_DiffusionProfileHash0");
UpgradeMaterial(mat, mainProfile, "_DiffusionProfile1", "_DiffusionProfileAsset1", "_DiffusionProfileHash1");
UpgradeMaterial(mat, mainProfile, "_DiffusionProfile2", "_DiffusionProfileAsset2", "_DiffusionProfileHash2");
UpgradeMaterial(mat, mainProfile, "_DiffusionProfile3", "_DiffusionProfileAsset3", "_DiffusionProfileHash3");
}
[System.Serializable]
struct SerializableGUIDs
{
[SerializeField]
public string[] assetGUIDs;
}
static void UpgradeMaterial(Material mat, DiffusionProfileSettings mainProfile, string diffusionProfile, string diffusionProfileAsset, string diffusionProfileHash)
{
// if the material don't have a diffusion profile
if (!mat.HasProperty(diffusionProfile) || !mat.HasProperty(diffusionProfileAsset) || !mat.HasProperty(diffusionProfileHash))
return;
// We can't upgrade materials if the diffusion profile is null
if (mainProfile == null)
return;
// or if it already have been upgraded
int index = mat.GetInt(diffusionProfile) - 1; // the index in the material is stored with +1 because 0 is none
if (index < 0)
return;
mat.SetInt(diffusionProfile, -1);
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(mainProfile));
SerializableGUIDs profiles = JsonUtility.FromJson<SerializableGUIDs>(importer.userData);
if (String.IsNullOrEmpty(profiles.assetGUIDs ? [index]))
{
Debug.LogError("Could not upgrade diffusion profile reference in material " + mat + ": index " + index + " not found in main diffusion profile");
return;
}
string diffusionProfileGUID = profiles.assetGUIDs[index];
var newProfile = AssetDatabase.LoadAssetAtPath<DiffusionProfileSettings>(AssetDatabase.GUIDToAssetPath(diffusionProfileGUID));
mat.SetVector(diffusionProfileAsset, HDUtils.ConvertGUIDToVector4(diffusionProfileGUID));
mat.SetFloat(diffusionProfileHash, HDShadowUtils.Asfloat(newProfile.profile.hash));
if (newProfile.profile.hash == 0)
Debug.LogError("Diffusion profile hash of " + newProfile + " have not been initialized !");
if (mat.shader.name.StartsWith("HDRP/"))
{
// Set the reference value for the stencil test.
int stencilRef = (int)StencilUsage.Clear;
int stencilWriteMask = (int)StencilUsage.RequiresDeferredLighting | (int)StencilUsage.SubsurfaceScattering;
int stencilGBufferRef = (int)StencilUsage.RequiresDeferredLighting;
int stencilGBufferMask = (int)StencilUsage.RequiresDeferredLighting | (int)StencilUsage.SubsurfaceScattering;
if (mat.HasProperty("_MaterialID") && (int)mat.GetFloat("_MaterialID") == 0) // 0 is MaterialId.LitSSS
{
stencilRef = (int)StencilUsage.SubsurfaceScattering;
stencilGBufferRef |= (int)StencilUsage.SubsurfaceScattering;
}
if (mat.HasProperty("_ReceivesSSR") && mat.GetInt("_ReceivesSSR") == 1)
{
stencilWriteMask |= (int)StencilUsage.TraceReflectionRay;
stencilRef |= (int)StencilUsage.TraceReflectionRay;
stencilGBufferMask |= (int)StencilUsage.TraceReflectionRay;
stencilGBufferRef |= (int)StencilUsage.TraceReflectionRay;
}
// As we tag both during motion vector pass and Gbuffer pass we need a separate state and we need to use the write mask
mat.SetInt("_StencilRef", stencilRef);
mat.SetInt("_StencilWriteMask", stencilWriteMask);
mat.SetInt("_StencilRefGBuffer", stencilGBufferRef);
mat.SetInt("_StencilWriteMaskGBuffer", stencilGBufferMask);
mat.SetInt("_StencilRefMV", (int)StencilUsage.ObjectMotionVector);
mat.SetInt("_StencilWriteMaskMV", (int)StencilUsage.ObjectMotionVector);
}
}
static DiffusionProfileSettings CreateNewDiffusionProfile(DiffusionProfileSettings asset, string assetName, DiffusionProfile profile, int index)
{
var path = AssetDatabase.GetAssetPath(asset);
path = Path.GetDirectoryName(path) + "/" + assetName + Path.GetExtension(path);
path = AssetDatabase.GenerateUniqueAssetPath(path);
if (index == 0)
{
asset.profile = profile;
profile.Validate();
asset.UpdateCache();
AssetDatabase.MoveAsset(AssetDatabase.GetAssetPath(asset), path);
return asset;
}
var newDiffusionProfile = ScriptableObject.CreateInstance<DiffusionProfileSettings>();
newDiffusionProfile.name = asset.name;
newDiffusionProfile.profile = profile;
newDiffusionProfile.m_Version = Version.DiffusionProfileRework;
profile.Validate();
newDiffusionProfile.UpdateCache();
AssetDatabase.CreateAsset(newDiffusionProfile, path);
return newDiffusionProfile;
}
public void TryToUpgrade()
{
if (k_Migration.Migrate(this))
{
UnityEditor.EditorUtility.SetDirty(this);
UnityEditor.AssetDatabase.SaveAssets();
// Do not refresh the database now because it will force the reimport of all new diffusion profile settings
EditorApplication.delayCall += UnityEditor.AssetDatabase.Refresh;
}
}
#endif
}
}