using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using UnityEditor; using UnityEditor.Rendering; using UnityEditor.Rendering.Universal; using System.Linq; using NiloToon.NiloToonURP; using UnityEngine.Rendering; using Object = UnityEngine.Object; namespace NiloToon.NiloToonURP { public static class NiloToonMaterialConvertor { private static readonly int SurfaceTypePreset = Shader.PropertyToID("_SurfaceTypePreset"); private static readonly int RenderOutline = Shader.PropertyToID("_RenderOutline"); private static readonly int IsSkin = Shader.PropertyToID("_IsSkin"); private static readonly int IsFace = Shader.PropertyToID("_IsFace"); private static readonly int PerMaterialEnableDepthTextureRimLightAndShadow = Shader.PropertyToID("_PerMaterialEnableDepthTextureRimLightAndShadow"); public enum NiloToonSurfaceTypePreset { Opaque_Outline = 0, Opaque = 1, Transparent_ZWrite_Outline = 2, Transparent = 3, Transparent_ZWrite = 4, CutoutOpaque_Outline = 5, CutoutOpaque = 6, CutoutTransparent_ZWrite_Outline = 7, CutoutTransparent = 8, CutoutTransparent_ZWrite = 9, TransparentQueueTransparent_ZWrite_Outline = 10, TransparentQueueTransparent_ZWrite = 11, CutoutTransparentQueueTransparent_ZWrite_Outline = 12, CutoutTransparentQueueTransparent_ZWrite = 13, } enum RenderQueueGroup { Opaque, Cutout, Transparent } public static void AutoConvertMaterialsToNiloToon(List allTargetMaterials) { Shader niloToonCharShader = Shader.Find("Universal Render Pipeline/NiloToon/NiloToon_Character"); Shader URPComplexLitShader = Shader.Find("Universal Render Pipeline/Complex Lit"); Shader URPLitShader = Shader.Find("Universal Render Pipeline/Lit"); Shader URPSimpleLitShader = Shader.Find("Universal Render Pipeline/Simple Lit"); Shader URPUnlitShader = Shader.Find("Universal Render Pipeline/Unlit"); Shader UniGLTFUnlitShader = Shader.Find("UniGLTF/UniUnlit"); Shader VRMBRPMToon00Shader = Shader.Find("VRM/MToon"); // has it's own shader properties Shader VRMBRPMToon10Shader = Shader.Find("VRM10/MToon10"); // share the exact same shader properties with URP version Shader VRMURPMToon10Shader = Shader.Find( "VRM10/Universal Render Pipeline/MToon10"); // share the exact same shader properties with BRP version Shader builtinRPStandardShader = Shader.Find("Standard"); // clone all original materials to a new List with the same order, for later reference, since we will edit the real material later List allOriginalMaterialsClone = new List(allTargetMaterials); for (int i = 0; i < allTargetMaterials.Count; i++) { allOriginalMaterialsClone[i] = Object.Instantiate(allTargetMaterials[i]); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Find the correct NiloToonSurfaceTypePreset index of each original material // (matching the index of NiloToonCharacter_SurfaceType_LWGUI_ShaderPropertyPreset.asset) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// NiloToonSurfaceTypePreset[] niloToonSurfaceTypePresetIDArray = new NiloToonSurfaceTypePreset[allTargetMaterials.Count]; for (int i = 0; i < niloToonSurfaceTypePresetIDArray.Length; i++) { niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset .Opaque_Outline; // init as Opaque+Outline(index is 0), it is the default preset } for (int i = 0; i < allOriginalMaterialsClone.Count; i++) { Material matOriginal = allOriginalMaterialsClone[i]; if (matOriginal.shader == UniGLTFUnlitShader) { //public enum UniUnlitRenderMode //{ // Opaque = 0, // Cutout = 1, // Transparent = 2, //} int _BlendMode = (int)matOriginal.GetFloat("_BlendMode"); switch (_BlendMode) { case 0: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Opaque_Outline; break; case 1: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; break; case 2: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; break; default: throw new NotImplementedException( "seems that VRM shader(UniGLTF/UniUnlit) added a new UniUnlitRenderMode that is not handled by NiloToon yet, contact NiloToon's developer to support this."); } } if (matOriginal.shader == URPComplexLitShader || matOriginal.shader == URPLitShader || matOriginal.shader == URPSimpleLitShader || matOriginal.shader == URPUnlitShader) { //public enum SurfaceType //{ // Opaque = 0, // Transparent = 1, //} int _Surface = (int)matOriginal.GetFloat("_Surface"); bool _AlphaClip = matOriginal.GetFloat("_AlphaClip") > 0.5f; switch (_Surface) { case 0: niloToonSurfaceTypePresetIDArray[i] = _AlphaClip ? NiloToonSurfaceTypePreset.CutoutOpaque_Outline : NiloToonSurfaceTypePreset.Opaque_Outline; break; case 1: niloToonSurfaceTypePresetIDArray[i] = _AlphaClip ? NiloToonSurfaceTypePreset.CutoutTransparent : NiloToonSurfaceTypePreset.Transparent; break; default: throw new NotImplementedException( "seems that URP's Lit,Complex Lit,Simple Lit or Unlit added a new SurfaceType that is not handled by NiloToon yet, contact NiloToon's developer to support this."); } } if (matOriginal.shader == builtinRPStandardShader) { // Opaque = 0, // Cutout = 1, // Fade = 2, (ZWrite is off) // Transparent = 3, (ZWrite is on) int _Mode = (int)matOriginal.GetFloat("_Mode"); switch (_Mode) { case 0: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Opaque_Outline; break; case 1: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; break; case 2: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; break; case 3: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline; break; default: throw new NotImplementedException( "seems that BRP Standard shader added a new Mode that is not handled by NiloToon yet, contact NiloToon's developer to support this."); } } // for any VRM00 migrated material's shader if (matOriginal.shader == VRMBRPMToon00Shader) { //public enum RenderMode //{ // Opaque = 0, // Cutout = 1, // Transparent = 2, // TransparentWithZWrite = 3, //} int _BlendMode = (int)matOriginal .GetFloat( "_BlendMode"); // '_BlendMode' in vrm00's MToon shader is the 'Rendering Type' in UI, 'RenderMode' in C# // vrm00 MToon's _OutlineWidthMode //public enum OutlineWidthMode //{ // None = 0, // WorldCoordinates = 1, // ScreenCoordinates = 2, //} int _OutlineWidthMode = (int)matOriginal.GetFloat("_OutlineWidthMode"); bool hasOutline = _OutlineWidthMode > 0; switch (_BlendMode) { case 0: niloToonSurfaceTypePresetIDArray[i] = hasOutline ? NiloToonSurfaceTypePreset.Opaque_Outline : NiloToonSurfaceTypePreset.Opaque; break; case 1: niloToonSurfaceTypePresetIDArray[i] = hasOutline ? NiloToonSurfaceTypePreset.CutoutOpaque_Outline : NiloToonSurfaceTypePreset.CutoutOpaque; break; case 2: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 'Transparent' don't have outline in NiloToon break; case 3: niloToonSurfaceTypePresetIDArray[i] = hasOutline ? NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline : NiloToonSurfaceTypePreset.Transparent_ZWrite; break; default: throw new NotImplementedException( "seems that VRM MToon shader(VRM/MToon) added a new Rendering Type that is not handled by NiloToon yet, contact NiloToon's developer to support this."); } } // for any VRM10 migrated material's shader if (matOriginal.shader == VRMBRPMToon10Shader || matOriginal.shader == VRMURPMToon10Shader) { // all VRM1 shader(BRP/URP) share the same properties{}! //public enum MToon10AlphaMode //{ // Opaque = 0, // Cutout = 1, // Transparent = 2, //} int _AlphaMode = (int)matOriginal.GetFloat("_AlphaMode"); switch (_AlphaMode) { case 0: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Opaque_Outline; break; case 1: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; break; case 2: bool _TransparentWithZWrite = matOriginal.GetFloat("_TransparentWithZWrite") > 0.5f; niloToonSurfaceTypePresetIDArray[i] = _TransparentWithZWrite ? NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline : NiloToonSurfaceTypePreset.Transparent; break; default: throw new NotImplementedException( "seems that VRM1 MToon shader(VRM10's MToon10) added a new MToon10AlphaMode that is not handled by NiloToon yet, contact NiloToon's developer to support this."); } } if (matOriginal.shader == niloToonCharShader) { // NiloToon->NiloToon, so nothing to do, just pass SurfaceType without edit niloToonSurfaceTypePresetIDArray[i] = (NiloToonSurfaceTypePreset)(int)matOriginal.GetFloat("_SurfaceTypePreset"); } if (matOriginal.shader.name.Contains("lilToon")) { /* // [Rendering Mode] // Opaque = 0 // Cutout = 1 // Transparent = 2 // Refraction // Fur // FurCutout // Gem int _RenderingMode = ... there is no rendering mode in material info. _TransparentMode is not what we are looking for switch (_RenderingMode) { case 0: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Opaque_Outline; break; case 1: niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; break; case 2: bool _ZWrite = matOriginal.GetFloat("_ZWrite") > 0.5f; niloToonSurfaceTypePresetIDArray[i] = _ZWrite ? NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline : NiloToonSurfaceTypePreset.Transparent; break; default: // it is not support, use a generic preset niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; break; } */ // so we need some complex logic to find out the correct NiloToonSurfaceType, // copy from lilInspector.cs -> CheckShaderType(Material material) bool isCutout = matOriginal.shader.name.Contains("Cutout"); bool isTransparent = matOriginal.shader.name.Contains("Transparent") || matOriginal.shader.name.Contains("Overlay"); bool isOutl = matOriginal.shader.name.Contains("Outline"); bool isTransparentQueue = matOriginal.renderQueue > 2500; bool isZWrite = matOriginal.GetFloat("_ZWrite") > 0.5f; // if ZWrite is off, we treat the material as transparent if (!isCutout && !isTransparent && !isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Opaque; // 1 else if (!isCutout && !isTransparent && !isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 2 else if (!isCutout && !isTransparent && !isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite; // 3 else if (!isCutout && !isTransparent && !isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 4 else if (!isCutout && !isTransparent && isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Opaque_Outline; // 5 else if (!isCutout && !isTransparent && isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 6 else if (!isCutout && !isTransparent && isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline; // 7 else if (!isCutout && !isTransparent && isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 8 else if (!isCutout && isTransparent && !isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent_ZWrite; // 9 else if (!isCutout && isTransparent && !isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 10 else if (!isCutout && isTransparent && !isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent_ZWrite; // 11 else if (!isCutout && isTransparent && !isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 12 else if (!isCutout && isTransparent && isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline; // 13 else if (!isCutout && isTransparent && isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 14 else if (!isCutout && isTransparent && isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite; // 15 else if (!isCutout && isTransparent && isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.Transparent; // 16 else if ( isCutout && !isTransparent && !isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque; // 17 else if ( isCutout && !isTransparent && !isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 18 else if ( isCutout && !isTransparent && !isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque; // 19 else if ( isCutout && !isTransparent && !isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 20 else if ( isCutout && !isTransparent && isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; // 21 else if ( isCutout && !isTransparent && isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 22 else if ( isCutout && !isTransparent && isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite_Outline; // 23 else if ( isCutout && !isTransparent && isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 24 else if ( isCutout && isTransparent && !isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite; // 25 else if ( isCutout && isTransparent && !isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 26 else if ( isCutout && isTransparent && !isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite; // 27 else if ( isCutout && isTransparent && !isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 28 else if ( isCutout && isTransparent && isOutl && !isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite_Outline; // 29 else if ( isCutout && isTransparent && isOutl && !isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 30 else if ( isCutout && isTransparent && isOutl && isTransparentQueue && isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite_Outline; //31 else if ( isCutout && isTransparent && isOutl && isTransparentQueue && !isZWrite) niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutTransparent; // 32 } // since there are many model's texture that alpha is not used for transparency(e.g. store special data that is not alpha), // we will not use texture's alpha to decide if Cutout should be enabled or not anymore /* // [feature removed] // If the NiloToonSurfaceTypePreset is the default one that ignores alpha, use _BaseMap's alpha to determine if cutout is needed // this step is useful when there is no information about what NiloToonSurfaceTypePreset should be, // the only information we have is the _BaseMap's alpha, the alpha will hint us what NiloToonSurfaceTypePreset is suitable if (matOriginal.shader == URPLitShader && niloToonSurfaceTypePresetIDArray[i] == NiloToonSurfaceTypePreset.Opaque_Outline) { Texture2D baseMapTexture; // try to get _MainTex first from any BRP material baseMapTexture = matOriginal.mainTexture as Texture2D; // if we can't get one, try to get _BaseMap from any URP material if (!baseMapTexture) { if(matOriginal.HasProperty("_BaseMap")) { baseMapTexture = matOriginal.GetTexture("_BaseMap") as Texture2D; } } // if the material has a _MainTex or _BaseMap if (baseMapTexture != null) { // and if texture has alpha value if(TextureHasAlpha(baseMapTexture)) { // convert Opaque_Outline -> CutoutOpaque_Outline niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque_Outline; } } } */ } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // if the material is not a URP shader, it won't have _BaseMap property, // so it should be using a built-in RP only shader currently(e.g. Built-in RP vrm/mtoon or any error shader material), // we will first switch the material's shader to built-in RP's "Standard" shader for auto material convertion by URP in the next section //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// foreach (var mat in allTargetMaterials) { // skip for vrm mtoon, since we will not rely on URP's material upgrader, and handle everything by ourself if (mat.shader == VRMBRPMToon00Shader || mat.shader == VRMBRPMToon10Shader || mat.shader == VRMURPMToon10Shader) continue; // Ensure not a variant BreakMaterialVariant(mat); // support these special shaders from URP's package: // - PhysicalMaterial3DsMax // - ArnoldStandardSurface if (mat.HasProperty("_BASE_COLOR_MAP")) { Texture basmeap = mat.GetTexture("_BASE_COLOR_MAP"); if (basmeap) { mat.shader = builtinRPStandardShader; mat.mainTexture = basmeap; } } if (!mat.HasProperty("_BaseMap") || !mat.GetTexture("_BaseMap")) { // switch material to use built-in RP's standard shader first, so that it is prepared for URP's material upgrade mat.shader = builtinRPStandardShader; EditorUtility.SetDirty(mat); } } AssetDatabase.SaveAssets(); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // if the material is not a URP's shader, we have converted it to built-in RP's "Standard" // we then simulate a click to "Edit/Rendering/Materials/Convert Selected Built-in Materials to URP", // which means calling to UniversalRenderPipelineMaterialUpgrader.UpgradeSelectedMaterials(). //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// List upgraders = new List(); GetUpgraders(ref upgraders); HashSet shaderNamesToIgnore = new HashSet(); GetShaderNamesToIgnore(ref shaderNamesToIgnore); // set selection to materials that we want to upgrade UnityEngine.Object[] targets = new UnityEngine.Object[allTargetMaterials.Count]; targets = allTargetMaterials.ToArray(); var originalSelectionObjects = Selection.objects; Selection.objects = targets; // call SRP's UpgradeSelection() MaterialUpgrader.UpgradeSelection(upgraders, shaderNamesToIgnore, "Upgrade to UniversalRP Materials", MaterialUpgrader.UpgradeFlags.LogMessageWhenNoUpgraderFound); // restore Selection Selection.objects = originalSelectionObjects; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // switch material to "NiloToon_Character" shader, // and edit any important properties //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// for (int i = 0; i < allTargetMaterials.Count; i++) { Material mat = allTargetMaterials[i]; Material originalMatClone = allOriginalMaterialsClone[i]; NiloToonSurfaceTypePreset nilotoonSurfaceTypePresetID = niloToonSurfaceTypePresetIDArray[i]; // Ensure not a variant BreakMaterialVariant(mat); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // if material is URP package's material (e.g. Lit.mat), // skip editing the material, // else we will be editing URP's default material that is inside URP package ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// { string path = UnityEditor.AssetDatabase.GetAssetPath(mat); if (path.StartsWith("Packages/com.unity.render-pipelines.universal")) { continue; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // if material is Particle or Sprite shader, skip editing it ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (mat.shader.name.Contains("Particle") || mat.shader.name.Contains("Sprite")) { continue; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // if the current shader is not any NiloToon shader // switch this shader to NiloToon_Character shader ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (!mat.shader.name.Contains("NiloToon")) { int originalRenderQueue = mat.renderQueue; // this line will reset render queue to shader's default! mat.shader = niloToonCharShader; // so we restore the render queue mat.renderQueue = originalRenderQueue; EditorUtility.SetDirty(mat); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // if the current shader is NiloToon_Character shader (not NiloToon's sticker/environment shaders) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (mat.shader == niloToonCharShader) { string[] IsFaceTargetNames = { "face", "facial", "express", "kao", "head" }; string[] IsFaceBanNames = { "Kaoru", "Surface", "phone", "headset" }; // avoid "Kaoru" treated as face due to "kao", avoid "headphone" or "headset" treated as head // TODO: should we include "facial" as eye target name? string[] IsEyeTargetNames = { "eye", "iris", "pupil", "lash", "brow", "mayu", "hitomi", "shirome", "matsuge", "matuge", "hairaito", "doukou", "guruguru", ".me", "Canthus", "sclera", "cornea", "limbus" }; string[] IsEyeBanNames = { "brown" }; // avoid "brown" treated as eye due to "brow" string[] IsMouthTargetNames = { "mouth", "oral", "tongue", "kuchi", ".ha", "kounai", "shita" }; string[] IsMouthBanNames = { ".hada" }; string[] IsTeethTargetNames = { "teeth", "tooth" }; string[] IsTeethBanNames = { }; string[] IsSkinTargetNames = { "skin", "hada", "body", "karada" }; // material with a name "body / karada" is not always skin, but we still put "body" into this array, // since a skin material without enabling "IsSkin" is far worse than a non-skin material enabled "IsSkin" wrongly. string[] IsSkinBanNames = { }; string[] IsNoOutlineTargetNames = { "noline", "nooutline", "no_line", "no_outline" }; string[] IsNoOutlineBanNames = { }; //---------------------------------------------------- // FaceFinal = face + (eye + mouth + teeth) string[] IsFaceFinalTargetNames = new string[] { }; IsFaceFinalTargetNames = IsFaceFinalTargetNames.Concat(IsFaceTargetNames).ToArray(); IsFaceFinalTargetNames = IsFaceFinalTargetNames.Concat(IsEyeTargetNames).ToArray(); IsFaceFinalTargetNames = IsFaceFinalTargetNames.Concat(IsMouthTargetNames).ToArray(); IsFaceFinalTargetNames = IsFaceFinalTargetNames.Concat(IsTeethTargetNames).ToArray(); string[] IsFaceExactTargetNames = new string[]{ "me", "ha"}; string[] IsFaceFinalBanNames = new string[] { }; IsFaceFinalBanNames = IsFaceFinalBanNames.Concat(IsFaceBanNames).ToArray(); IsFaceFinalBanNames = IsFaceFinalBanNames.Concat(IsEyeBanNames).ToArray(); IsFaceFinalBanNames = IsFaceFinalBanNames.Concat(IsMouthBanNames).ToArray(); IsFaceFinalBanNames = IsFaceFinalBanNames.Concat(IsTeethBanNames).ToArray(); //---------------------------------------------------- // SkinFinal = skin + (face + mouth) string[] IsSkinFinalTargetNames = new string[] { }; IsSkinFinalTargetNames = IsSkinFinalTargetNames.Concat(IsSkinTargetNames).ToArray(); IsSkinFinalTargetNames = IsSkinFinalTargetNames.Concat(IsFaceTargetNames).ToArray(); IsSkinFinalTargetNames = IsSkinFinalTargetNames.Concat(IsMouthTargetNames).ToArray(); string[] IsSkinFinalBanNames = new string[] { }; IsSkinFinalBanNames = IsSkinFinalBanNames.Concat(IsSkinBanNames).ToArray(); IsSkinFinalBanNames = IsSkinFinalBanNames.Concat(IsFaceBanNames).ToArray(); //IsSkinFinalBanNames = IsSkinFinalBanNames.Concat(IsMouthBanNames).ToArray(); //---------------------------------------------------- List IsNoOutlineFinalTargetNames = IsFaceFinalTargetNames.Where(x => x != "face" && x != "head").ToList(); IsNoOutlineFinalTargetNames.Concat(IsNoOutlineTargetNames); List IsNoOutlineExactTargetNames = new List(); IsNoOutlineExactTargetNames.Concat(IsFaceExactTargetNames); List IsNoOutlineFinalBanNames = IsFaceFinalBanNames.ToList(); IsNoOutlineFinalBanNames.Concat(IsNoOutlineBanNames); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto disable classic outline if material name contain face/outline related keywords that should not render classic outline ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool isNoOutline = false; foreach (var keyword in IsNoOutlineFinalTargetNames) { isNoOutline |= NiloToonUtils.NameHasKeyword(mat.name, keyword); } foreach (var keyword in IsNoOutlineExactTargetNames) { isNoOutline |= NiloToonUtils.NameEqualsKeywordIgnoreCase(mat.name, keyword); } foreach (var keyword in IsNoOutlineFinalBanNames) { isNoOutline &= !NiloToonUtils.NameHasKeyword(mat.name, keyword); } if (isNoOutline) { switch (nilotoonSurfaceTypePresetID) { case NiloToonSurfaceTypePreset.Opaque_Outline: nilotoonSurfaceTypePresetID = NiloToonSurfaceTypePreset.Opaque; break; case NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline: nilotoonSurfaceTypePresetID = NiloToonSurfaceTypePreset.Transparent_ZWrite; break; case NiloToonSurfaceTypePreset.CutoutOpaque_Outline: nilotoonSurfaceTypePresetID = NiloToonSurfaceTypePreset.CutoutOpaque; break; case NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite_Outline: nilotoonSurfaceTypePresetID = NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite; break; case NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite_Outline: nilotoonSurfaceTypePresetID = NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite; break; case NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite_Outline: nilotoonSurfaceTypePresetID = NiloToonSurfaceTypePreset .CutoutTransparentQueueTransparent_ZWrite; break; default: // do nothing for non-outline material input break; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto set SurfaceType preset ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SetMaterialNiloToonSurfaceTypeAndProperties(mat, nilotoonSurfaceTypePresetID); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // port common vrm00 mtoon00 & vrm10 mtoon10 to nilotoon ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.shader == VRMBRPMToon00Shader || originalMatClone.shader == VRMBRPMToon10Shader || originalMatClone.shader == VRMURPMToon10Shader) { // port base map mat.SetTexture("_BaseMap", originalMatClone.GetTexture("_MainTex")); // port base color (all vrm00 & vrm10 rely on _Color) mat.SetFloat("_MultiplyBRPColor", 1); //mat.SetColor("_BaseColor", originalMatClone.GetColor("_Color")); // not replacing _BaseColor as _Color, since we now * _Color already, so _BaseColor should be in default value(1,1,1,1) // port outline tint color mat.SetColor("_OutlineTintColor", originalMatClone.GetColor("_OutlineColor")); // TODO: handle 'outline color = replace' mode // cancel skin outline override Color skinOutlineOverrideShadowColor = mat.GetColor("_OutlineTintColorSkinAreaOverride"); skinOutlineOverrideShadowColor.a = 0; mat.SetColor("_OutlineTintColorSkinAreaOverride", skinOutlineOverrideShadowColor); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto set outline extra mul for VRM00 mtoon00 material ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.shader == VRMBRPMToon00Shader) { const float niloToonWidthRelativeToMToon00 = 12; //12~18 is good mat.SetFloat("_OutlineWidthExtraMultiplier", niloToonWidthRelativeToMToon00); // extra check to limit any unexpected large outline width float maxFinalWidth = 0.5f; // 0.5 is NiloToon's default outline width float finalWidth = Mathf.Min(maxFinalWidth, mat.GetFloat("_OutlineWidth") * niloToonWidthRelativeToMToon00); mat.SetFloat("_OutlineWidth", finalWidth / niloToonWidthRelativeToMToon00); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto set outline extra mul for VRM10 mtoon10 material ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.shader == VRMBRPMToon10Shader || originalMatClone.shader == VRMURPMToon10Shader) { const float niloToonWidthRelativeToMToon10 = 512; mat.SetFloat("_OutlineWidthExtraMultiplier", niloToonWidthRelativeToMToon10); // extra check to limit any unexpected large outline width float maxFinalWidth = 0.5f; // 0.5 is NiloToon's default outline width float finalWidth = Mathf.Min(maxFinalWidth, mat.GetFloat("_OutlineWidth") * niloToonWidthRelativeToMToon10); mat.SetFloat("_OutlineWidth", finalWidth / niloToonWidthRelativeToMToon10); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // port vrm00 mtoon00 properties to nilotoon ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.shader == VRMBRPMToon00Shader) { float MToonScrollX = originalMatClone.GetFloat("_UvAnimScrollX"); float MToonScrollY = originalMatClone.GetFloat("_UvAnimScrollY"); float MToonRotate = originalMatClone.GetFloat("_UvAnimRotation"); Vector4 _UV0ScrollSpeed = new Vector4(); _UV0ScrollSpeed.x = MToonScrollX; _UV0ScrollSpeed.y = MToonScrollY; mat.SetVector("_UV0ScrollSpeed", _UV0ScrollSpeed); mat.SetFloat("_UV0RotateSpeed", MToonRotate); if (MToonScrollX != 0 || MToonScrollY != 0 || MToonRotate != 0) { mat.SetFloat("_EnableUVEditGroup", 1); } //public enum CullMode //{ // Off = 0, // Front = 1, // Back = 2, //} int _CullMode = (int)originalMatClone.GetFloat("_CullMode"); switch (_CullMode) { // Cull Off = Render Both case 0: mat.SetFloat("_RenderFacePreset", 2); mat.SetFloat("_Cull", 0); mat.SetFloat("_CullOutline", 1); break; // Cull Front = Render Back case 1: mat.SetFloat("_RenderFacePreset", 1); mat.SetFloat("_Cull", 1); mat.SetFloat("_CullOutline", 2); break; // Cull Back = Render Front case 2: mat.SetFloat("_RenderFacePreset", 0); mat.SetFloat("_Cull", 2); mat.SetFloat("_CullOutline", 1); break; } Texture2D _ShadeTexture = originalMatClone.GetTexture("_ShadeTexture") as Texture2D; if (_ShadeTexture) { mat.SetTexture("_OverrideShadowColorTex", _ShadeTexture); mat.SetFloat("_UseOverrideShadowColorByTexture", 1); mat.EnableKeyword("_OVERRIDE_SHADOWCOLOR_BY_TEXTURE"); mat.SetColor("_OverrideShadowColorTexTintColor", originalMatClone.GetColor("_ShadeColor")); } Texture2D _OutlineWidthTexture = originalMatClone.GetTexture("_OutlineWidthTexture") as Texture2D; if (_OutlineWidthTexture) { mat.SetTexture("_OutlineWidthTex", _OutlineWidthTexture); } // TODO: matcap additive direct port // TODO: additive param rim } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // port vrm10 mtoon10 properties to nilotoon ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.shader == VRMBRPMToon10Shader || originalMatClone.shader == VRMURPMToon10Shader) { float MToonScrollX = originalMatClone.GetFloat("_UvAnimScrollXSpeed"); float MToonScrollY = originalMatClone.GetFloat("_UvAnimScrollYSpeed"); float MToonRotate = originalMatClone.GetFloat("_UvAnimRotationSpeed"); Vector4 _UV0ScrollSpeed = new Vector4(); _UV0ScrollSpeed.x = MToonScrollX; _UV0ScrollSpeed.y = MToonScrollY; mat.SetVector("_UV0ScrollSpeed", _UV0ScrollSpeed); mat.SetFloat("_UV0RotateSpeed", -MToonRotate); if (MToonScrollX != 0 || MToonScrollY != 0 || MToonRotate != 0) { mat.SetFloat("_EnableUVEditGroup", 1); } int _M_CullMode = (int)originalMatClone.GetFloat("_M_CullMode"); switch (_M_CullMode) { // Cull Off = Render Both case 0: mat.SetFloat("_RenderFacePreset", 2); mat.SetFloat("_Cull", 0); mat.SetFloat("_CullOutline", 1); break; // Cull Front = Render Back case 1: mat.SetFloat("_RenderFacePreset", 1); mat.SetFloat("_Cull", 1); mat.SetFloat("_CullOutline", 2); break; // Cull Back = Render Front case 2: mat.SetFloat("_RenderFacePreset", 0); mat.SetFloat("_Cull", 2); mat.SetFloat("_CullOutline", 1); break; } mat.renderQueue += (int)originalMatClone.GetFloat("_RenderQueueOffset"); Texture2D _ShadeTex = originalMatClone.GetTexture("_ShadeTex") as Texture2D; if (_ShadeTex) { mat.SetTexture("_OverrideShadowColorTex", _ShadeTex); mat.SetFloat("_UseOverrideShadowColorByTexture", 1); mat.EnableKeyword("_OVERRIDE_SHADOWCOLOR_BY_TEXTURE"); mat.SetColor("_OverrideShadowColorTexTintColor", originalMatClone.GetColor("_ShadeColor")); } // TODO: matcap additive direct port // TODO: additive param rim } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // port liltoon properties to nilotoon ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.shader.name.Contains("lilToon")) { Port_lilToon_properties_To_NiloToon(originalMatClone, mat); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Auto enable NiloToon mat's texture feature(uniform+keyword) if any textures are assigned. // *Skip if the input material is: // - NiloToon_Character shader // - any lilToon shader // since we handled them already, if we do it again here, we may enable texture features that should be keep disabled) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if ((originalMatClone.shader != niloToonCharShader) && !(originalMatClone.name.Contains("lilToon"))) { if (mat.GetTexture("_OutlineWidthTex")) { mat.SetFloat("_UseOutlineWidthTex", 1); mat.EnableKeyword("_OUTLINEWIDTHMAP"); mat.SetVector("_OutlineWidthTexChannelMask", new Vector4(0, 1, 0, 0)); // vrmc mtoon's _OutlineWidthTex use G channel } if (mat.GetTexture("_BumpMap")) { mat.SetFloat("_UseNormalMap", 1); mat.EnableKeyword("_NORMALMAP"); } if (mat.GetTexture("_EmissionMap")) { mat.SetFloat("_UseEmission", 1); mat.EnableKeyword("_EMISSION"); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Reset _Parallax from 0.02 -> 0.005(default value) if _ParallaxMap doesn't exist // so _Parallax is not a modified property which confuses user ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (originalMatClone.HasProperty("_ParallaxMap")) { if (!originalMatClone.GetTexture("_ParallaxMap")) { mat.SetFloat("_Parallax", 0.005f); } } else { mat.SetFloat("_Parallax", 0.005f); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto enable 'IsFace' if material name contains 'face' related keywords ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool isFace = false; foreach (var keyword in IsFaceFinalTargetNames) { isFace |= NiloToonUtils.NameHasKeyword(mat.name, keyword); } foreach (var keyword in IsFaceExactTargetNames) { isFace |= NiloToonUtils.NameEqualsKeywordIgnoreCase(mat.name,keyword); } foreach (var keyword in IsFaceFinalBanNames) { isFace &= !NiloToonUtils.NameHasKeyword(mat.name, keyword); } if (isFace) { SetMaterialAsIsFace(mat); // *do not set material as skin } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto enable 'IsSkin' if material name contains 'skin' related keywords ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool isSkin = false; foreach (var keyword in IsSkinFinalTargetNames) { isSkin |= NiloToonUtils.NameHasKeyword(mat.name, keyword); } foreach (var keyword in IsSkinFinalBanNames) { isSkin &= !NiloToonUtils.NameHasKeyword(mat.name, keyword); } if (isSkin) { SetMaterialAsIsSkin(mat); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // auto disable depth tex shadow if // - it is eye (e.g. eye white material) // - it doesn't draw depth texture (e.g., render queue >= 2500) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (NiloToonUtils.NameHasKeyword(mat.name, "eye") || mat.renderQueue >= 2500) { mat.SetFloat(PerMaterialEnableDepthTextureRimLightAndShadow, 0); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Stencil preset matching ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int _StencilComp = (int)mat.GetFloat("_StencilComp"); int _StencilPass = (int)mat.GetFloat("_StencilPass"); int resultStencilPresetID = 0; // default = Disabled // [copy logic from NiloToonCharacter_StencilPreset_LWGUI_ShaderPropertyPreset] // matching [1]: 1st>Writer (Eyebrow) if (_StencilComp == 8 && _StencilPass == 2) { resultStencilPresetID = 1; } // matching [2]: 2nd>Reader (Original Hair) if (_StencilComp == 6 && _StencilPass == 0) { resultStencilPresetID = 2; } // matching [3]: 3rd>Reader-Invert (Redraw Hair) if (_StencilComp == 3 && _StencilPass == 0) { resultStencilPresetID = 3; } mat.SetFloat("_StencilPreset", resultStencilPresetID); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // tell unity we edited material ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// EditorUtility.SetDirty(mat); } } } private static void Port_lilToon_properties_To_NiloToon(Material fromlilToonMat, Material toNiloToonMat) { // try to match as many lilToon 1.7.2's lts_o.shader properties as possible // (?) _***** means a liltoon property not yet supported by nilotoon, under consideration // (X) _***** means a liltoon property not supported by nilotoon by design // (XV) _***** means a liltoon property not supported by nilotoon material by design, but it should be controlled by nilotoon's volume // (Same) _***** means a liltoon property is supported by nilotoon already, since the name is the same, no action needed //---------------------------------------------------------------------------------------------------------------------- // Dummy // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Base toNiloToonMat.SetFloat("_EnableRendering", fromlilToonMat.GetFloat("_Invisible") > 0.5 ? 0 : 1); // (lilToon: early return "init as 0 struct" in vertex shader, same as NiloToon) // (XV) _AsUnlit (lilToon: lerp main light color to white, lerp additional light color to black) // (Same)_Cutoff (lilToon: standard alpha clip threshold, same as NiloToon/Lit) // (?) _SubpassCutoff (NiloToon: similar to _CutOff, but only for "subpass", not sure what Subpass is) // (X) _FlipNormal (NiloToon: always perform flipNormal, there is no option in material) (lilToon: sFlipBackfaceNormal -> N = facing < (_FlipNormal-1.0) ? -N : N. Similar to NiloToon) // (?) _ShiftBackfaceUV (NiloToon: too specific, not sure if it is a good idea to add it) (lilToon: back face UV += (1,0) or not. lilToon's doc: Shift the UVs on the back by 1.0 in the X-axis direction. By turning this on and setting the Tiling's X to 0.5, and doubling the texture's resolution horizontally to place two textures side by side, you can create an expression where different textures are applied to the front and back.) toNiloToonMat.SetFloat("_BackFaceForceShadow", fromlilToonMat.GetFloat( "_BackfaceForceShadow")); // lilToon: float bfshadow = (fd.facing < 0.0) ? 1.0 - _BackfaceForceShadow : 1.0; toNiloToonMat.SetColor("_BackFaceBaseMapReplaceColor", fromlilToonMat.GetColor( "_BackfaceColor")); // lilToon: fd.col.rgb = (fd.facing < 0.0) ? lerp(fd.col.rgb, _BackfaceColor.rgb * fd.lightColor, _BackfaceColor.a) : fd.col.rgb; // (X) _VertexLightStrength (NiloToon: this lil prop is for BRP only, ignored) (lilToon: for BRP only) // (XV) _LightMinLimit (lilToon: lightColor = clamp(lightColor, _LightMinLimit, _LightMaxLimit);) // (XV) _LightMaxLimit (lilToon: lightColor = clamp(lightColor, _LightMinLimit, _LightMaxLimit);) // (X) _BeforeExposureLimit (NiloToon: this lilToon prop is for HDRP only, ignored) // (XV) _MonochromeLighting (lilToon: lightColor = lerp(lightColor, lilGray(lightColor), _MonochromeLighting);) // (X) _AlphaBoostFA (NiloToon: this lilToon prop is for forward add (FA) pass, ignored)(lilToon: fd.col.rgb *= saturate(fd.col.a * _AlphaBoostFA);) // (XV) _lilDirectionalLightStrength (lilToon: lightColor *= _lilDirectionalLightStrength) // (XV) _LightDirectionOverride (lilToon: add a object->world space light vector to light dir, re-normalize? (not sure)) // (?) _AAStrength (lilToon: for value with sharp change, apply fwidth AA by -> (value - borderMin) / saturate(borderMax - borderMin + fwidth(value) * aascale)) // (?) _UseDither (lilToon: dither fade0out per material) // (?) _DitherTex (lilToon: dither fadeout per material) // (?) _DitherMaxValue (lilToon: dither fadeout per material) //---------------------------------------------------------------------------------------------------------------------- // Main toNiloToonMat.SetColor("_BaseColor", fromlilToonMat.GetColor("_Color")); toNiloToonMat.SetTexture("_BaseMap", fromlilToonMat.GetTexture("_MainTex")); toNiloToonMat.SetVector("_BaseMap_ST", fromlilToonMat.GetVector("_MainTex_ST")); // auto uniform by Unity // (!) _MainTex_ScrollRotate // TODO: apply the BaseMap's uv, not UV0! // (?) _MainTexHSVG (lilToon: hsv = float3(hsv.x+hsvg.x,saturate(hsv.y*hsvg.y),saturate(hsv.z*hsvg.z));) // (X) _MainGradationStrength (NiloToon: too specific, ignored)(lilToon: rgb per channel color 1D remap) // (X) _MainGradationTex (NiloToon: too specific, ignored)(lilToon: rgb per channel color 1D remap) // (?) _MainColorAdjustMask (lilToon: mask of _MainTexHSVG) //---------------------------------------------------------------------------------------------------------------------- // Main2nd (port to NiloToon's BaseMapStackingLayer1) float _UseMain2ndTex = fromlilToonMat.GetFloat("_UseMain2ndTex"); toNiloToonMat.SetFloat("_BaseMapStackingLayer1Enable", _UseMain2ndTex); if (_UseMain2ndTex > 0.5) { toNiloToonMat.EnableKeyword("_BASEMAP_STACKING_LAYER1"); } else { toNiloToonMat.DisableKeyword("_BASEMAP_STACKING_LAYER1"); } toNiloToonMat.SetColor("_BaseMapStackingLayer1TintColor", fromlilToonMat.GetColor("_Color2nd")); toNiloToonMat.SetTexture("_BaseMapStackingLayer1Tex", fromlilToonMat.GetTexture("_Main2ndTex")); toNiloToonMat.SetVector("_BaseMapStackingLayer1TexUVScaleOffset", fromlilToonMat.GetVector("_Main2ndTex_ST")); // liltoon / nilotoon are both in degree toNiloToonMat.SetFloat("_BaseMapStackingLayer1TexUVRotatedAngle", fromlilToonMat.GetFloat("_Main2ndTexAngle") * 180f / Mathf.PI); { Vector4 _Main2ndTex_ScrollRotate = fromlilToonMat.GetVector("_Main2ndTex_ScrollRotate"); toNiloToonMat.SetVector("_BaseMapStackingLayer1TexUVAnimSpeed", new Vector4(_Main2ndTex_ScrollRotate.x, _Main2ndTex_ScrollRotate.y, 0, 0)); // [Don't use _Main2ndTex_ScrollRotate.z since it is not used by liltoon] // [use the above _Main2ndTexAngle instead] //toNiloToonMat.SetFloat("_BaseMapStackingLayer1TexUVRotatedAngle", _Main2ndTex_ScrollRotate.z * Mathf.Rad2Deg); // liltoon's speed is "cycle per second", nilotoon is "degree per second" toNiloToonMat.SetFloat("_BaseMapStackingLayer1TexUVRotateSpeed", _Main2ndTex_ScrollRotate.w * 360); } // liltoon's _Main2ndTex_UVMode = UV0|UV1|UV2|UV3|MatCap toNiloToonMat.SetFloat("_BaseMapStackingLayer1TexUVIndex", fromlilToonMat.GetFloat("_Main2ndTex_UVMode")); toNiloToonMat.SetFloat("_BaseMapStackingLayer1ApplytoFaces", fromlilToonMat.GetFloat("_Main2ndTex_Cull")); // (X) _Main2ndTexDecalAnimation // (X) _Main2ndTexDecalSubParam // (X) _Main2ndTexIsDecal // (X) _Main2ndTexIsLeftOnly // (X) _Main2ndTexIsRightOnly // (X) _Main2ndTexShouldCopy // (X) _Main2ndTexShouldFlipMirror // (X) _Main2ndTexShouldFlipCopy // (X) _Main2ndTexIsMSDF toNiloToonMat.SetTexture("_BaseMapStackingLayer1MaskTex", fromlilToonMat.GetTexture("_Main2ndBlendMask")); { // liltoon's blend mode: // 0: Normal // 1: Add // 2: Screen // 3: Multiply // NiloToon's blend mode: // 0: Normal RGBA // 1: Normal (same as liltoon) // 2: Add (same as liltoon) // 3: Screen (same as liltoon) // 4: Multiply (same as liltoon) // 5: None float _Main2ndTexBlendMode = fromlilToonMat.GetFloat("_Main2ndTexBlendMode"); float NiloToonBlendMode = 0; // default 0 (Normal RGBA) switch (_Main2ndTexBlendMode) { case 0: NiloToonBlendMode = 1; break; case 1: NiloToonBlendMode = 2; break; case 2: NiloToonBlendMode = 3; break; case 3: NiloToonBlendMode = 4; break; } toNiloToonMat.SetFloat("_BaseMapStackingLayer1ColorBlendMode", NiloToonBlendMode); } // (X) _Main2ndTexAlphaMode // TODO? // (X) _Main2ndEnableLighting // (X) _Main2ndDissolveMask // (X) _Main2ndDissolveNoiseMask // (X) _Main2ndDissolveNoiseMask_ScrollRotate // (X) _Main2ndDissolveNoiseStrength // (X) _Main2ndDissolveColor // (X) _Main2ndDissolveParams // (X) _Main2ndDissolvePos // (X) _Main2ndDistanceFade //---------------------------------------------------------------------------------------------------------------------- // Main3rd (port to NiloToon's BaseMapStackingLayer2) float _UseMain3rdTex = fromlilToonMat.GetFloat("_UseMain3rdTex"); toNiloToonMat.SetFloat("_BaseMapStackingLayer2Enable", _UseMain3rdTex); if (_UseMain3rdTex == 1) { toNiloToonMat.EnableKeyword("_BASEMAP_STACKING_LAYER2"); } else { toNiloToonMat.DisableKeyword("_BASEMAP_STACKING_LAYER2"); } toNiloToonMat.SetColor("_BaseMapStackingLayer2TintColor", fromlilToonMat.GetColor("_Color3rd")); toNiloToonMat.SetTexture("_BaseMapStackingLayer2Tex", fromlilToonMat.GetTexture("_Main3rdTex")); toNiloToonMat.SetVector("_BaseMapStackingLayer2TexUVScaleOffset", fromlilToonMat.GetVector("_Main3rdTex_ST")); // liltoon / nilotoon are both in degree toNiloToonMat.SetFloat("_BaseMapStackingLayer2TexUVRotatedAngle", fromlilToonMat.GetFloat("_Main3rdTexAngle")); { Vector4 _Main3rdTex_ScrollRotate = fromlilToonMat.GetVector("_Main3rdTex_ScrollRotate"); toNiloToonMat.SetVector("_BaseMapStackingLayer2TexUVAnimSpeed", new Vector4(_Main3rdTex_ScrollRotate.x, _Main3rdTex_ScrollRotate.y, 0, 0)); // [Don't use _Main3rdTex_ScrollRotate.z since it is not used by liltoon] // [use the above _Main3rdTexAngle instead] //toNiloToonMat.SetFloat("_BaseMapStackingLayer2TexUVRotatedAngle", _Main3rdTex_ScrollRotate.z * Mathf.Rad2Deg); // liltoon's speed is "cycle per second", nilotoon is "degree per second" toNiloToonMat.SetFloat("_BaseMapStackingLayer2TexUVRotateSpeed", _Main3rdTex_ScrollRotate.w * 360); } // liltoon's _Main3rdTex_UVMode = UV0|UV1|UV2|UV3|MatCap toNiloToonMat.SetFloat("_BaseMapStackingLayer2TexUVIndex", fromlilToonMat.GetFloat("_Main3rdTex_UVMode")); toNiloToonMat.SetFloat("_BaseMapStackingLayer2ApplytoFaces", fromlilToonMat.GetFloat("_Main3rdTex_Cull")); // (X) _Main3rdTexDecalAnimation // (X) _Main3rdTexDecalSubParam // (X) _Main3rdTexIsDecal // (X) _Main3rdTexIsLeftOnly // (X) _Main3rdTexIsRightOnly // (X) _Main3rdTexShouldCopy // (X) _Main3rdTexShouldFlipMirror // (X) _Main3rdTexShouldFlipCopy // (X) _Main3rdTexIsMSDF toNiloToonMat.SetTexture("_BaseMapStackingLayer2MaskTex", fromlilToonMat.GetTexture("_Main3rdBlendMask")); { // liltoon's blend mode: // 0: Normal // 1: Add // 2: Screen // 3: Multiply // NiloToon's blend mode: // 0: Normal RGBA // 1: Normal (same as liltoon) // 2: Add (same as liltoon) // 3: Screen (same as liltoon) // 4: Multiply (same as liltoon) // 5: None float _Main3rdTexBlendMode = fromlilToonMat.GetFloat("_Main3rdTexBlendMode"); float NiloToonBlendMode = 0; // default 0 (Normal RGBA) switch (_Main3rdTexBlendMode) { case 0: NiloToonBlendMode = 1; break; case 1: NiloToonBlendMode = 2; break; case 2: NiloToonBlendMode = 3; break; case 3: NiloToonBlendMode = 4; break; } toNiloToonMat.SetFloat("_BaseMapStackingLayer2ColorBlendMode", NiloToonBlendMode); } // (X) _Main3rdTexAlphaMode // TODO? // (X) _Main3rdEnableLighting // (X) _Main3rdDissolveMask // (X) _Main3rdDissolveNoiseMask // (X) _Main3rdDissolveNoiseMask_ScrollRotate // (X) _Main3rdDissolveNoiseStrength // (X) _Main3rdDissolveColor // (X) _Main3rdDissolveParams // (X) _Main3rdDissolvePos // (X) _Main3rdDistanceFade //---------------------------------------------------------------------------------------------------------------------- // Alpha Mask // lilToon's _AlphaMaskMode // 0 = None // 1 = Replace // 2 = Multiply // 3 = Add // 4 = Subtract int _AlphaMaskMode = (int)fromlilToonMat.GetFloat("_AlphaMaskMode"); if (_AlphaMaskMode != 0) { toNiloToonMat.SetFloat("_UseAlphaOverrideTex", 1); toNiloToonMat.EnableKeyword("_ALPHAOVERRIDEMAP"); toNiloToonMat.SetVector("_AlphaOverrideTexChannelMask", new Vector4(1f, 0f, 0f, 0f)); //r channel // convert to nilotoon // 0 = Replace // 1 = Multiply // 2 = Add // 3 = Subtract toNiloToonMat.SetFloat("_AlphaOverrideMode", Mathf.Min(3, _AlphaMaskMode - 1)); } else { toNiloToonMat.SetFloat("_UseAlphaOverrideTex", 0); toNiloToonMat.DisableKeyword("_ALPHAOVERRIDEMAP"); } toNiloToonMat.SetTexture("_AlphaOverrideTex", fromlilToonMat.GetTexture("_AlphaMask")); // liltoon GUI's invert toggle is not a property, it translate to a MAD (* scale + value) toNiloToonMat.SetFloat("_AlphaOverrideTexValueScale", fromlilToonMat.GetFloat("_AlphaMaskScale")); toNiloToonMat.SetFloat("_AlphaOverrideTexValueOffset", fromlilToonMat.GetFloat("_AlphaMaskValue")); //---------------------------------------------------------------------------------------------------------------------- // NormalMap int _UseBumpMap = (int)fromlilToonMat.GetFloat("_UseBumpMap"); if (_UseBumpMap == 1) { toNiloToonMat.SetFloat("_UseNormalMap", 1); toNiloToonMat.EnableKeyword("_NORMALMAP"); } else { toNiloToonMat.SetFloat("_UseNormalMap", 0); toNiloToonMat.DisableKeyword("_NORMALMAP"); } // (Same)_BumpMap // (Same)_BumpScale //---------------------------------------------------------------------------------------------------------------------- // NormalMap 2nd (apply to nilotoon's detail map?) // (?) ...All... //---------------------------------------------------------------------------------------------------------------------- // Anisotropy // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Backlight // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Shadow toNiloToonMat.SetFloat("_EnableShadowColor", fromlilToonMat.GetFloat("_UseShadow")); Texture2D occlusionMap = fromlilToonMat.GetTexture("_ShadowBorderMask") as Texture2D; toNiloToonMat.SetTexture("_OcclusionMap", occlusionMap); if (occlusionMap) { toNiloToonMat.SetFloat("_UseOcclusion", 1); toNiloToonMat.EnableKeyword("_OCCLUSIONMAP"); } else { toNiloToonMat.SetFloat("_UseOcclusion", 0); toNiloToonMat.DisableKeyword("_OCCLUSIONMAP"); } //---------------------------------------------------------------------------------------------------------------------- // Rim Shade //---------------------------------------------------------------------------------------------------------------------- // Reflection // TODO //---------------------------------------------------------------------------------------------------------------------- // MatCap // TODO (apply to basemap stacking layer3, base on blend mode) //---------------------------------------------------------------------------------------------------------------------- // MatCap 2nd // TODO (apply to basemap stacking layer4, apply base on blend mode) //---------------------------------------------------------------------------------------------------------------------- // Rim // TODO (we should write a ALU rim in NiloToon, similar to lilToon) //---------------------------------------------------------------------------------------------------------------------- // Glitter // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Emission int _UseEmission = (int)fromlilToonMat.GetFloat("_UseEmission"); if (_UseEmission == 1) { toNiloToonMat.SetFloat("_UseEmission", 1); toNiloToonMat.EnableKeyword("_EMISSION"); } else { toNiloToonMat.SetFloat("_UseEmission", 0); toNiloToonMat.DisableKeyword("_EMISSION"); } // (Same)_EmissionColor toNiloToonMat.SetFloat("_EmissionIntensity", fromlilToonMat.GetColor("_EmissionColor").a); // lilToon's _EmissionColor.a is the intensity // (Same)_EmissionMap toNiloToonMat.SetVector("_EmissionMapUVScrollSpeed", fromlilToonMat.GetVector("_EmissionMap_ScrollRotate")); // (X) _EmissionMap_UVMode toNiloToonMat.SetFloat("_MultiplyBaseColorToEmissionColor", fromlilToonMat.GetFloat("_EmissionMainStrength")); //_EmissionBlend //_EmissionBlendMask // (X) _EmissionBlendMask_ScrollRot // (X) _EmissionBlendMode // (X) _EmissionBlink // (X) _EmissionUseGrad // (X) _EmissionGradTex // (X) _EmissionGradSpeed // (X) _EmissionParallaxDepth // (X) _EmissionFluorescence //---------------------------------------------------------------------------------------------------------------------- // Emission2nd // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Parallax int _UseParallax = (int)fromlilToonMat.GetFloat("_UseParallax"); if (_UseParallax == 1) { toNiloToonMat.SetFloat("_ParallaxMapEnable", 1); toNiloToonMat.EnableKeyword("_PARALLAXMAP"); } else { toNiloToonMat.SetFloat("_ParallaxMapEnable", 0); toNiloToonMat.DisableKeyword("_PARALLAXMAP"); } // (X) _UsePOM // (Same) _ParallaxMap // (Same) _Parallax // (X) _ParallaxOffset //---------------------------------------------------------------------------------------------------------------------- // Distance Fade // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // AudioLink // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Dissolve // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // ID Mask // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Encryption // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // Outline toNiloToonMat.SetColor("_OutlineTintColor", fromlilToonMat.GetColor("_OutlineColor")); // _OutlineWidth (same, no need to convert) // make 2 outline system's width matching float _OutlineWidth = fromlilToonMat.GetFloat("_OutlineWidth"); const float niloToonWidthRelativeTolilToon = 4; toNiloToonMat.SetFloat("_OutlineWidthExtraMultiplier", niloToonWidthRelativeTolilToon); // extra check to limit any unexpected large outline width float maxFinalWidth = 0.5f; // 0.5 is NiloToon's default outline width float finalWidth = Mathf.Min(maxFinalWidth, _OutlineWidth * niloToonWidthRelativeTolilToon); toNiloToonMat.SetFloat("_OutlineWidth", finalWidth / niloToonWidthRelativeTolilToon); Texture2D _OutlineWidthMask = fromlilToonMat.GetTexture("_OutlineWidthMask") as Texture2D; if (_OutlineWidthMask) { toNiloToonMat.SetFloat("_UseOutlineWidthTex", 1); toNiloToonMat.EnableKeyword("_OUTLINEWIDTHMAP"); toNiloToonMat.SetVector("_OutlineWidthTexChannelMask", new Vector4(1, 0, 0, 0)); toNiloToonMat.SetTexture("_OutlineWidthTex", _OutlineWidthMask); } else { toNiloToonMat.SetFloat("_UseOutlineWidthTex", 0); toNiloToonMat.DisableKeyword("_OUTLINEWIDTHMAP"); toNiloToonMat.SetVector("_OutlineWidthTexChannelMask", new Vector4(0, 1, 0, 0)); } float _OutlineVertexR2Width = fromlilToonMat.GetFloat("_OutlineVertexR2Width"); if (_OutlineVertexR2Width == 0) { // no vertex color used toNiloToonMat.SetFloat("_UseOutlineWidthMaskFromVertexColor", 0); toNiloToonMat.SetVector("_OutlineWidthMaskFromVertexColor", new Vector4(0, 1, 0, 0)); } if (_OutlineVertexR2Width == 1) { // vertex color.r toNiloToonMat.SetFloat("_UseOutlineWidthMaskFromVertexColor", 1); toNiloToonMat.SetVector("_OutlineWidthMaskFromVertexColor", new Vector4(1, 0, 0, 0)); } if (_OutlineVertexR2Width == 2) { // vertex color.a toNiloToonMat.SetFloat("_UseOutlineWidthMaskFromVertexColor", 1); toNiloToonMat.SetVector("_OutlineWidthMaskFromVertexColor", new Vector4(0, 0, 0, 1)); } toNiloToonMat.SetFloat("_OutlineBaseZOffset", fromlilToonMat.GetFloat("_OutlineZBias")); //---------------------------------------------------------------------------------------------------------------------- // Tessellation // (X) ...All... //---------------------------------------------------------------------------------------------------------------------- // For Multi //---------------------------------------------------------------------------------------------------------------------- // Save (Unused) //---------------------------------------------------------------------------------------------------------------------- // Advanced //---------------------------------------------------------------------------------------------------------------------- // Outline Advanced } static void SetMaterialAsIsSkin(Material m) { m.SetFloat(IsSkin, 1); // no keyword on/off is needed for _IsSkin // ... } static void SetMaterialAsIsFace(Material m) { m.SetFloat(IsFace, 1); m.EnableKeyword("_ISFACE"); } static void SetMaterialAsNoOutline(Material m) { // TODO: update if (m.GetFloat(SurfaceTypePreset) == 0) { m.SetFloat(SurfaceTypePreset, 1); } m.SetFloat(RenderOutline, 0); // no keyword on/off is needed for _RenderOutline // ... } public static void SetMaterialNiloToonSurfaceTypeAndProperties(Material m, NiloToonSurfaceTypePreset niloToonSurfaceTypePreset) { // fix render queue when it is out of expected range void ClampRenderQueueMinMax(Material m, int minRenderQueue, int maxRenderQueue) { if (m.renderQueue < minRenderQueue) m.renderQueue = minRenderQueue; if (m.renderQueue > maxRenderQueue) m.renderQueue = maxRenderQueue; } void ClampRenderQueueToGroup(Material m, RenderQueueGroup renderQueueGroup) { // from Unity's RenderQueue enum //public enum RenderQueue //{ // /// This render queue is rendered before any others. // Background = 1000, // /// Opaque geometry uses this queue. // Geometry = 2000, // /// Alpha tested geometry uses this queue. // AlphaTest = 2450, // /// Last render queue that is considered "opaque". // GeometryLast = 2500, // /// This render queue is rendered after Geometry and AlphaTest, in back-to-front order. // Transparent = 3000, // /// This render queue is meant for overlay effects. // Overlay = 4000, //} switch (renderQueueGroup) { case RenderQueueGroup.Opaque: ClampRenderQueueMinMax(m, 2000, 2450 - 1); break; case RenderQueueGroup.Cutout: ClampRenderQueueMinMax(m, 2450, 2500 - 1); break; // 2500 is SkyBox case RenderQueueGroup.Transparent: ClampRenderQueueMinMax(m, 2501, 4000 - 1); break; } } // hardcode matching NiloToonCharacter_SurfaceType_LWGUI_ShaderPropertyPreset.asset switch (niloToonSurfaceTypePreset) { case NiloToonSurfaceTypePreset.Opaque_Outline: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.Opaque_Outline); m.SetFloat("_SrcBlend", 1); m.SetFloat("_DstBlend", 0); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 1); //m.renderQueue = 2000; // matching preset, not -1 ClampRenderQueueToGroup(m, RenderQueueGroup.Opaque); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.Opaque: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.Opaque); m.SetFloat("_SrcBlend", 1); m.SetFloat("_DstBlend", 0); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 0); //m.renderQueue = 2000; // matching preset, not -1 ClampRenderQueueToGroup(m, RenderQueueGroup.Opaque); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 1); //m.renderQueue = 2499; ClampRenderQueueToGroup(m, RenderQueueGroup.Cutout); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.Transparent: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.Transparent); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 0); m.SetFloat("_RenderOutline", 0); //m.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; ClampRenderQueueToGroup(m, RenderQueueGroup.Transparent); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.Transparent_ZWrite: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.Transparent_ZWrite); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 0); //m.renderQueue = 2499; ClampRenderQueueToGroup(m, RenderQueueGroup.Cutout); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutOpaque_Outline: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutOpaque_Outline); m.SetFloat("_SrcBlend", 1); m.SetFloat("_DstBlend", 0); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 1); //m.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest; ClampRenderQueueToGroup(m, RenderQueueGroup.Cutout); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutOpaque: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutOpaque); m.SetFloat("_SrcBlend", 1); m.SetFloat("_DstBlend", 0); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 0); //m.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest; ClampRenderQueueToGroup(m, RenderQueueGroup.Cutout); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite_Outline: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite_Outline); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 1); //m.renderQueue = 2499; ClampRenderQueueToGroup(m, RenderQueueGroup.Cutout); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutTransparent: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutTransparent); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 0); m.SetFloat("_RenderOutline", 0); //m.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; ClampRenderQueueToGroup(m, RenderQueueGroup.Transparent); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutTransparent_ZWrite); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 0); //m.renderQueue = 2499; ClampRenderQueueToGroup(m, RenderQueueGroup.Cutout); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite_Outline: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite_Outline); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 1); //m.renderQueue = 3000; ClampRenderQueueToGroup(m, RenderQueueGroup.Transparent); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 0); //m.renderQueue = 3000; ClampRenderQueueToGroup(m, RenderQueueGroup.Transparent); m.SetFloat("_AlphaClip", 0); m.DisableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite_Outline: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite_Outline); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 1); //m.renderQueue = 3000; ClampRenderQueueToGroup(m, RenderQueueGroup.Transparent); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; case NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite: m.SetFloat(SurfaceTypePreset, (int)NiloToonSurfaceTypePreset.CutoutTransparentQueueTransparent_ZWrite); m.SetFloat("_SrcBlend", 5); m.SetFloat("_DstBlend", 10); m.SetFloat("_ZWrite", 1); m.SetFloat("_RenderOutline", 0); //m.renderQueue = 3000; ClampRenderQueueToGroup(m, RenderQueueGroup.Transparent); m.SetFloat("_AlphaClip", 1); m.EnableKeyword("_ALPHATEST_ON"); break; default: throw new NotImplementedException("Contact NiloToon's developer to support a new SurfaceType."); } } static bool TextureHasAlpha(Texture2D texture) { // Blit texture to a new RT to avoid non-Readable texture problem RenderTexture tempRT = RenderTexture.GetTemporary(texture.width, texture.height); Graphics.Blit(texture, tempRT); RenderTexture RTactiveCache = RenderTexture.active; RenderTexture.active = tempRT; // apply RT to our new Texture2D, so we can read it's per pixel alpha Texture2D readableTexture = new Texture2D(texture.width, texture.height); readableTexture.ReadPixels(new Rect(0, 0, tempRT.width, tempRT.height), 0, 0); readableTexture.Apply(); RenderTexture.active = RTactiveCache; RenderTexture.ReleaseTemporary(tempRT); Color[] pixels = readableTexture.GetPixels(); // this loop maybe slow depending on Texture size foreach (Color pixel in pixels) { if (pixel.a < 1f) { return true; } } return false; } /// /// Breaks the variant link of a material /// public static void BreakMaterialVariant(Material mat) { if (mat == null) return; // break (Material.parent only exists in Unity2022.1 or later) #if UNITY_2022_3_OR_NEWER mat.parent = null; #endif } //////////////////////////////////////////////////////////////////////////////////////////////////////// // copy from UniversalRenderPipelineMaterialUpgrader.cs //////////////////////////////////////////////////////////////////////////////////////////////////////// static void GetShaderNamesToIgnore(ref HashSet shadersToIgnore) { // all URP shader don't need an upgrade, since it is URP shader already! shadersToIgnore.Add("Universal Render Pipeline/Baked Lit"); shadersToIgnore.Add("Universal Render Pipeline/Lit"); shadersToIgnore.Add("Universal Render Pipeline/Particles/Lit"); shadersToIgnore.Add("Universal Render Pipeline/Particles/Simple Lit"); shadersToIgnore.Add("Universal Render Pipeline/Particles/Unlit"); shadersToIgnore.Add("Universal Render Pipeline/Simple Lit"); shadersToIgnore.Add("Universal Render Pipeline/Complex Lit"); shadersToIgnore.Add("Universal Render Pipeline/Nature/SpeedTree7"); shadersToIgnore.Add("Universal Render Pipeline/Nature/SpeedTree7 Billboard"); shadersToIgnore.Add("Universal Render Pipeline/Nature/SpeedTree8"); shadersToIgnore.Add("Universal Render Pipeline/2D/Sprite-Lit-Default"); shadersToIgnore.Add("Universal Render Pipeline/Terrain/Lit"); shadersToIgnore.Add("Universal Render Pipeline/Unlit"); shadersToIgnore.Add("Sprites/Default"); // NiloToonURP added all character shader to ignore list: shadersToIgnore.Add("Universal Render Pipeline/NiloToon/NiloToon_Character"); shadersToIgnore.Add("Universal Render Pipeline/NiloToon/NiloToon_Character Sticker(Multiply)"); shadersToIgnore.Add("Universal Render Pipeline/NiloToon/NiloToon_Character Sticker(Additive)"); // lilToon shader will be upgraded by NiloToon's script shadersToIgnore.Add("lilToon"); shadersToIgnore.Add("Hidden/lilToonOutline"); shadersToIgnore.Add("Hidden/lilToonTransparent"); shadersToIgnore.Add("Hidden/lilToonCutoutOutline"); shadersToIgnore.Add("Hidden/lilToonTransparentOutline"); // vrm mtoon will be upgraded by NiloToon's script shadersToIgnore.Add("UniGLTF/UniUnlit"); shadersToIgnore.Add("VRM/MToon"); shadersToIgnore.Add("VRM10/MToon10"); shadersToIgnore.Add("VRM10/Universal Render Pipeline/MToon10"); } static void GetUpgraders(ref List upgraders) { ///////////////////////////////////// // Unity Standard Upgraders // ///////////////////////////////////// upgraders.Add(new StandardUpgrader("Standard")); upgraders.Add(new StandardUpgrader("Standard (Specular setup)")); //////////////////////////////////// // Particle Upgraders // //////////////////////////////////// upgraders.Add(new ParticleUpgrader("Particles/Standard Surface")); upgraders.Add(new ParticleUpgrader("Particles/Standard Unlit")); upgraders.Add(new ParticleUpgrader("Particles/VertexLit Blended")); //////////////////////////////////// // Autodesk Interactive // //////////////////////////////////// upgraders.Add(new AutodeskInteractiveUpgrader("Autodesk Interactive")); } #if UNITY_EDITOR [MenuItem("Window/NiloToonURP/[Material] Convert Selected Materials to NiloToon", priority = 2)] [MenuItem("Assets/NiloToon/[Material] Convert Selected Materials to NiloToon", priority = 1100 + 2)] public static void ConvertSelectedMaterialsToNiloToon_Character() { var allselectedObjects = Selection.objects; List allInputMaterials = new List(); foreach (var selectedObject in allselectedObjects) { if (selectedObject is Material mat) { if (mat != null) { allInputMaterials.Add(mat); } } } AutoConvertMaterialsToNiloToon(allInputMaterials); } [MenuItem("Window/NiloToonURP/[Material] Convert Selected Materials to NiloToon", priority = 2, validate = true)] [MenuItem("Assets/NiloToon/[Material] Convert Selected Materials to NiloToon", priority = 1100 + 2, validate = true)] public static bool ValidateConvertSelectedMaterialsToNiloToon_Character() { var allselectedObjects = Selection.objects; return allselectedObjects.Any(selectedObject => selectedObject is Material); } #endif } }