using System.Text; using UnityEditor; using UnityEngine; public static class ConvertStandardSpecularToUrpLit { [MenuItem("Tools/Convert Standard Specular To URP Lit")] private static void Convert() { var report = new StringBuilder(); Object selected = Selection.activeObject; string folder = selected != null ? AssetDatabase.GetAssetPath(selected) : string.Empty; report.AppendLine("=== Standard Specular -> URP Lit ==="); report.AppendLine($"Selection object: {(selected != null ? selected.name : "NULL")}"); report.AppendLine($"Selection path: {folder}"); report.AppendLine($"Selection type: {(selected != null ? selected.GetType().Name : "NULL")}"); report.AppendLine(); if (string.IsNullOrEmpty(folder)) { report.AppendLine("[ERROR] Nothing selected."); Debug.LogError(report.ToString()); return; } if (!AssetDatabase.IsValidFolder(folder)) { report.AppendLine("[ERROR] Selected asset is not a folder."); report.AppendLine("Select a folder in Project window and run the tool again."); Debug.LogError(report.ToString()); return; } Shader urpLit = Shader.Find("Universal Render Pipeline/Lit"); if (urpLit == null) { report.AppendLine("[ERROR] Shader not found: Universal Render Pipeline/Lit"); Debug.LogError(report.ToString()); return; } string[] guids = AssetDatabase.FindAssets("t:Material", new[] { folder }); report.AppendLine($"Search folder: {folder}"); report.AppendLine($"Materials found: {guids.Length}"); report.AppendLine(); int converted = 0; int skipped = 0; int failed = 0; foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); Material mat = AssetDatabase.LoadAssetAtPath(path); if (mat == null) { failed++; report.AppendLine($"[FAILED] {path} | material load returned null"); continue; } string shaderName = mat.shader != null ? mat.shader.name : "NULL"; report.AppendLine($"[FOUND] {path}"); report.AppendLine($" Material: {mat.name}"); report.AppendLine($" Shader: {shaderName}"); if (shaderName != "Standard (Specular setup)") { skipped++; report.AppendLine(" Action: skipped (shader mismatch)"); continue; } Texture mainTex = mat.GetTexture("_MainTex"); Color color = mat.HasProperty("_Color") ? mat.GetColor("_Color") : Color.white; Texture bumpMap = mat.GetTexture("_BumpMap"); float bumpScale = mat.HasProperty("_BumpScale") ? mat.GetFloat("_BumpScale") : 1f; Texture emissionMap = mat.GetTexture("_EmissionMap"); Color emissionColor = mat.HasProperty("_EmissionColor") ? mat.GetColor("_EmissionColor") : Color.black; Texture specGlossMap = mat.GetTexture("_SpecGlossMap"); Color specColor = mat.HasProperty("_SpecColor") ? mat.GetColor("_SpecColor") : Color.white; float glossiness = mat.HasProperty("_Glossiness") ? mat.GetFloat("_Glossiness") : 0.5f; report.AppendLine($" _MainTex: {(mainTex != null ? mainTex.name : "null")}"); report.AppendLine($" _Color: {color}"); report.AppendLine($" _BumpMap: {(bumpMap != null ? bumpMap.name : "null")}"); report.AppendLine($" _BumpScale: {bumpScale}"); report.AppendLine($" _SpecGlossMap:{(specGlossMap != null ? specGlossMap.name : "null")}"); report.AppendLine($" _SpecColor: {specColor}"); report.AppendLine($" _Glossiness: {glossiness}"); report.AppendLine($" _EmissionMap: {(emissionMap != null ? emissionMap.name : "null")}"); report.AppendLine($" _EmissionColor:{emissionColor}"); try { mat.shader = urpLit; if (mat.HasProperty("_WorkflowMode")) mat.SetFloat("_WorkflowMode", 0f); // Specular workflow if (mat.HasProperty("_BaseMap")) mat.SetTexture("_BaseMap", mainTex); if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", color); if (mat.HasProperty("_BumpMap")) mat.SetTexture("_BumpMap", bumpMap); if (mat.HasProperty("_BumpScale")) mat.SetFloat("_BumpScale", bumpScale); if (mat.HasProperty("_SpecGlossMap")) mat.SetTexture("_SpecGlossMap", specGlossMap); if (mat.HasProperty("_SpecColor")) mat.SetColor("_SpecColor", specColor); if (mat.HasProperty("_Smoothness")) mat.SetFloat("_Smoothness", glossiness); if (emissionMap != null) { mat.EnableKeyword("_EMISSION"); if (mat.HasProperty("_EmissionMap")) mat.SetTexture("_EmissionMap", emissionMap); if (mat.HasProperty("_EmissionColor")) mat.SetColor("_EmissionColor", emissionColor); } EditorUtility.SetDirty(mat); converted++; report.AppendLine(" Action: converted"); } catch (System.Exception e) { failed++; report.AppendLine($" Action: failed"); report.AppendLine($" Error: {e.Message}"); } report.AppendLine(); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); report.AppendLine("=== Summary ==="); report.AppendLine($"Converted: {converted}"); report.AppendLine($"Skipped: {skipped}"); report.AppendLine($"Failed: {failed}"); report.AppendLine($"Total: {guids.Length}"); Debug.Log(report.ToString()); } }