diff --git a/Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs b/Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs new file mode 100644 index 00000000..5c14ea79 --- /dev/null +++ b/Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs @@ -0,0 +1,25 @@ +using UnityEngine.Rendering; + +namespace ReadyPlayerMe.Core.Editor +{ + public static class ShaderVariantConstants + { + public static ShaderVariantData[] Variants = new [] + { + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN _ALPHATEST_ON" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN _EMISSION _METALLICGLOSSMAP" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN _EMISSION _METALLICGLOSSMAP _NORMALMAP" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN _METALLICGLOSSMAP _NORMALMAP" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN _METALLICGLOSSMAP _NORMALMAP _OCCLUSION" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN _NORMALMAP" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ForwardBase, "DIRECTIONAL LIGHTPROBE_SH _ALPHABLEND_ON" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ShadowCaster, "SHADOWS_DEPTH" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ShadowCaster, "SHADOWS_DEPTH _ALPHABLEND_ON" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ShadowCaster, "SHADOWS_DEPTH _ALPHATEST_ON" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ShadowCaster, "SHADOWS_DEPTH _METALLICGLOSSMAP" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ShadowCaster, "SHADOWS_DEPTH _METALLICGLOSSMAP _OCCLUSION" ), + new ShaderVariantData("glTF/PbrMetallicRoughness", PassType.ShadowCaster, "_METALLICGLOSSMAP _OCCLUSION" ), + }; + } +} diff --git a/Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs.meta b/Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs.meta new file mode 100644 index 00000000..44759b75 --- /dev/null +++ b/Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3618da9f59bf4a34db4895ae8524b8e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Core/Scripts/Utilities/ShaderVariantTool.cs b/Editor/Core/Scripts/Utilities/ShaderVariantTool.cs new file mode 100644 index 00000000..fcb976a7 --- /dev/null +++ b/Editor/Core/Scripts/Utilities/ShaderVariantTool.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; + +namespace ReadyPlayerMe.Core.Editor +{ + [System.Serializable] + public struct ShaderVariantData + { + public string ShaderName; + public PassType PassType; + public string Keywords; + + public ShaderVariantData(string shaderName, PassType passType, string keywords) + { + ShaderName = shaderName; + PassType = passType; + Keywords = keywords; + } + } + + public class ShaderVariantTool + { + public List ShaderVariants { get; private set; } = new List(); + + /// + /// Reads the shader variants from a ShaderVariantCollection asset. + /// + /// The ShaderVariantCollection asset to load from. + public void ReadShaderVariantsFromCollection(ShaderVariantCollection variantCollection) + { + ShaderVariants.Clear(); // Clear any existing data + try + { + var serializedObject = new SerializedObject(variantCollection); + var shaderArrayProperty = serializedObject.FindProperty("m_Shaders"); + + if (shaderArrayProperty == null) + { + Debug.Log("Error: Unable to find Shaders in the ShaderVariantCollection."); + return; + } + + for (int i = 0; i < shaderArrayProperty.arraySize; i++) + { + var shaderProperty = shaderArrayProperty.GetArrayElementAtIndex(i); + var shaderReferenceProp = shaderProperty.FindPropertyRelative("first"); + var shader = shaderReferenceProp.objectReferenceValue as Shader; + + if (shader == null) + { + Debug.LogError("Shader not found."); + continue; + } + + var variantsProperty = shaderProperty.FindPropertyRelative("second.variants"); + for (int j = 0; j < variantsProperty.arraySize; j++) + { + var variantProperty = variantsProperty.GetArrayElementAtIndex(j); + var passTypeProperty = variantProperty.FindPropertyRelative("passType"); + var keywordsProperty = variantProperty.FindPropertyRelative("keywords"); + + var passType = (PassType)passTypeProperty.intValue; + + ShaderVariants.Add(new ShaderVariantData + { + ShaderName = shader.name, + PassType = passType, + Keywords = keywordsProperty.stringValue + }); + } + } + + Debug.Log($"Successfully loaded {ShaderVariants.Count} shader variants."); + } + catch + { + Debug.LogError("An error occurred while reading the ShaderVariantCollection."); + } + } + + /// + /// Exports the shader variants to a script for hard-coding. + /// + public void ExportShaderVariantsToFile(string outputPath) + { + List lines = new List(); + lines.Add("using UnityEngine.Rendering;\n"); + lines.Add("namespace ReadyPlayerMe.Core.Editor\n{"); + lines.Add(" public static class ShaderVariantConstants\n {"); + lines.Add(" public static ShaderVariantData[] Variants = new [] \n {"); + + foreach (ShaderVariantData variant in ShaderVariants) + { + string keywordsString = variant.Keywords.Length > 0 ? $"\"{string.Join("\", \"", variant.Keywords)}\"" : "None"; + lines.Add($" new ShaderVariantData(\"{variant.ShaderName}\", PassType.{variant.PassType}, {keywordsString} ),"); + } + + lines.Add(" };"); + lines.Add(" }"); + lines.Add("}"); + + File.WriteAllLines(outputPath, lines.ToArray()); + AssetDatabase.Refresh(); + Debug.Log($"Shader variants exported to {outputPath}"); + } + + /// + /// Creates a new .shadervariants file based on the shader variants list. + /// + public void CreateNewShaderVariantsFile(string outputPath) + { + ShaderVariantCollection newCollection = new ShaderVariantCollection(); + + foreach (ShaderVariantData variantData in ShaderVariantConstants.Variants) + { + Shader shader = Shader.Find(variantData.ShaderName); + if (shader == null) + { + Debug.LogError($"Shader not found: {variantData.ShaderName}"); + continue; + } + + var keywordsArray = variantData.Keywords.Split(' '); + ShaderVariantCollection.ShaderVariant newVariant = new ShaderVariantCollection.ShaderVariant( + shader, + variantData.PassType, + keywordsArray); + newCollection.Add(newVariant); + } + + AssetDatabase.CreateAsset(newCollection, outputPath); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + Debug.Log($"New .shadervariants file created at {outputPath}"); + } + } +} \ No newline at end of file diff --git a/Editor/Core/Scripts/Utilities/ShaderVariantTool.cs.meta b/Editor/Core/Scripts/Utilities/ShaderVariantTool.cs.meta new file mode 100644 index 00000000..ec210f6d --- /dev/null +++ b/Editor/Core/Scripts/Utilities/ShaderVariantTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f9e050aace6e214db052d4bfef9a104 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: