2876 lines
150 KiB
C#

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 DepthTexRimLight3DRimMaskEnable =
Shader.PropertyToID("_DepthTexRimLight3DRimMaskEnable");
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
}
private sealed class MaterialCloneList : IDisposable
{
private readonly List<Material> materials;
public MaterialCloneList(IReadOnlyList<Material> sourceMaterials)
{
materials = new List<Material>(sourceMaterials.Count);
for (int i = 0; i < sourceMaterials.Count; i++)
{
Material material = sourceMaterials[i];
materials.Add(material != null ? Object.Instantiate(material) : null);
}
}
public int Count => materials.Count;
public Material this[int index] => materials[index];
public void Dispose()
{
foreach (Material material in materials)
{
if (material)
{
Object.DestroyImmediate(material);
}
}
materials.Clear();
}
}
public static void AutoConvertMaterialsToNiloToon(List<Material> 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");
var renderQueueRepackItems = new List<RenderQueueRepackItem>();
var renderQueueRepackMaterials = new HashSet<Material>();
// clone all original materials to a new List with the same order, for later reference, since we will edit the real material later
using MaterialCloneList allOriginalMaterialsClone = new MaterialCloneList(allTargetMaterials);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 (!HasUsableShader(matOriginal))
{
continue;
}
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 (IsLilToonMultiFamilyShader(matOriginal.shader))
{
niloToonSurfaceTypePresetIDArray[i] = ResolveLilToonMultiSurfaceTypePreset(matOriginal);
}
else 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
}
if (IsLilToonFurMaterial(matOriginal))
{
// NiloToonFurPass renders the opaque queue only. Keep converted fur renderable even when the lilToon source used a transparent fur mode.
niloToonSurfaceTypePresetIDArray[i] = NiloToonSurfaceTypePreset.CutoutOpaque;
}
// Do not use texture alpha to infer cutout: many models store non-transparency data in alpha.
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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)
{
if (mat == null)
{
continue;
}
// 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);
if (!HasUsableShader(mat))
{
mat.shader = builtinRPStandardShader;
EditorUtility.SetDirty(mat);
continue;
}
// 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<MaterialUpgrader> upgraders = new List<MaterialUpgrader>();
GetUpgraders(ref upgraders);
HashSet<string> shaderNamesToIgnore = new HashSet<string>();
GetShaderNamesToIgnore(ref shaderNamesToIgnore);
for (int i = 0; i < allTargetMaterials.Count; i++)
{
Material material = allTargetMaterials[i];
if (!ShouldUpgradeMaterialNonInteractively(material, shaderNamesToIgnore))
{
continue;
}
MaterialUpgrader.Upgrade(material, upgraders,
MaterialUpgrader.UpgradeFlags.LogMessageWhenNoUpgraderFound);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 (!HasUsableShader(mat))
{
continue;
}
bool hasUsableOriginalShader = HasUsableShader(originalMatClone);
string currentShaderName = mat.shader.name;
string originalShaderName = hasUsableOriginalShader ? originalMatClone.shader.name : string.Empty;
int sourceRenderQueue = hasUsableOriginalShader ? originalMatClone.renderQueue : mat.renderQueue;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 (currentShaderName.Contains("Particle") ||
currentShaderName.Contains("Sprite"))
{
continue;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if the current shader is not any NiloToon shader
// switch this shader to NiloToon_Character shader
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (!currentShaderName.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<string> IsNoOutlineFinalTargetNames =
IsFaceFinalTargetNames.Where(x => x != "face" && x != "head").ToList();
IsNoOutlineFinalTargetNames = IsNoOutlineFinalTargetNames.Concat(IsNoOutlineTargetNames).ToList();
List<string> IsNoOutlineExactTargetNames = new List<string>();
IsNoOutlineExactTargetNames = IsNoOutlineExactTargetNames.Concat(IsFaceExactTargetNames).ToList();
List<string> IsNoOutlineFinalBanNames = IsFaceFinalBanNames.ToList();
IsNoOutlineFinalBanNames = IsNoOutlineFinalBanNames.Concat(IsNoOutlineBanNames).ToList();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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);
// Group by the converted NiloToon preset. Source queues only preserve order inside the chosen opaque/transparent group.
bool targetUsesOpaqueQueue = mat.renderQueue <= (int)RenderQueue.GeometryLast;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// port common vrm00 mtoon00 & vrm10 mtoon10 to nilotoon
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (hasUsableOriginalShader &&
(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 (hasUsableOriginalShader && 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 (hasUsableOriginalShader &&
(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 (hasUsableOriginalShader && 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 (hasUsableOriginalShader &&
(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;
}
// Batch repack normally overwrites this value and uses originalMatClone.renderQueue as the ordering signal.
// Validated UniVRM MToon10 already includes this offset there; this legacy add only matters if repack falls back.
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 (originalShaderName.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 (!hasUsableOriginalShader ||
((originalMatClone.shader != niloToonCharShader) &&
!originalShaderName.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 (hasUsableOriginalShader && 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);
}
if (renderQueueRepackMaterials.Add(mat))
{
renderQueueRepackItems.Add(new RenderQueueRepackItem(
mat,
sourceRenderQueue,
i,
targetUsesOpaqueQueue));
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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);
}
}
RepackRenderQueuesPreservingRelativeOrder(renderQueueRepackItems);
foreach (RenderQueueRepackItem item in renderQueueRepackItems)
{
AutoDisableDepthTextureRimLightAndShadowIfNeeded(item.Material);
EditorUtility.SetDirty(item.Material);
}
}
private readonly struct RenderQueueRepackItem
{
public RenderQueueRepackItem(
Material material,
int sourceRenderQueue,
int originalIndex,
bool targetUsesOpaqueQueue)
{
Material = material;
SourceRenderQueue = sourceRenderQueue;
OriginalIndex = originalIndex;
TargetUsesOpaqueQueue = targetUsesOpaqueQueue;
}
public Material Material { get; }
public int SourceRenderQueue { get; }
public int OriginalIndex { get; }
public bool TargetUsesOpaqueQueue { get; }
}
private sealed class RenderQueueBucket
{
public int SourceRenderQueue;
public int AssignedRenderQueue;
public readonly List<RenderQueueRepackItem> Items = new List<RenderQueueRepackItem>();
}
private static void RepackRenderQueuesPreservingRelativeOrder(List<RenderQueueRepackItem> items)
{
RepackRenderQueueGroup(items, true, 0, (int)RenderQueue.GeometryLast);
RepackRenderQueueGroup(items, false, (int)RenderQueue.GeometryLast + 1, (int)RenderQueue.Overlay - 1);
}
private static void RepackRenderQueueGroup(
List<RenderQueueRepackItem> allItems,
bool targetUsesOpaqueQueue,
int minQueue,
int maxQueue)
{
List<RenderQueueRepackItem> groupItems = allItems
.Where(item => item.TargetUsesOpaqueQueue == targetUsesOpaqueQueue)
.OrderBy(item => item.SourceRenderQueue)
.ThenBy(item => item.OriginalIndex)
.ToList();
if (groupItems.Count == 0)
{
return;
}
List<RenderQueueBucket> buckets = CreateRenderQueueBuckets(groupItems);
if (buckets.Count > maxQueue - minQueue + 1)
{
Debug.LogWarning(
$"[NiloToon] Too many distinct render queues ({buckets.Count}) to preserve relative order inside {minQueue}..{maxQueue}.");
return;
}
for (int i = 0; i < buckets.Count; i++)
{
buckets[i].AssignedRenderQueue = Mathf.Clamp(buckets[i].SourceRenderQueue, minQueue, maxQueue);
if (i > 0 && buckets[i].AssignedRenderQueue <= buckets[i - 1].AssignedRenderQueue)
{
buckets[i].AssignedRenderQueue = buckets[i - 1].AssignedRenderQueue + 1;
}
}
if (buckets[buckets.Count - 1].AssignedRenderQueue > maxQueue)
{
buckets[buckets.Count - 1].AssignedRenderQueue = maxQueue;
for (int i = buckets.Count - 2; i >= 0; i--)
{
if (buckets[i].AssignedRenderQueue >= buckets[i + 1].AssignedRenderQueue)
{
buckets[i].AssignedRenderQueue = buckets[i + 1].AssignedRenderQueue - 1;
}
}
}
foreach (RenderQueueBucket bucket in buckets)
{
foreach (RenderQueueRepackItem item in bucket.Items)
{
item.Material.renderQueue = bucket.AssignedRenderQueue;
}
}
}
private static List<RenderQueueBucket> CreateRenderQueueBuckets(List<RenderQueueRepackItem> sortedItems)
{
var buckets = new List<RenderQueueBucket>();
foreach (RenderQueueRepackItem item in sortedItems)
{
RenderQueueBucket bucket = buckets.Count > 0 && buckets[buckets.Count - 1].SourceRenderQueue == item.SourceRenderQueue
? buckets[buckets.Count - 1]
: null;
if (bucket == null)
{
bucket = new RenderQueueBucket { SourceRenderQueue = item.SourceRenderQueue };
buckets.Add(bucket);
}
bucket.Items.Add(item);
}
return buckets;
}
private static void AutoDisableDepthTextureRimLightAndShadowIfNeeded(Material mat)
{
if (NiloToonUtils.NameHasKeyword(mat.name, "eye") ||
mat.renderQueue > (int)RenderQueue.GeometryLast)
{
mat.SetFloat(PerMaterialEnableDepthTextureRimLightAndShadow, 0);
}
}
private static bool IsLilToonMultiFamilyShader(Shader shader)
{
return shader != null &&
shader.name.Contains("lilToonMulti", StringComparison.Ordinal);
}
private static bool IsLilToonFurMaterial(Material material)
{
if (!HasUsableShader(material))
{
return false;
}
string shaderName = material.shader.name;
bool isLilToonFamily = shaderName.Contains("lilToon", StringComparison.Ordinal);
if (!isLilToonFamily)
{
return false;
}
if (shaderName.Contains("Fur", StringComparison.Ordinal))
{
return true;
}
if (IsLilToonMultiFamilyShader(material.shader) && material.HasProperty("_TransparentMode"))
{
int transparentMode = Mathf.RoundToInt(material.GetFloat("_TransparentMode"));
return transparentMode == 4 || transparentMode == 5;
}
return material.HasProperty("_FurNoiseMask") ||
material.HasProperty("_FurMask") ||
material.HasProperty("_FurLengthMask") ||
material.HasProperty("_FurVector") ||
material.HasProperty("_FurLayerNum");
}
private static NiloToonSurfaceTypePreset ResolveLilToonMultiSurfaceTypePreset(Material matOriginal)
{
int transparentMode = matOriginal.HasProperty("_TransparentMode")
? Mathf.RoundToInt(matOriginal.GetFloat("_TransparentMode"))
: 0;
bool useOutline = matOriginal.HasProperty("_UseOutline") && matOriginal.GetFloat("_UseOutline") > 0.5f;
bool zWrite = !matOriginal.HasProperty("_ZWrite") || matOriginal.GetFloat("_ZWrite") > 0.5f;
bool isTransparentQueue = matOriginal.renderQueue > 2500;
switch (transparentMode)
{
case 0:
return ResolveLilToonMultiOpaquePreset(useOutline, zWrite);
case 1:
return ResolveLilToonMultiCutoutPreset(useOutline, zWrite);
case 2:
return ResolveLilToonMultiTransparentPreset(useOutline, zWrite, isTransparentQueue);
case 3:
// lilToonMulti refraction uses its own shader path without outline and falls back closest to opaque surface family.
return ResolveLilToonMultiOpaquePreset(false, zWrite);
case 4:
// NiloToonFurPass renders opaque queue only, so converted fur must stay in the cutout/opaque family.
return ResolveLilToonMultiCutoutPreset(false, true);
case 5:
// lilToonMulti fur cutout uses alpha clip but does not expose an outline variant.
return ResolveLilToonMultiCutoutPreset(false, zWrite);
case 6:
// lilToonMulti gem is additive/transparent and does not expose an outline variant.
return ResolveLilToonMultiTransparentPreset(false, zWrite, isTransparentQueue);
default:
Debug.LogWarning(
$"Unsupported lilToonMulti _TransparentMode '{transparentMode}' on material '{matOriginal.name}'. Falling back to opaque surface family.");
return ResolveLilToonMultiOpaquePreset(false, zWrite);
}
}
private static NiloToonSurfaceTypePreset ResolveLilToonMultiOpaquePreset(
bool useOutline,
bool zWrite)
{
if (!zWrite)
{
return NiloToonSurfaceTypePreset.Transparent;
}
return useOutline
? NiloToonSurfaceTypePreset.Opaque_Outline
: NiloToonSurfaceTypePreset.Opaque;
}
private static NiloToonSurfaceTypePreset ResolveLilToonMultiTransparentPreset(
bool useOutline,
bool zWrite,
bool isTransparentQueue)
{
if (!zWrite)
{
return NiloToonSurfaceTypePreset.Transparent;
}
if (isTransparentQueue)
{
return useOutline
? NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite_Outline
: NiloToonSurfaceTypePreset.TransparentQueueTransparent_ZWrite;
}
return useOutline
? NiloToonSurfaceTypePreset.Transparent_ZWrite_Outline
: NiloToonSurfaceTypePreset.Transparent_ZWrite;
}
private static NiloToonSurfaceTypePreset ResolveLilToonMultiCutoutPreset(
bool useOutline,
bool zWrite)
{
if (!zWrite)
{
return NiloToonSurfaceTypePreset.CutoutTransparent;
}
// NiloToon has no cutout-opaque + transparent-queue preset, so the closest representable family stays in cutout opaque.
return useOutline
? NiloToonSurfaceTypePreset.CutoutOpaque_Outline
: NiloToonSurfaceTypePreset.CutoutOpaque;
}
private static void SetKeyword(Material material, string keyword, bool enabled)
{
if (enabled)
{
material.EnableKeyword(keyword);
}
else
{
material.DisableKeyword(keyword);
}
}
private static readonly Vector4 DefaultTextureScaleOffset = new Vector4(1f, 1f, 0f, 0f);
private static bool HasShaderProperty(Material material, string property, ShaderPropertyType propertyType)
{
if (!material || !material.shader)
{
return false;
}
int propertyIndex = material.shader.FindPropertyIndex(property);
return propertyIndex >= 0 && material.shader.GetPropertyType(propertyIndex) == propertyType;
}
private static bool HasFloatProperty(Material material, string property)
{
if (!material || !material.shader)
{
return false;
}
int propertyIndex = material.shader.FindPropertyIndex(property);
if (propertyIndex < 0)
{
return false;
}
ShaderPropertyType propertyType = material.shader.GetPropertyType(propertyIndex);
return propertyType == ShaderPropertyType.Float ||
propertyType == ShaderPropertyType.Range ||
propertyType.ToString() == "Int";
}
private static float GetFloatOrDefault(Material material, string property, float defaultValue = 0f)
{
return HasFloatProperty(material, property) ? material.GetFloat(property) : defaultValue;
}
private static Color GetColorOrDefault(Material material, string property, Color defaultValue)
{
return HasShaderProperty(material, property, ShaderPropertyType.Color) ? material.GetColor(property) : defaultValue;
}
private static Vector4 GetVectorOrDefault(Material material, string property, Vector4 defaultValue)
{
return HasShaderProperty(material, property, ShaderPropertyType.Vector) ? material.GetVector(property) : defaultValue;
}
private static Texture GetTextureOrNull(Material material, string property)
{
return HasShaderProperty(material, property, ShaderPropertyType.Texture) ? material.GetTexture(property) : null;
}
private static Vector4 GetTextureScaleOffsetOrDefault(Material material, string textureProperty)
{
if (!HasShaderProperty(material, textureProperty, ShaderPropertyType.Texture))
{
return DefaultTextureScaleOffset;
}
Vector2 scale = material.GetTextureScale(textureProperty);
Vector2 offset = material.GetTextureOffset(textureProperty);
return new Vector4(scale.x, scale.y, offset.x, offset.y);
}
private static void CopyFloat(Material source, Material destination, string sourceProperty, string destinationProperty)
{
if (!HasFloatProperty(source, sourceProperty) || !HasFloatProperty(destination, destinationProperty))
{
return;
}
destination.SetFloat(destinationProperty, source.GetFloat(sourceProperty));
}
private static void CopyColor(Material source, Material destination, string sourceProperty, string destinationProperty)
{
if (!HasShaderProperty(source, sourceProperty, ShaderPropertyType.Color) ||
!HasShaderProperty(destination, destinationProperty, ShaderPropertyType.Color))
{
return;
}
destination.SetColor(destinationProperty, source.GetColor(sourceProperty));
}
private static void CopyVector(Material source, Material destination, string sourceProperty, string destinationProperty)
{
if (!HasShaderProperty(source, sourceProperty, ShaderPropertyType.Vector) ||
!HasShaderProperty(destination, destinationProperty, ShaderPropertyType.Vector))
{
return;
}
destination.SetVector(destinationProperty, source.GetVector(sourceProperty));
}
private static void CopyTextureWithScaleOffset(Material source, Material destination, string sourceProperty, string destinationProperty)
{
if (!HasShaderProperty(source, sourceProperty, ShaderPropertyType.Texture) ||
!HasShaderProperty(destination, destinationProperty, ShaderPropertyType.Texture))
{
return;
}
destination.SetTexture(destinationProperty, source.GetTexture(sourceProperty));
destination.SetTextureScale(destinationProperty, source.GetTextureScale(sourceProperty));
destination.SetTextureOffset(destinationProperty, source.GetTextureOffset(sourceProperty));
}
private static void SetFloatIfHasProperty(Material material, string property, float value)
{
if (!HasFloatProperty(material, property))
{
return;
}
material.SetFloat(property, value);
}
private static void SetColorIfHasProperty(Material material, string property, Color value)
{
if (!material.HasProperty(property))
{
return;
}
material.SetColor(property, value);
}
private static void SetTextureIfHasProperty(Material material, string property, Texture value)
{
if (!material.HasProperty(property))
{
return;
}
material.SetTexture(property, value);
}
private static void SetLilToonShadowAOMinMax(Material material, string minProperty, string maxProperty, float scale, float offset)
{
if (Mathf.Abs(scale) < 0.00001f)
{
SetFloatIfHasProperty(material, minProperty, 0f);
SetFloatIfHasProperty(material, maxProperty, 1f);
return;
}
SetFloatIfHasProperty(material, minProperty, Mathf.Clamp(-offset / scale, -0.01f, 1.01f));
SetFloatIfHasProperty(material, maxProperty, Mathf.Clamp((1f - offset) / scale, -0.01f, 1.01f));
}
private static void PortLilToonShadowAORemap(Material source, Material destination)
{
if (HasShaderProperty(source, "_ShadowAOShift", ShaderPropertyType.Vector))
{
Vector4 shadowAOShift = source.GetVector("_ShadowAOShift");
SetLilToonShadowAOMinMax(destination, "_lilShadowAO1Min", "_lilShadowAO1Max", shadowAOShift.x, shadowAOShift.y);
SetLilToonShadowAOMinMax(destination, "_lilShadowAO2Min", "_lilShadowAO2Max", shadowAOShift.z, shadowAOShift.w);
}
if (HasShaderProperty(source, "_ShadowAOShift2", ShaderPropertyType.Vector))
{
Vector4 shadowAOShift2 = source.GetVector("_ShadowAOShift2");
SetLilToonShadowAOMinMax(destination, "_lilShadowAO3Min", "_lilShadowAO3Max", shadowAOShift2.x, shadowAOShift2.y);
}
}
private static void PortLilToonShadowModeProperties(Material source, Material destination)
{
CopyFloat(source, destination, "_ShadowMaskType", "_lilShadowMaskType");
CopyTextureWithScaleOffset(source, destination, "_ShadowStrengthMask", "_lilShadowStrengthMask");
CopyFloat(source, destination, "_ShadowStrength", "_lilShadowStrength");
CopyFloat(source, destination, "_ShadowStrengthMaskLOD", "_lilShadowStrengthMaskLOD");
CopyFloat(source, destination, "_ShadowFlatBorder", "_lilShadowFlatBorder");
CopyFloat(source, destination, "_ShadowFlatBlur", "_lilShadowFlatBlur");
CopyFloat(source, destination, "_ShadowColorType", "_lilShadowColorType");
CopyTextureWithScaleOffset(source, destination, "_ShadowColorTex", "_lilShadowColorTex");
CopyTextureWithScaleOffset(source, destination, "_Shadow2ndColorTex", "_lilShadow2ndColorTex");
CopyTextureWithScaleOffset(source, destination, "_Shadow3rdColorTex", "_lilShadow3rdColorTex");
CopyColor(source, destination, "_ShadowColor", "_lilShadowColor");
CopyColor(source, destination, "_Shadow2ndColor", "_lilShadow2ndColor");
CopyColor(source, destination, "_Shadow3rdColor", "_lilShadow3rdColor");
CopyFloat(source, destination, "_ShadowBorder", "_lilShadowBorder");
CopyFloat(source, destination, "_ShadowBlur", "_lilShadowBlur");
CopyFloat(source, destination, "_ShadowNormalStrength", "_lilShadowNormalStrength");
CopyFloat(source, destination, "_ShadowReceive", "_lilShadowReceive");
CopyFloat(source, destination, "_Shadow2ndBorder", "_lilShadow2ndBorder");
CopyFloat(source, destination, "_Shadow2ndBlur", "_lilShadow2ndBlur");
CopyFloat(source, destination, "_Shadow2ndNormalStrength", "_lilShadow2ndNormalStrength");
CopyFloat(source, destination, "_Shadow2ndReceive", "_lilShadow2ndReceive");
CopyFloat(source, destination, "_Shadow3rdBorder", "_lilShadow3rdBorder");
CopyFloat(source, destination, "_Shadow3rdBlur", "_lilShadow3rdBlur");
CopyFloat(source, destination, "_Shadow3rdNormalStrength", "_lilShadow3rdNormalStrength");
CopyFloat(source, destination, "_Shadow3rdReceive", "_lilShadow3rdReceive");
CopyColor(source, destination, "_ShadowBorderColor", "_lilShadowBorderColor");
CopyFloat(source, destination, "_ShadowBorderRange", "_lilShadowBorderRange");
CopyFloat(source, destination, "_ShadowMainStrength", "_lilShadowMainStrength");
CopyFloat(source, destination, "_ShadowEnvStrength", "_lilShadowEnvStrength");
CopyFloat(source, destination, "_AAStrength", "_lilAAStrength");
CopyTextureWithScaleOffset(source, destination, "_ShadowBlurMask", "_lilShadowBlurMask");
CopyFloat(source, destination, "_ShadowBlurMaskLOD", "_lilShadowBlurMaskLOD");
CopyTextureWithScaleOffset(source, destination, "_ShadowBorderMask", "_lilShadowBorderMask");
CopyFloat(source, destination, "_ShadowBorderMaskLOD", "_lilShadowBorderMaskLOD");
CopyFloat(source, destination, "_ShadowPostAO", "_lilShadowPostAO");
}
private static void DisableNativeNiloMatCapGroups(Material material)
{
material.SetFloat("_UseMatCapAlphaBlend", 0);
material.SetFloat("_UseMatCapAdditive", 0);
material.SetFloat("_UseMatCapOcclusion", 0);
material.DisableKeyword("_MATCAP_BLEND");
material.DisableKeyword("_MATCAP_ADD");
material.DisableKeyword("_MATCAP_OCCLUSION");
}
private static void PortLilToonMatCapLayerToGeneric(
Material source,
Material destination,
string sourceUse,
string destinationUse,
string destinationKeyword,
string sourceColor,
string destinationColor,
string sourceMap,
string destinationMap,
string sourceMainStrength,
string destinationMainStrength,
string sourceBlendUv1,
string destinationBlendUv1,
string sourceZRotCancel,
string destinationZRotCancel,
string sourcePerspective,
string destinationPerspective,
string sourceVrParallaxStrength,
string destinationVrParallaxStrength,
string sourceBlend,
string destinationBlend,
string sourceMask,
string destinationMask,
string sourceEnableLighting,
string destinationEnableLighting,
string sourceShadowMask,
string destinationShadowMask,
string sourceBackfaceMask,
string destinationBackfaceMask,
string sourceLod,
string destinationLod,
string sourceBlendMode,
string destinationBlendMode,
string sourceApplyTransparency,
string destinationApplyTransparency,
string sourceNormalStrength,
string destinationNormalStrength,
string sourceUseCustomNormal,
string destinationUseCustomNormal,
string destinationCustomNormalKeyword,
string sourceBumpMap,
string destinationBumpMap,
string sourceBumpScale,
string destinationBumpScale)
{
CopyFloat(source, destination, sourceUse, destinationUse);
CopyColor(source, destination, sourceColor, destinationColor);
CopyTextureWithScaleOffset(source, destination, sourceMap, destinationMap);
CopyFloat(source, destination, sourceMainStrength, destinationMainStrength);
CopyVector(source, destination, sourceBlendUv1, destinationBlendUv1);
CopyFloat(source, destination, sourceZRotCancel, destinationZRotCancel);
CopyFloat(source, destination, sourcePerspective, destinationPerspective);
CopyFloat(source, destination, sourceVrParallaxStrength, destinationVrParallaxStrength);
CopyFloat(source, destination, sourceBlend, destinationBlend);
CopyTextureWithScaleOffset(source, destination, sourceMask, destinationMask);
CopyFloat(source, destination, sourceEnableLighting, destinationEnableLighting);
CopyFloat(source, destination, sourceShadowMask, destinationShadowMask);
CopyFloat(source, destination, sourceBackfaceMask, destinationBackfaceMask);
CopyFloat(source, destination, sourceLod, destinationLod);
CopyFloat(source, destination, sourceBlendMode, destinationBlendMode);
CopyFloat(source, destination, sourceApplyTransparency, destinationApplyTransparency);
CopyFloat(source, destination, sourceNormalStrength, destinationNormalStrength);
CopyFloat(source, destination, sourceUseCustomNormal, destinationUseCustomNormal);
CopyTextureWithScaleOffset(source, destination, sourceBumpMap, destinationBumpMap);
CopyFloat(source, destination, sourceBumpScale, destinationBumpScale);
bool isEnabled = HasFloatProperty(source, sourceUse) && source.GetFloat(sourceUse) > 0.5f;
bool useCustomNormal = HasFloatProperty(source, sourceUseCustomNormal) && source.GetFloat(sourceUseCustomNormal) > 0.5f;
SetKeyword(destination, destinationKeyword, isEnabled);
SetKeyword(destination, destinationCustomNormalKeyword, isEnabled && useCustomNormal);
}
private static void PortLilToonRimToGenericRimLight3D(Material source, Material destination)
{
CopyFloat(source, destination, "_UseRim", "_UseGenericRimLight3D");
CopyColor(source, destination, "_RimColor", "_GenericRimLight3DColor");
CopyTextureWithScaleOffset(source, destination, "_RimColorTex", "_GenericRimLight3DColorTex");
CopyFloat(source, destination, "_RimMainStrength", "_GenericRimLight3DMainStrength");
CopyFloat(source, destination, "_RimEnableLighting", "_GenericRimLight3DEnableLighting");
CopyFloat(source, destination, "_RimShadowMask", "_GenericRimLight3DShadowMask");
CopyFloat(source, destination, "_RimBackfaceMask", "_GenericRimLight3DBackfaceMask");
CopyFloat(source, destination, "_RimBlendMode", "_GenericRimLight3DBlendMode");
CopyFloat(source, destination, "_RimDirStrength", "_GenericRimLight3DDirStrength");
CopyFloat(source, destination, "_RimDirRange", "_GenericRimLight3DDirRange");
CopyFloat(source, destination, "_RimBorder", "_GenericRimLight3DBorder");
CopyFloat(source, destination, "_RimBlur", "_GenericRimLight3DBlur");
CopyFloat(source, destination, "_RimIndirRange", "_GenericRimLight3DIndirRange");
CopyColor(source, destination, "_RimIndirColor", "_GenericRimLight3DIndirColor");
CopyFloat(source, destination, "_RimIndirBorder", "_GenericRimLight3DIndirBorder");
CopyFloat(source, destination, "_RimIndirBlur", "_GenericRimLight3DIndirBlur");
CopyFloat(source, destination, "_RimNormalStrength", "_GenericRimLight3DNormalStrength");
CopyFloat(source, destination, "_RimFresnelPower", "_GenericRimLight3DFresnelPower");
CopyFloat(source, destination, "_RimVRParallaxStrength", "_GenericRimLight3DVRParallaxStrength");
if (destination.HasProperty("_GenericRimLight3DAlpha"))
{
destination.SetFloat("_GenericRimLight3DAlpha", 1f);
}
bool isEnabled = HasFloatProperty(source, "_UseRim") && source.GetFloat("_UseRim") > 0.5f;
SetKeyword(destination, "_GENERIC_RIMLIGHT3D", isEnabled);
}
private static void SetFloatClampedIfHasProperty(Material source, Material destination, string sourceProperty, string destinationProperty, float min, float max)
{
if (!source.HasProperty(sourceProperty) || !destination.HasProperty(destinationProperty))
{
return;
}
destination.SetFloat(destinationProperty, Mathf.Clamp(source.GetFloat(sourceProperty), min, max));
}
private static void SetNiloFurNoiseTilingFromLilToon(Material source, Material destination)
{
if (!source.HasProperty("_FurNoiseMask") || !destination.HasProperty("_NiloFurNoiseTiling"))
{
return;
}
Vector2 scale = source.GetTextureScale("_FurNoiseMask");
Vector2 offset = source.GetTextureOffset("_FurNoiseMask");
destination.SetVector("_NiloFurNoiseTiling", new Vector4(scale.x, scale.y, offset.x, offset.y));
}
private static void SetDefaultFurNoiseIfNeeded(Material destination)
{
if (!destination.HasProperty("_NiloFurNoiseTex") || destination.GetTexture("_NiloFurNoiseTex") != null)
{
return;
}
Texture2D defaultFurNoise =
AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/NiloToonURP/Textures/NiloFurNoise.png");
if (defaultFurNoise != null)
{
destination.SetTexture("_NiloFurNoiseTex", defaultFurNoise);
}
}
private static void PortLilToonFurProperties(Material source, Material destination)
{
if (!IsLilToonFurMaterial(source))
{
return;
}
SetMaterialNiloToonSurfaceTypeAndProperties(destination, NiloToonSurfaceTypePreset.CutoutOpaque);
SetFloatIfHasProperty(destination, "_EnableFur", 1f);
SetFloatIfHasProperty(destination, "_NiloFurStrength", 1f);
SetFloatIfHasProperty(destination, "_AllowRenderURPUniversalForwardOnlyPass", 1f);
SetKeyword(destination, "_NILOTOON_FUR", true);
destination.SetShaderPassEnabled("UniversalForwardOnly", true);
destination.SetShaderPassEnabled("NiloToonFur", true);
destination.SetShaderPassEnabled("NiloToonFurDepthPrepass", true);
destination.SetShaderPassEnabled("NiloToonFurPrepassBufferDepth", true);
destination.SetShaderPassEnabled("NiloToonFurPrepassBufferAlpha", true);
CopyTextureWithScaleOffset(source, destination, "_FurNoiseMask", "_NiloFurNoiseTex");
SetNiloFurNoiseTilingFromLilToon(source, destination);
SetDefaultFurNoiseIfNeeded(destination);
CopyTextureWithScaleOffset(source, destination, "_FurMask", "_NiloFurMask");
CopyTextureWithScaleOffset(source, destination, "_FurLengthMask", "_NiloFurLengthMask");
CopyTextureWithScaleOffset(source, destination, "_FurVectorTex", "_NiloFurVectorTex");
bool hasVectorTexture = destination.HasProperty("_NiloFurVectorTex") &&
destination.GetTexture("_NiloFurVectorTex") != null;
SetKeyword(destination, "_NILOTOON_FUR_VECTORTEX", hasVectorTexture);
CopyFloat(source, destination, "_FurVectorScale", "_NiloFurVectorScale");
if (source.HasProperty("_FurVector") && destination.HasProperty("_NiloFurVector"))
{
Vector4 furVector = source.GetVector("_FurVector");
destination.SetVector("_NiloFurVector", new Vector4(furVector.x, furVector.y, furVector.z, 0f));
SetFloatIfHasProperty(destination, "_NiloFurLength", Mathf.Max(0f, furVector.w));
}
CopyFloat(source, destination, "_VertexColor2FurVector", "_VertexColor2FurVector");
CopyFloat(source, destination, "_FurGravity", "_NiloFurGravity");
CopyFloat(source, destination, "_FurRandomize", "_NiloFurRandomize");
CopyFloat(source, destination, "_FurRootOffset", "_NiloFurRootOffset");
CopyFloat(source, destination, "_FurCutoutLength", "_NiloFurCutoutLength");
CopyFloat(source, destination, "_FurCull", "_NiloFurCull");
CopyColor(source, destination, "_FurRimColor", "_NiloFurRimColor");
CopyFloat(source, destination, "_FurRimFresnelPower", "_NiloFurRimFresnelPower");
CopyFloat(source, destination, "_FurRimAntiLight", "_NiloFurRimAntiLight");
if (source.HasProperty("_FurAO"))
{
float furAO = source.GetFloat("_FurAO");
SetFloatIfHasProperty(destination, "_NiloFurOcclusionShadowAO", furAO);
SetFloatIfHasProperty(destination, "_NiloFurColorDarkenAO", furAO);
}
SetFloatClampedIfHasProperty(source, destination, "_FurLayerNum", "_NiloFurLayerNum", 1f, 2f);
}
private static void PortLilToonEnvironmentReflectionProperties(Material source, Material destination)
{
float useEnvironmentReflection =
GetFloatOrDefault(source, "_UseReflection", 0f) *
GetFloatOrDefault(source, "_ApplyReflection", 0f);
// Keep the native NiloToon environment reflection group as data-only for lilToon conversion.
// The actual lilToon-compatible shading path is handled separately by Generic Reflection.
SetFloatIfHasProperty(destination, "_ReceiveEnvironmentReflection", 0f);
SetKeyword(destination, "_ENVIRONMENTREFLECTIONS", false);
Color reflectionColor = GetColorOrDefault(source, "_ReflectionColor", Color.white);
Color cubeColor = GetColorOrDefault(source, "_ReflectionCubeColor", Color.white);
SetFloatIfHasProperty(destination, "_EnvironmentReflectionUsage", reflectionColor.a);
// lilToon uses _Reflectance as the dielectric Fresnel input, not as total environment brightness.
SetFloatIfHasProperty(destination, "_EnvironmentReflectionBrightness", 1f);
SetFloatIfHasProperty(destination, "_EnvironmentReflectionTintAlbedo",
GetFloatOrDefault(source, "_Metallic", 0f));
SetColorIfHasProperty(destination, "_EnvironmentReflectionColor",
new Color(
reflectionColor.r * cubeColor.r,
reflectionColor.g * cubeColor.g,
reflectionColor.b * cubeColor.b,
1f));
Texture reflectionColorTex = source.HasProperty("_ReflectionColorTex")
? source.GetTexture("_ReflectionColorTex")
: null;
SetTextureIfHasProperty(destination, "_EnvironmentReflectionColorMaskMap", reflectionColorTex);
float lilToonBlendMode = GetFloatOrDefault(source, "_ReflectionBlendMode", 1f);
bool useAdditiveBlend = Mathf.Approximately(lilToonBlendMode, 1f) || Mathf.Approximately(lilToonBlendMode, 2f);
SetFloatIfHasProperty(destination, "_EnvironmentReflectionApplyReplaceBlending", useAdditiveBlend ? 0f : 1f);
SetFloatIfHasProperty(destination, "_EnvironmentReflectionApplyAddBlending", useAdditiveBlend ? 1f : 0f);
Texture reflectionCubemap = source.HasProperty("_ReflectionCubeTex")
? source.GetTexture("_ReflectionCubeTex")
: null;
SetTextureIfHasProperty(destination, "_EnvironmentReflectionOverrideCubemap", reflectionCubemap);
bool useOverrideCubemap =
useEnvironmentReflection > 0.5f &&
GetFloatOrDefault(source, "_ReflectionCubeOverride", 0f) > 0.5f &&
reflectionCubemap != null;
SetFloatIfHasProperty(destination, "_EnvironmentReflectionOverrideCubemapOn", useOverrideCubemap ? 1f : 0f);
SetKeyword(destination, "_ENVIRONMENTREFLECTIONS_OVERRIDE_CUBEMAP", false);
}
private static void PortLilToonReflectionToGenericReflection(Material source, Material destination)
{
float useReflection = GetFloatOrDefault(source, "_UseReflection", 0f);
float applySpecular = GetFloatOrDefault(source, "_ApplySpecular", 1f);
float applyReflection = GetFloatOrDefault(source, "_ApplyReflection", 0f);
Texture reflectionCubemap = source.HasProperty("_ReflectionCubeTex")
? source.GetTexture("_ReflectionCubeTex")
: null;
bool useGenericReflection = useReflection > 0.5f;
SetFloatIfHasProperty(destination, "_UseGenericReflection", useGenericReflection ? 1f : 0f);
SetKeyword(destination, "_GENERIC_REFLECTION", useGenericReflection);
SetTextureIfHasProperty(destination, "_GenericReflectionCubemap", reflectionCubemap);
CopyTextureWithScaleOffset(source, destination, "_SmoothnessTex", "_GenericReflectionSmoothnessMap");
CopyTextureWithScaleOffset(source, destination, "_ReflectionColorTex", "_GenericReflectionColorMaskMap");
CopyTextureWithScaleOffset(source, destination, "_MetallicGlossMap", "_GenericReflectionMetallicMap");
Color reflectionColor = GetColorOrDefault(source, "_ReflectionColor", Color.white);
SetColorIfHasProperty(destination, "_GenericReflectionColor", reflectionColor);
SetColorIfHasProperty(destination, "_GenericReflectionCubeColor",
GetColorOrDefault(source, "_ReflectionCubeColor", Color.black));
SetFloatIfHasProperty(destination, "_GenericReflectionBlend", 1f);
SetFloatIfHasProperty(destination, "_GenericReflectionBlendMode",
GetFloatOrDefault(source, "_ReflectionBlendMode", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionSmoothness",
GetFloatOrDefault(source, "_Smoothness", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionGSAAStrength",
GetFloatOrDefault(source, "_GSAAStrength", 0f));
SetFloatIfHasProperty(destination, "_GenericReflectionApplySpecular", applySpecular);
SetFloatIfHasProperty(destination, "_GenericReflectionApplySpecularFA",
GetFloatOrDefault(source, "_ApplySpecularFA", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionSpecularToon",
GetFloatOrDefault(source, "_SpecularToon", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionSpecularNormalStrength",
GetFloatOrDefault(source, "_SpecularNormalStrength", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionSpecularBorder",
GetFloatOrDefault(source, "_SpecularBorder", 0.5f));
SetFloatIfHasProperty(destination, "_GenericReflectionSpecularBlur",
GetFloatOrDefault(source, "_SpecularBlur", 0f));
SetFloatIfHasProperty(destination, "_GenericReflectionApplyReflection", applyReflection);
SetFloatIfHasProperty(destination, "_GenericReflectionReflectance",
GetFloatOrDefault(source, "_Reflectance", 0.04f));
SetFloatIfHasProperty(destination, "_GenericReflectionMetallic",
GetFloatOrDefault(source, "_Metallic", 0f));
SetFloatIfHasProperty(destination, "_GenericReflectionCubeOverride",
GetFloatOrDefault(source, "_ReflectionCubeOverride", 0f));
SetFloatIfHasProperty(destination, "_GenericReflectionCubeEnableLighting",
GetFloatOrDefault(source, "_ReflectionCubeEnableLighting", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionApplyTransparency",
GetFloatOrDefault(source, "_ReflectionApplyTransparency", 1f));
SetFloatIfHasProperty(destination, "_GenericReflectionNormalStrength",
GetFloatOrDefault(source, "_ReflectionNormalStrength", 1f));
}
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",
GetFloatOrDefault(fromlilToonMat, "_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)
SetFloatIfHasProperty(toNiloToonMat, "_AsUnlit", 0f);
// (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",
GetFloatOrDefault(fromlilToonMat,
"_BackfaceForceShadow")); // lilToon: float bfshadow = (fd.facing < 0.0) ? 1.0 - _BackfaceForceShadow : 1.0;
toNiloToonMat.SetColor("_BackFaceBaseMapReplaceColor",
GetColorOrDefault(fromlilToonMat,
"_BackfaceColor",
Color.clear)); // 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))
// (Same via lilToon shadow mode) _lilAAStrength
// (?) _UseDither (lilToon: dither fade0out per material)
// (?) _DitherTex (lilToon: dither fadeout per material)
// (?) _DitherMaxValue (lilToon: dither fadeout per material)
//----------------------------------------------------------------------------------------------------------------------
// Main
toNiloToonMat.SetColor("_BaseColor", GetColorOrDefault(fromlilToonMat, "_Color", Color.white));
toNiloToonMat.SetTexture("_BaseMap", GetTextureOrNull(fromlilToonMat, "_MainTex"));
toNiloToonMat.SetVector("_BaseMap_ST", GetTextureScaleOffsetOrDefault(fromlilToonMat, "_MainTex")); // auto uniform by Unity
// (!) _MainTex_ScrollRotate // TODO: apply the BaseMap's uv, not UV0!
if (HasShaderProperty(fromlilToonMat, "_MainTexHSVG", ShaderPropertyType.Vector))
{
Vector4 mainTexHSVG = GetVectorOrDefault(fromlilToonMat, "_MainTexHSVG", new Vector4(0f, 1f, 1f, 1f));
toNiloToonMat.SetFloat("_BaseMapHue", mainTexHSVG.x);
toNiloToonMat.SetFloat("_BaseMapSaturation", mainTexHSVG.y);
toNiloToonMat.SetFloat("_BaseMapValue", mainTexHSVG.z);
toNiloToonMat.SetFloat("_BaseMapGamma", mainTexHSVG.w);
}
// (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)
Texture baseMapHSVGMaskTex = GetTextureOrNull(fromlilToonMat, "_MainColorAdjustMask");
toNiloToonMat.SetFloat("_UseBaseMapHSVGMask", baseMapHSVGMaskTex ? 1 : 0);
toNiloToonMat.SetTexture("_BaseMapHSVGMaskTex", baseMapHSVGMaskTex);
if (baseMapHSVGMaskTex)
{
toNiloToonMat.EnableKeyword("_BASEMAP_HSVG_MASK");
}
else
{
toNiloToonMat.DisableKeyword("_BASEMAP_HSVG_MASK");
}
//----------------------------------------------------------------------------------------------------------------------
// Main2nd (port to NiloToon's BaseMapStackingLayer1)
float _UseMain2ndTex = GetFloatOrDefault(fromlilToonMat, "_UseMain2ndTex");
toNiloToonMat.SetFloat("_BaseMapStackingLayer1Enable", _UseMain2ndTex);
if (_UseMain2ndTex > 0.5)
{
toNiloToonMat.EnableKeyword("_BASEMAP_STACKING_LAYER1");
}
else
{
toNiloToonMat.DisableKeyword("_BASEMAP_STACKING_LAYER1");
}
toNiloToonMat.SetColor("_BaseMapStackingLayer1TintColor", GetColorOrDefault(fromlilToonMat, "_Color2nd", Color.white));
toNiloToonMat.SetTexture("_BaseMapStackingLayer1Tex", GetTextureOrNull(fromlilToonMat, "_Main2ndTex"));
toNiloToonMat.SetVector("_BaseMapStackingLayer1TexUVScaleOffset",
GetTextureScaleOffsetOrDefault(fromlilToonMat, "_Main2ndTex"));
// liltoon / nilotoon are both in degree
toNiloToonMat.SetFloat("_BaseMapStackingLayer1TexUVRotatedAngle",
GetFloatOrDefault(fromlilToonMat, "_Main2ndTexAngle") * 180f / Mathf.PI);
{
Vector4 _Main2ndTex_ScrollRotate = GetVectorOrDefault(fromlilToonMat, "_Main2ndTex_ScrollRotate", Vector4.zero);
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", GetFloatOrDefault(fromlilToonMat, "_Main2ndTex_UVMode"));
toNiloToonMat.SetFloat("_BaseMapStackingLayer1ApplytoFaces", GetFloatOrDefault(fromlilToonMat, "_Main2ndTex_Cull"));
// (X) _Main2ndTexDecalAnimation
// (X) _Main2ndTexDecalSubParam
// (X) _Main2ndTexIsDecal
// (X) _Main2ndTexIsLeftOnly
// (X) _Main2ndTexIsRightOnly
// (X) _Main2ndTexShouldCopy
// (X) _Main2ndTexShouldFlipMirror
// (X) _Main2ndTexShouldFlipCopy
// (X) _Main2ndTexIsMSDF
toNiloToonMat.SetTexture("_BaseMapStackingLayer1MaskTex", GetTextureOrNull(fromlilToonMat, "_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 = GetFloatOrDefault(fromlilToonMat, "_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 = GetFloatOrDefault(fromlilToonMat, "_UseMain3rdTex");
toNiloToonMat.SetFloat("_BaseMapStackingLayer2Enable", _UseMain3rdTex);
if (_UseMain3rdTex == 1)
{
toNiloToonMat.EnableKeyword("_BASEMAP_STACKING_LAYER2");
}
else
{
toNiloToonMat.DisableKeyword("_BASEMAP_STACKING_LAYER2");
}
toNiloToonMat.SetColor("_BaseMapStackingLayer2TintColor", GetColorOrDefault(fromlilToonMat, "_Color3rd", Color.white));
toNiloToonMat.SetTexture("_BaseMapStackingLayer2Tex", GetTextureOrNull(fromlilToonMat, "_Main3rdTex"));
toNiloToonMat.SetVector("_BaseMapStackingLayer2TexUVScaleOffset",
GetTextureScaleOffsetOrDefault(fromlilToonMat, "_Main3rdTex"));
// liltoon / nilotoon are both in degree
toNiloToonMat.SetFloat("_BaseMapStackingLayer2TexUVRotatedAngle",
GetFloatOrDefault(fromlilToonMat, "_Main3rdTexAngle"));
{
Vector4 _Main3rdTex_ScrollRotate = GetVectorOrDefault(fromlilToonMat, "_Main3rdTex_ScrollRotate", Vector4.zero);
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", GetFloatOrDefault(fromlilToonMat, "_Main3rdTex_UVMode"));
toNiloToonMat.SetFloat("_BaseMapStackingLayer2ApplytoFaces", GetFloatOrDefault(fromlilToonMat, "_Main3rdTex_Cull"));
// (X) _Main3rdTexDecalAnimation
// (X) _Main3rdTexDecalSubParam
// (X) _Main3rdTexIsDecal
// (X) _Main3rdTexIsLeftOnly
// (X) _Main3rdTexIsRightOnly
// (X) _Main3rdTexShouldCopy
// (X) _Main3rdTexShouldFlipMirror
// (X) _Main3rdTexShouldFlipCopy
// (X) _Main3rdTexIsMSDF
toNiloToonMat.SetTexture("_BaseMapStackingLayer2MaskTex", GetTextureOrNull(fromlilToonMat, "_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 = GetFloatOrDefault(fromlilToonMat, "_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)GetFloatOrDefault(fromlilToonMat, "_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", GetTextureOrNull(fromlilToonMat, "_AlphaMask"));
// liltoon GUI's invert toggle is not a property, it translate to a MAD (* scale + value)
toNiloToonMat.SetFloat("_AlphaOverrideTexValueScale", GetFloatOrDefault(fromlilToonMat, "_AlphaMaskScale", 1f));
toNiloToonMat.SetFloat("_AlphaOverrideTexValueOffset", GetFloatOrDefault(fromlilToonMat, "_AlphaMaskValue"));
//----------------------------------------------------------------------------------------------------------------------
// NormalMap
int _UseBumpMap = (int)GetFloatOrDefault(fromlilToonMat, "_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", GetFloatOrDefault(fromlilToonMat, "_UseShadow"));
SetFloatIfHasProperty(toNiloToonMat, "_ShadowColorMode", 1f);
SetKeyword(toNiloToonMat, "_SHADOW_MODE_LILTOON", true);
PortLilToonShadowModeProperties(fromlilToonMat, toNiloToonMat);
float shadowNormalStrength = GetFloatOrDefault(fromlilToonMat, "_ShadowNormalStrength", 1f);
toNiloToonMat.SetFloat("_MainLightSkinDiffuseNormalMapStrength", shadowNormalStrength);
toNiloToonMat.SetFloat("_MainLightNonSkinDiffuseNormalMapStrength", shadowNormalStrength);
PortLilToonShadowAORemap(fromlilToonMat, toNiloToonMat);
Texture2D occlusionMap = GetTextureOrNull(fromlilToonMat, "_ShadowBorderMask") as Texture2D;
toNiloToonMat.SetTexture("_OcclusionMap", occlusionMap);
toNiloToonMat.SetFloat("_UseOcclusion", 0);
toNiloToonMat.DisableKeyword("_OCCLUSIONMAP");
// _ShadowMainStrength -> _SelfShadowAlbedoMulStrength (both Range(0,1), copied 1:1).
// Note: lite variants (ltsl_*) don't declare _ShadowMainStrength; CopyFloat silently no-ops via HasProperty.
CopyFloat(fromlilToonMat, toNiloToonMat, "_ShadowMainStrength", "_SelfShadowAlbedoMulStrength");
//----------------------------------------------------------------------------------------------------------------------
// Rim Shade
//----------------------------------------------------------------------------------------------------------------------
// Reflection
PortLilToonEnvironmentReflectionProperties(fromlilToonMat, toNiloToonMat);
PortLilToonReflectionToGenericReflection(fromlilToonMat, toNiloToonMat);
bool genericReflectionOwnsLilToonSpecular =
GetFloatOrDefault(toNiloToonMat, "_UseGenericReflection", 0f) > 0.5f;
float useLilToonDirectSpecular =
genericReflectionOwnsLilToonSpecular
? 0f
: GetFloatOrDefault(fromlilToonMat, "_UseReflection") * GetFloatOrDefault(fromlilToonMat, "_ApplySpecular");
toNiloToonMat.SetFloat("_UseSpecular", useLilToonDirectSpecular);
if (useLilToonDirectSpecular > 0.5f)
{
toNiloToonMat.EnableKeyword("_SPECULARHIGHLIGHTS");
}
else
{
toNiloToonMat.DisableKeyword("_SPECULARHIGHLIGHTS");
}
toNiloToonMat.SetFloat("_UseGGXDirectSpecular", GetFloatOrDefault(fromlilToonMat, "_SpecularToon", 1f) > 0.5f ? 0 : 1);
toNiloToonMat.SetFloat("_Smoothness", GetFloatOrDefault(fromlilToonMat, "_Smoothness", toNiloToonMat.GetFloat("_Smoothness")));
Texture2D smoothnessMap = GetTextureOrNull(fromlilToonMat, "_SmoothnessTex") as Texture2D;
toNiloToonMat.SetTexture("_SmoothnessMap", smoothnessMap);
if (smoothnessMap)
{
toNiloToonMat.SetFloat("_UseSmoothnessMap", 1);
toNiloToonMat.EnableKeyword("_SMOOTHNESSMAP");
toNiloToonMat.SetFloat("_SmoothnessMapInputIsRoughnessMap", 0);
toNiloToonMat.SetVector("_SmoothnessMapChannelMask", new Vector4(1, 0, 0, 0));
}
else
{
toNiloToonMat.SetFloat("_UseSmoothnessMap", 0);
toNiloToonMat.DisableKeyword("_SMOOTHNESSMAP");
}
Color reflectionColor = GetColorOrDefault(fromlilToonMat, "_ReflectionColor", Color.white);
toNiloToonMat.SetFloat("_SpecularIntensity",
GetFloatOrDefault(fromlilToonMat, "_Reflectance") * reflectionColor.a);
toNiloToonMat.SetColor("_SpecularColor",
new Color(reflectionColor.r, reflectionColor.g, reflectionColor.b, 1));
toNiloToonMat.SetFloat("_MultiplyBaseColorToSpecularColor", GetFloatOrDefault(fromlilToonMat, "_Metallic"));
Texture2D reflectionColorTintMap = GetTextureOrNull(fromlilToonMat, "_ReflectionColorTex") as Texture2D;
toNiloToonMat.SetTexture("_SpecularColorTintMap", reflectionColorTintMap);
if (reflectionColorTintMap && !genericReflectionOwnsLilToonSpecular)
{
toNiloToonMat.SetFloat("_UseSpecularColorTintMap", 1);
toNiloToonMat.EnableKeyword("_SPECULARHIGHLIGHTS_TEX_TINT");
toNiloToonMat.SetFloat("_SpecularColorTintMapUsage", 1);
string reflectionColorTintMapPath = AssetDatabase.GetAssetPath(reflectionColorTintMap);
TextureImporter reflectionColorTintMapImporter =
string.IsNullOrEmpty(reflectionColorTintMapPath)
? null
: AssetImporter.GetAtPath(reflectionColorTintMapPath) as TextureImporter;
bool reflectionColorTintMapHasAlpha = reflectionColorTintMapImporter != null &&
reflectionColorTintMapImporter.DoesSourceTextureHaveAlpha();
if (reflectionColorTintMapHasAlpha)
{
toNiloToonMat.SetTexture("_SpecularMap", reflectionColorTintMap);
toNiloToonMat.SetVector("_SpecularMapChannelMask", new Vector4(0, 0, 0, 1));
}
}
else
{
toNiloToonMat.SetFloat("_UseSpecularColorTintMap", 0);
toNiloToonMat.DisableKeyword("_SPECULARHIGHLIGHTS_TEX_TINT");
}
//----------------------------------------------------------------------------------------------------------------------
// MatCap
DisableNativeNiloMatCapGroups(toNiloToonMat);
PortLilToonMatCapLayerToGeneric(
fromlilToonMat,
toNiloToonMat,
"_UseMatCap",
"_UseGenericMatCap1",
"_GENERIC_MATCAP1",
"_MatCapColor",
"_GenericMatCap1Color",
"_MatCapTex",
"_GenericMatCap1Map",
"_MatCapMainStrength",
"_GenericMatCap1MainStrength",
"_MatCapBlendUV1",
"_GenericMatCap1BlendUV1",
"_MatCapZRotCancel",
"_GenericMatCap1ZRotCancel",
"_MatCapPerspective",
"_GenericMatCap1Perspective",
"_MatCapVRParallaxStrength",
"_GenericMatCap1VRParallaxStrength",
"_MatCapBlend",
"_GenericMatCap1Blend",
"_MatCapBlendMask",
"_GenericMatCap1Mask",
"_MatCapEnableLighting",
"_GenericMatCap1EnableLighting",
"_MatCapShadowMask",
"_GenericMatCap1ShadowMask",
"_MatCapBackfaceMask",
"_GenericMatCap1BackfaceMask",
"_MatCapLod",
"_GenericMatCap1Lod",
"_MatCapBlendMode",
"_GenericMatCap1BlendMode",
"_MatCapApplyTransparency",
"_GenericMatCap1ApplyTransparency",
"_MatCapNormalStrength",
"_GenericMatCap1NormalStrength",
"_MatCapCustomNormal",
"_UseGenericMatCap1CustomNormal",
"_GENERIC_MATCAP1_CUSTOM_NORMAL",
"_MatCapBumpMap",
"_GenericMatCap1BumpMap",
"_MatCapBumpScale",
"_GenericMatCap1BumpScale");
//----------------------------------------------------------------------------------------------------------------------
// MatCap 2nd
PortLilToonMatCapLayerToGeneric(
fromlilToonMat,
toNiloToonMat,
"_UseMatCap2nd",
"_UseGenericMatCap2",
"_GENERIC_MATCAP2",
"_MatCap2ndColor",
"_GenericMatCap2Color",
"_MatCap2ndTex",
"_GenericMatCap2Map",
"_MatCap2ndMainStrength",
"_GenericMatCap2MainStrength",
"_MatCap2ndBlendUV1",
"_GenericMatCap2BlendUV1",
"_MatCap2ndZRotCancel",
"_GenericMatCap2ZRotCancel",
"_MatCap2ndPerspective",
"_GenericMatCap2Perspective",
"_MatCap2ndVRParallaxStrength",
"_GenericMatCap2VRParallaxStrength",
"_MatCap2ndBlend",
"_GenericMatCap2Blend",
"_MatCap2ndBlendMask",
"_GenericMatCap2Mask",
"_MatCap2ndEnableLighting",
"_GenericMatCap2EnableLighting",
"_MatCap2ndShadowMask",
"_GenericMatCap2ShadowMask",
"_MatCap2ndBackfaceMask",
"_GenericMatCap2BackfaceMask",
"_MatCap2ndLod",
"_GenericMatCap2Lod",
"_MatCap2ndBlendMode",
"_GenericMatCap2BlendMode",
"_MatCap2ndApplyTransparency",
"_GenericMatCap2ApplyTransparency",
"_MatCap2ndNormalStrength",
"_GenericMatCap2NormalStrength",
"_MatCap2ndCustomNormal",
"_UseGenericMatCap2CustomNormal",
"_GENERIC_MATCAP2_CUSTOM_NORMAL",
"_MatCap2ndBumpMap",
"_GenericMatCap2BumpMap",
"_MatCap2ndBumpScale",
"_GenericMatCap2BumpScale");
//----------------------------------------------------------------------------------------------------------------------
// Rim
PortLilToonRimToGenericRimLight3D(fromlilToonMat, toNiloToonMat);
//----------------------------------------------------------------------------------------------------------------------
// Glitter
// (X) ...All...
//----------------------------------------------------------------------------------------------------------------------
// Emission
int _UseEmission = (int)GetFloatOrDefault(fromlilToonMat, "_UseEmission");
if (_UseEmission == 1)
{
toNiloToonMat.SetFloat("_UseEmission", 1);
toNiloToonMat.EnableKeyword("_EMISSION");
}
else
{
toNiloToonMat.SetFloat("_UseEmission", 0);
toNiloToonMat.DisableKeyword("_EMISSION");
}
// (Same)_EmissionColor
toNiloToonMat.SetFloat("_EmissionIntensity",
GetColorOrDefault(fromlilToonMat, "_EmissionColor", Color.clear).a); // lilToon's _EmissionColor.a is the intensity
// (Same)_EmissionMap
toNiloToonMat.SetVector("_EmissionMapUVScrollSpeed",
GetVectorOrDefault(fromlilToonMat, "_EmissionMap_ScrollRotate", Vector4.zero));
// (X) _EmissionMap_UVMode
toNiloToonMat.SetFloat("_MultiplyBaseColorToEmissionColor",
GetFloatOrDefault(fromlilToonMat, "_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)GetFloatOrDefault(fromlilToonMat, "_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", GetColorOrDefault(fromlilToonMat, "_OutlineColor", Color.white));
// _OutlineWidth (same, no need to convert)
// make 2 outline system's width matching
float _OutlineWidth = GetFloatOrDefault(fromlilToonMat, "_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 = GetTextureOrNull(fromlilToonMat, "_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 = GetFloatOrDefault(fromlilToonMat, "_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", GetFloatOrDefault(fromlilToonMat, "_OutlineZBias"));
//----------------------------------------------------------------------------------------------------------------------
// Tessellation
// (X) ...All...
//----------------------------------------------------------------------------------------------------------------------
// For Multi
//----------------------------------------------------------------------------------------------------------------------
// Save (Unused)
//----------------------------------------------------------------------------------------------------------------------
// Advanced
//----------------------------------------------------------------------------------------------------------------------
// Outline Advanced
PortLilToonFurProperties(fromlilToonMat, toNiloToonMat);
}
static void SetMaterialAsIsSkin(Material m)
{
m.SetFloat(IsSkin, 1);
if (m.HasProperty(DepthTexRimLight3DRimMaskEnable))
{
m.SetFloat(DepthTexRimLight3DRimMaskEnable, 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)
{
int? clampedRenderQueue = null;
// 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;
clampedRenderQueue = m.renderQueue;
}
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:
// Preserve user-authored opaque/cutout ordering (e.g. 1999/2000 or 2450/2452) while keeping queues in Unity's opaque range.
ClampRenderQueueMinMax(m, 0, (int)RenderQueue.GeometryLast);
break;
case RenderQueueGroup.Cutout:
ClampRenderQueueMinMax(m, 0, (int)RenderQueue.GeometryLast);
break;
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.");
}
if (clampedRenderQueue.HasValue)
{
m.renderQueue = clampedRenderQueue.Value;
}
}
/// <summary>
/// Breaks the variant link of a material
/// </summary>
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
}
static bool IsMaterialVariant(Material mat)
{
if (mat == null)
return false;
#if UNITY_2022_1_OR_NEWER
return mat.isVariant;
#else
return false;
#endif
}
static bool HasUsableShader(Material mat)
{
return mat != null && mat.shader != null;
}
static bool ShouldUpgradeMaterialNonInteractively(Material material, HashSet<string> shaderNamesToIgnore)
{
if (!HasUsableShader(material))
return false;
if (IsMaterialVariant(material))
return false;
return !shaderNamesToIgnore.Contains(material.shader.name);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// copy from UniversalRenderPipelineMaterialUpgrader.cs
////////////////////////////////////////////////////////////////////////////////////////////////////////
static void GetShaderNamesToIgnore(ref HashSet<string> 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<MaterialUpgrader> 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<Material> allInputMaterials = new List<Material>();
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
}
}