Skip to content

Commit

Permalink
feat: added shader variant tool
Browse files Browse the repository at this point in the history
  • Loading branch information
HarrisonHough committed Sep 26, 2024
1 parent 8082b93 commit 49ae2e9
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 0 deletions.
25 changes: 25 additions & 0 deletions Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs
Original file line number Diff line number Diff line change
@@ -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" ),
};
}
}
11 changes: 11 additions & 0 deletions Editor/Core/Scripts/Utilities/ShaderVariantConstants.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

140 changes: 140 additions & 0 deletions Editor/Core/Scripts/Utilities/ShaderVariantTool.cs
Original file line number Diff line number Diff line change
@@ -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<ShaderVariantData> ShaderVariants { get; private set; } = new List<ShaderVariantData>();

/// <summary>
/// Reads the shader variants from a ShaderVariantCollection asset.
/// </summary>
/// <param name="variantCollection">The ShaderVariantCollection asset to load from.</param>
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.");
}
}

/// <summary>
/// Exports the shader variants to a script for hard-coding.
/// </summary>
public void ExportShaderVariantsToFile(string outputPath)
{
List<string> lines = new List<string>();
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}");
}

/// <summary>
/// Creates a new .shadervariants file based on the shader variants list.
/// </summary>
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}");
}
}
}
11 changes: 11 additions & 0 deletions Editor/Core/Scripts/Utilities/ShaderVariantTool.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 49ae2e9

Please sign in to comment.