Files
VR-WuKong/Assets/Mirror/Examples/Editor/MirrorRenderPipelineConverter.cs

292 lines
13 KiB
C#
Raw Normal View History

2025-11-13 17:40:28 +08:00
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
namespace Mirror.Examples.Editor
{
[InitializeOnLoad]
public class MirrorRenderPipelineConverter
{
private const string CONVERTED_FLAG_FILE = "MirrorExamplesPipelineConverted.txt";
static MirrorRenderPipelineConverter()
{
EditorApplication.delayCall += CheckPipelineOnLoad;
}
private static void CheckPipelineOnLoad()
{
if (HasConvertedFlag())
return;
RenderPipelineType currentPipeline = DetectRenderPipeline();
if (currentPipeline == RenderPipelineType.BuiltIn)
{
SetConvertedFlag();
return;
}
string examplesPath = GetExamplesFolderPath();
if (string.IsNullOrEmpty(examplesPath))
{
Debug.LogError("Could not locate Examples folder!");
return;
}
int choice = EditorUtility.DisplayDialogComplex(
$"Mirror Examples {currentPipeline} Conversion",
$"Mirror examples need to be converted to {currentPipeline}.\n\nThis will only affect {examplesPath} and subfolders.",
"Go Ahead", // 0 - Left (confirm)
"Don't Ask Again", // 1 - Right (cancel)
"Not Now" // 2 - Middle (alternative)
);
switch (choice)
{
case 0: // Go Ahead
ConvertMaterials(currentPipeline, examplesPath);
SetConvertedFlag();
Debug.Log("Mirror Examples materials converted to " + currentPipeline);
break;
case 1: // Don't Ask Again
SetConvertedFlag();
break;
case 2: // Not Now
break;
}
}
private enum RenderPipelineType
{
BuiltIn,
URP
}
private static RenderPipelineType DetectRenderPipeline()
{
var pipeline = UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline;
return pipeline != null && pipeline.GetType().Name.Contains("Universal") ? RenderPipelineType.URP : RenderPipelineType.BuiltIn;
}
private static string GetExamplesFolderPath()
{
string[] guids = AssetDatabase.FindAssets("MirrorRenderPipelineConverter t:Script");
if (guids.Length == 0) return null;
string scriptPath = AssetDatabase.GUIDToAssetPath(guids[0]);
return Path.GetDirectoryName(Path.GetDirectoryName(scriptPath))?.Replace("\\", "/");
}
/// <summary>
/// Converts materials in the Examples folder to match the current render pipeline.
/// Only processes .mat files and forces conversion for legacy/built-in shaders.
/// </summary>
private static void ConvertMaterials(RenderPipelineType targetPipeline, string examplesPath)
{
if (!Directory.Exists(examplesPath))
{
Debug.LogError($"Examples folder not found at: {examplesPath}");
return;
}
try
{
// Find all .mat files in Examples folder and subfolders
string[] materialGuids = AssetDatabase.FindAssets("t:Material", new[] { examplesPath })
.Where(guid => AssetDatabase.GUIDToAssetPath(guid).EndsWith(".mat"))
.ToArray();
foreach (string guid in materialGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
if (mat != null)
{
string shaderName = mat.shader.name;
// Force conversion for non-URP shaders that won't render correctly
bool needsConversion = shaderName.StartsWith("Legacy Shaders/") ||
shaderName == "Standard" ||
shaderName == "Standard (Specular setup)";
if (!needsConversion && Shader.Find(shaderName) != null)
{
Debug.Log($"Shader '{shaderName}' exists and is assumed URP-compatible, skipping: {path}");
continue;
}
if (targetPipeline == RenderPipelineType.URP)
ConvertToURP(mat);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
catch (System.Exception e)
{
Debug.LogError($"Error during material conversion: {e.Message}");
}
}
/// <summary>
/// Converts a material to URP-compatible shaders, preserving properties like color, texture,
/// tiling, transparency, and forward rendering options (specular highlights and reflections).
/// </summary>
private static void ConvertToURP(Material material)
{
string originalShaderName = material.shader.name;
// Capture all relevant properties before changing the shader
Color initialColor = material.GetColor("_Color");
Debug.Log($"Initial _Color for '{material.name}': {initialColor} (Hex: {ColorUtility.ToHtmlStringRGBA(initialColor)})", material);
Texture mainTex = null;
Vector4 mainTexST = Vector4.zero; // x, y = tiling; z, w = offset
if (material.HasProperty("_MainTex"))
{
mainTex = material.GetTexture("_MainTex");
mainTexST = material.GetVector("_MainTex_ST");
Debug.Log($"Initial _MainTex for '{material.name}': {(mainTex != null ? mainTex.name : "null")}, Tiling/Offset: {mainTexST}", material);
}
else if (material.mainTexture != null)
{
mainTex = material.mainTexture;
mainTexST = new Vector4(material.mainTextureScale.x, material.mainTextureScale.y, material.mainTextureOffset.x, material.mainTextureOffset.y);
Debug.Log($"Initial mainTexture fallback for '{material.name}': {mainTex.name}, Tiling/Offset: {mainTexST}", material);
}
Texture bumpMap = null;
if (material.HasProperty("_BumpMap"))
{
bumpMap = material.GetTexture("_BumpMap");
Debug.Log($"Initial _BumpMap for '{material.name}': {(bumpMap != null ? bumpMap.name : "null")}", material);
}
float metallic = material.HasProperty("_Metallic") ? material.GetFloat("_Metallic") : 0f;
float smoothness = material.HasProperty("_Glossiness") ? material.GetFloat("_Glossiness") : 0f;
Debug.Log($"Initial Metallic for '{material.name}': {metallic}, Smoothness: {smoothness}", material);
bool isTransparent = material.renderQueue == (int)UnityEngine.Rendering.RenderQueue.Transparent;
// Capture Forward Rendering Options (Specular Highlights and Reflections)
float specularHighlights = material.HasProperty("_SpecularHighlights") ? material.GetFloat("_SpecularHighlights") : 0f; // Default off
float environmentReflections = material.HasProperty("_GlossyReflections") ? material.GetFloat("_GlossyReflections") : 0f; // Default off
Debug.Log($"Initial Specular Highlights for '{material.name}': {(specularHighlights > 0 ? "On" : "Off")}, Environment Reflections: {(environmentReflections > 0 ? "On" : "Off")}", material);
// Handle skybox materials
if (originalShaderName.StartsWith("Skybox/"))
{
if (originalShaderName == "Skybox/6 Sided")
{
Shader urpSixSidedShader = Shader.Find("Skybox/6 Sided");
if (urpSixSidedShader != null && material.shader != urpSixSidedShader)
{
material.shader = urpSixSidedShader;
Debug.Log($"Converted to URP Skybox/6 Sided: {AssetDatabase.GetAssetPath(material)}", material);
}
return;
}
else
{
Shader urpSkyboxShader = Shader.Find("Skybox/Panoramic");
if (urpSkyboxShader != null && material.shader != urpSkyboxShader)
{
material.shader = urpSkyboxShader;
if (material.HasProperty("_Tex"))
material.SetTexture("_MainTex", material.GetTexture("_Tex"));
else if (material.HasProperty("_FrontTex"))
material.SetTexture("_MainTex", material.GetTexture("_FrontTex"));
if (material.HasProperty("_Tint"))
material.SetColor("_Tint", material.GetColor("_Tint"));
Debug.Log($"Converted to URP Skybox/Panoramic: {AssetDatabase.GetAssetPath(material)}", material);
}
return;
}
}
// Convert to URP Lit for all other materials
Shader urpLitShader = Shader.Find("Universal Render Pipeline/Lit");
if (urpLitShader == null)
{
Debug.LogError("URP Lit shader not found in project!");
return;
}
material.shader = urpLitShader;
// Apply texture and tiling
if (mainTex != null)
{
material.SetTexture("_BaseMap", mainTex);
material.SetVector("_BaseMap_ST", mainTexST);
Debug.Log($"Set _BaseMap for '{material.name}' to: {mainTex.name}, Tiling/Offset: {mainTexST}", material);
}
else
{
Debug.Log($"No albedo texture found for '{material.name}' at {AssetDatabase.GetAssetPath(material)}", material);
}
// Apply color
Color baseColor = initialColor == Color.clear ? Color.white : initialColor;
material.SetColor("_BaseColor", baseColor);
Debug.Log($"Set _BaseColor for '{material.name}' to: {baseColor} (Hex: {ColorUtility.ToHtmlStringRGBA(baseColor)})", material);
// Apply normal map
if (bumpMap != null)
{
material.SetTexture("_BumpMap", bumpMap);
Debug.Log($"Set _BumpMap for '{material.name}' to: {bumpMap.name}", material);
}
// Apply metallic and smoothness
material.SetFloat("_Metallic", metallic);
material.SetFloat("_Smoothness", smoothness);
Debug.Log($"Set Metallic for '{material.name}' to: {metallic}, Smoothness to: {smoothness}", material);
// Apply forward rendering options
material.SetFloat("_SpecularHighlights", specularHighlights);
material.SetFloat("_EnvironmentReflections", environmentReflections);
Debug.Log($"Set Specular Highlights for '{material.name}' to: {(specularHighlights > 0 ? "On" : "Off")}, Environment Reflections to: {(environmentReflections > 0 ? "On" : "Off")}", material);
// Set surface type and blending
if (isTransparent)
{
material.SetFloat("_Surface", 1f); // Transparent
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
Debug.Log($"Set '{material.name}' to Transparent Surface Type", material);
}
else
{
material.SetFloat("_Surface", 0f); // Opaque
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
Debug.Log($"Set '{material.name}' to Opaque Surface Type", material);
}
Debug.Log($"Converted '{originalShaderName}' to URP Lit: {AssetDatabase.GetAssetPath(material)}", material);
}
private static bool HasConvertedFlag()
{
string flagPath = Path.Combine(Application.dataPath, "..", CONVERTED_FLAG_FILE);
return File.Exists(flagPath);
}
private static void SetConvertedFlag()
{
string flagPath = Path.Combine(Application.dataPath, "..", CONVERTED_FLAG_FILE);
File.WriteAllText(flagPath, "Converted: " + System.DateTime.Now.ToString());
AssetDatabase.Refresh();
}
}
}
#endif