using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEditor; namespace MCPForUnity.Editor.Helpers { internal static class RenderPipelineUtility { internal enum PipelineKind { BuiltIn, Universal, HighDefinition, Custom } internal enum VFXComponentType { ParticleSystem, LineRenderer, TrailRenderer } private static Dictionary s_DefaultVFXMaterials = new Dictionary(); private static readonly string[] BuiltInLitShaders = { "Standard", "Legacy Shaders/Diffuse" }; private static readonly string[] BuiltInUnlitShaders = { "Unlit/Color", "Unlit/Texture" }; private static readonly string[] UrpLitShaders = { "Universal Render Pipeline/Lit", "Universal Render Pipeline/Simple Lit" }; private static readonly string[] UrpUnlitShaders = { "Universal Render Pipeline/Unlit" }; private static readonly string[] HdrpLitShaders = { "HDRP/Lit", "High Definition Render Pipeline/Lit" }; private static readonly string[] HdrpUnlitShaders = { "HDRP/Unlit", "High Definition Render Pipeline/Unlit" }; internal static PipelineKind GetActivePipeline() { var asset = GraphicsSettings.currentRenderPipeline; if (asset == null) { return PipelineKind.BuiltIn; } var typeName = asset.GetType().FullName ?? string.Empty; if (typeName.IndexOf("HighDefinition", StringComparison.OrdinalIgnoreCase) >= 0 || typeName.IndexOf("HDRP", StringComparison.OrdinalIgnoreCase) >= 0) { return PipelineKind.HighDefinition; } if (typeName.IndexOf("Universal", StringComparison.OrdinalIgnoreCase) >= 0 || typeName.IndexOf("URP", StringComparison.OrdinalIgnoreCase) >= 0) { return PipelineKind.Universal; } return PipelineKind.Custom; } internal static Shader ResolveShader(string requestedNameOrAlias) { var pipeline = GetActivePipeline(); if (!string.IsNullOrWhiteSpace(requestedNameOrAlias)) { var alias = requestedNameOrAlias.Trim(); var aliasMatch = ResolveAlias(alias, pipeline); if (aliasMatch != null) { WarnIfPipelineMismatch(aliasMatch.name, pipeline); return aliasMatch; } var direct = Shader.Find(alias); if (direct != null) { WarnIfPipelineMismatch(direct.name, pipeline); return direct; } McpLog.Warn($"Shader '{alias}' not found. Falling back to {pipeline} defaults."); } var fallback = ResolveDefaultLitShader(pipeline) ?? ResolveDefaultLitShader(PipelineKind.BuiltIn) ?? Shader.Find("Unlit/Color"); if (fallback != null) { WarnIfPipelineMismatch(fallback.name, pipeline); } return fallback; } internal static Shader ResolveDefaultLitShader(PipelineKind pipeline) { return pipeline switch { PipelineKind.HighDefinition => TryFindShader(HdrpLitShaders) ?? TryFindShader(UrpLitShaders), PipelineKind.Universal => TryFindShader(UrpLitShaders) ?? TryFindShader(HdrpLitShaders), PipelineKind.Custom => TryFindShader(BuiltInLitShaders) ?? TryFindShader(UrpLitShaders) ?? TryFindShader(HdrpLitShaders), _ => TryFindShader(BuiltInLitShaders) ?? Shader.Find("Unlit/Color") }; } internal static Shader ResolveDefaultUnlitShader(PipelineKind pipeline) { return pipeline switch { PipelineKind.HighDefinition => TryFindShader(HdrpUnlitShaders) ?? TryFindShader(UrpUnlitShaders) ?? TryFindShader(BuiltInUnlitShaders), PipelineKind.Universal => TryFindShader(UrpUnlitShaders) ?? TryFindShader(HdrpUnlitShaders) ?? TryFindShader(BuiltInUnlitShaders), PipelineKind.Custom => TryFindShader(BuiltInUnlitShaders) ?? TryFindShader(UrpUnlitShaders) ?? TryFindShader(HdrpUnlitShaders), _ => TryFindShader(BuiltInUnlitShaders) }; } private static Shader ResolveAlias(string alias, PipelineKind pipeline) { if (string.Equals(alias, "lit", StringComparison.OrdinalIgnoreCase) || string.Equals(alias, "default", StringComparison.OrdinalIgnoreCase) || string.Equals(alias, "default_lit", StringComparison.OrdinalIgnoreCase) || string.Equals(alias, "standard", StringComparison.OrdinalIgnoreCase)) { return ResolveDefaultLitShader(pipeline); } if (string.Equals(alias, "unlit", StringComparison.OrdinalIgnoreCase)) { return ResolveDefaultUnlitShader(pipeline); } if (string.Equals(alias, "urp_lit", StringComparison.OrdinalIgnoreCase)) { return TryFindShader(UrpLitShaders); } if (string.Equals(alias, "hdrp_lit", StringComparison.OrdinalIgnoreCase)) { return TryFindShader(HdrpLitShaders); } if (string.Equals(alias, "built_in_lit", StringComparison.OrdinalIgnoreCase)) { return TryFindShader(BuiltInLitShaders); } return null; } private static Shader TryFindShader(params string[] shaderNames) { foreach (var shaderName in shaderNames) { var shader = Shader.Find(shaderName); if (shader != null) { return shader; } } return null; } private static void WarnIfPipelineMismatch(string shaderName, PipelineKind activePipeline) { if (string.IsNullOrEmpty(shaderName)) { return; } var lowerName = shaderName.ToLowerInvariant(); bool shaderLooksUrp = lowerName.Contains("universal render pipeline") || lowerName.Contains("urp/"); bool shaderLooksHdrp = lowerName.Contains("high definition render pipeline") || lowerName.Contains("hdrp/"); bool shaderLooksBuiltin = lowerName.Contains("standard") || lowerName.Contains("legacy shaders/"); bool shaderLooksSrp = shaderLooksUrp || shaderLooksHdrp; switch (activePipeline) { case PipelineKind.HighDefinition: if (shaderLooksUrp) { McpLog.Warn($"[RenderPipelineUtility] Active pipeline is HDRP but shader '{shaderName}' looks URP-based. Asset may appear incorrect."); } else if (shaderLooksBuiltin && !shaderLooksHdrp) { McpLog.Warn($"[RenderPipelineUtility] Active pipeline is HDRP but shader '{shaderName}' looks Built-in. Consider using an HDRP shader for correct results."); } break; case PipelineKind.Universal: if (shaderLooksHdrp) { McpLog.Warn($"[RenderPipelineUtility] Active pipeline is URP but shader '{shaderName}' looks HDRP-based. Asset may appear incorrect."); } else if (shaderLooksBuiltin && !shaderLooksUrp) { McpLog.Warn($"[RenderPipelineUtility] Active pipeline is URP but shader '{shaderName}' looks Built-in. Consider using a URP shader for correct results."); } break; case PipelineKind.BuiltIn: if (shaderLooksSrp) { McpLog.Warn($"[RenderPipelineUtility] Active pipeline is Built-in but shader '{shaderName}' targets URP/HDRP. Asset may not render as expected."); } break; } } internal static Material GetOrCreateDefaultVFXMaterial(VFXComponentType componentType) { var pipeline = GetActivePipeline(); string cacheKey = $"{pipeline}_{componentType}"; if (s_DefaultVFXMaterials.TryGetValue(cacheKey, out Material cachedMaterial) && cachedMaterial != null) { return cachedMaterial; } Material material = null; if (pipeline == PipelineKind.BuiltIn) { string builtinPath = componentType == VFXComponentType.ParticleSystem ? "Default-Particle.mat" : "Default-Line.mat"; material = AssetDatabase.GetBuiltinExtraResource(builtinPath); } if (material == null) { Shader shader = ResolveDefaultUnlitShader(pipeline); if (shader == null) { shader = Shader.Find("Unlit/Color"); } if (shader != null) { material = new Material(shader); material.name = $"Auto_Default_{componentType}_{pipeline}"; // Set default color (white is standard for VFX) if (material.HasProperty("_Color")) { material.SetColor("_Color", Color.white); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", Color.white); } if (componentType == VFXComponentType.ParticleSystem) { material.renderQueue = 3000; if (material.HasProperty("_Mode")) { material.SetFloat("_Mode", 2); } if (material.HasProperty("_SrcBlend")) { material.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.SrcAlpha); } if (material.HasProperty("_DstBlend")) { material.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); } if (material.HasProperty("_ZWrite")) { material.SetFloat("_ZWrite", 0); } } McpLog.Info($"[RenderPipelineUtility] Created default VFX material for {componentType} using {shader.name}"); } } if (material != null) { s_DefaultVFXMaterials[cacheKey] = material; } return material; } } }