Project_WL/AgentScripts/ToonConvert.cs

188 lines
11 KiB
C#
Raw Permalink Normal View History

// run_script entry points for #744 shader application (WL = himminji base · Unity 6000.3 · URP 17)
// unity command run_script --file AgentScripts/ToonConvert.cs --entry ToonConvert.Report --args '["Assets/ResWork/Map"]'
// unity command run_script --file AgentScripts/ToonConvert.cs --entry ToonConvert.MapToToonPro --args '["Assets/ResWork/Map/Content_Map1", true]'
// unity command run_script --file AgentScripts/ToonConvert.cs --entry ToonConvert.CharsToUTS --args '["Assets/ResWork/Suriyun/Characters", true]'
// Mapping only copies the base/normal/mask textures and colors; toon parameters keep the target shader defaults (tuning is a follow-up).
// Materials whose shader is already the target, or that are transparent/particle/UI/unknown, are skipped and listed in the report.
using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEngine;
public static class ToonConvert
{
const string ToonProName = "Toon Shaders Pro/URP/Toon";
const string UtsName = "Toon/Toon";
// ---------- survey ----------
public static object Report(string folder)
{
var guids = AssetDatabase.FindAssets("t:Material", new[] { folder });
var byShader = new Dictionary<string, int>();
foreach (var g in guids)
{
var m = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(g));
var n = (m == null || m.shader == null) ? "(null)" : m.shader.name;
byShader[n] = byShader.TryGetValue(n, out var c) ? c + 1 : 1;
}
var sb = new StringBuilder();
sb.Append(folder).Append(" materials=").Append(guids.Length).Append('\n');
foreach (var kv in byShader) sb.Append(" ").Append(kv.Value).Append(" ").Append(kv.Key).Append('\n');
return sb.ToString();
}
// ---------- helpers ----------
static Texture Tex(Material m, string prop) => m.HasProperty(prop) ? m.GetTexture(prop) : null;
static Vector2 Scale(Material m, string prop) => m.HasProperty(prop) ? m.GetTextureScale(prop) : Vector2.one;
static Vector2 Offset(Material m, string prop) => m.HasProperty(prop) ? m.GetTextureOffset(prop) : Vector2.zero;
static Color Col(Material m, string prop, Color fallback) => m.HasProperty(prop) ? m.GetColor(prop) : fallback;
static float Flt(Material m, string prop, float fallback) => m.HasProperty(prop) ? m.GetFloat(prop) : fallback;
// Read a source material into a neutral description regardless of its shader family.
class Src
{
public Texture baseMap; public Vector2 scale = Vector2.one, offset = Vector2.zero;
public Color baseColor = Color.white; public Texture normalMap; public float normalScale = 1f;
public float smoothness = 0.5f, metallic = 0f, cutoff = 0.5f; public bool alphaClip; public bool transparent;
public string family;
}
static Src ReadSource(Material m)
{
var s = new Src();
var n = m.shader.name;
if (n.StartsWith("MK/Toon"))
{
s.family = "MKToon";
s.baseMap = Tex(m, "_AlbedoMap"); s.scale = Scale(m, "_AlbedoMap"); s.offset = Offset(m, "_AlbedoMap");
s.baseColor = Col(m, "_AlbedoColor", Color.white);
s.normalMap = Tex(m, "_NormalMap"); s.normalScale = Flt(m, "_NormalMapIntensity", 1f);
s.smoothness = Flt(m, "_Smoothness", 0.5f);
s.cutoff = Flt(m, "_AlphaCutoff", 0.5f); s.alphaClip = Flt(m, "_AlphaClipping", 0f) > 0.5f;
s.transparent = Flt(m, "_Surface", 0f) > 0.5f;
}
else if (n.StartsWith("Universal Render Pipeline/") || n == ToonProName)
{
s.family = "URP";
s.baseMap = Tex(m, "_BaseMap"); s.scale = Scale(m, "_BaseMap"); s.offset = Offset(m, "_BaseMap");
s.baseColor = Col(m, "_BaseColor", Color.white);
s.normalMap = Tex(m, "_BumpMap"); s.normalScale = Flt(m, "_BumpScale", 1f);
s.smoothness = Flt(m, "_Smoothness", 0.5f); s.metallic = Flt(m, "_Metallic", 0f);
s.cutoff = Flt(m, "_Cutoff", 0.5f); s.alphaClip = Flt(m, "_AlphaClip", 0f) > 0.5f;
s.transparent = Flt(m, "_Surface", 0f) > 0.5f;
}
else if (n == "Standard" || n.StartsWith("Standard (") || n.StartsWith("Legacy Shaders/"))
{
s.family = "BuiltIn";
s.baseMap = Tex(m, "_MainTex"); s.scale = Scale(m, "_MainTex"); s.offset = Offset(m, "_MainTex");
s.baseColor = Col(m, "_Color", Color.white);
s.normalMap = Tex(m, "_BumpMap"); s.normalScale = Flt(m, "_BumpScale", 1f);
s.smoothness = Flt(m, "_Glossiness", 0.5f); s.metallic = Flt(m, "_Metallic", 0f);
s.cutoff = Flt(m, "_Cutoff", 0.5f); s.alphaClip = Flt(m, "_Mode", 0f) == 1f;
s.transparent = Flt(m, "_Mode", 0f) >= 2f;
}
else if (n == UtsName)
{
s.family = "UTS";
s.baseMap = Tex(m, "_MainTex"); s.scale = Scale(m, "_MainTex"); s.offset = Offset(m, "_MainTex");
s.baseColor = Col(m, "_BaseColor", Color.white);
s.normalMap = Tex(m, "_NormalMap"); s.normalScale = Flt(m, "_BumpScale", 1f);
}
else s.family = null;
return s;
}
// ---------- map → Toon Shaders Pro ----------
public static object MapToToonPro(string folder, bool dryRun)
{
var target = Shader.Find(ToonProName);
if (target == null) return "ERROR: shader not found: " + ToonProName;
var guids = AssetDatabase.FindAssets("t:Material", new[] { folder });
int converted = 0, skipped = 0; var skippedList = new List<string>(); var log = new StringBuilder();
foreach (var g in guids)
{
var path = AssetDatabase.GUIDToAssetPath(g);
var m = AssetDatabase.LoadAssetAtPath<Material>(path);
if (m == null || m.shader == null) { skipped++; skippedList.Add(path + " (null)"); continue; }
if (m.shader.name == ToonProName) { skipped++; continue; }
var s = ReadSource(m);
if (s.family == null || s.family == "UTS" || s.transparent)
{ skipped++; skippedList.Add(path + " (" + m.shader.name + (s.transparent ? " transparent" : "") + ")"); continue; }
log.Append(path).Append(" : ").Append(m.shader.name).Append(" -> ToonPro\n");
if (dryRun) { converted++; continue; }
Undo.RecordObject(m, "ToonConvert");
var queue = m.renderQueue;
m.shader = target;
m.SetTexture("_BaseMap", s.baseMap); m.SetTextureScale("_BaseMap", s.scale); m.SetTextureOffset("_BaseMap", s.offset);
m.SetColor("_BaseColor", s.baseColor);
m.SetTexture("_BumpMap", s.normalMap); m.SetFloat("_BumpScale", s.normalScale);
if (s.normalMap != null) m.EnableKeyword("_NORMALMAP"); else m.DisableKeyword("_NORMALMAP");
m.SetFloat("_Smoothness", s.smoothness); m.SetFloat("_Metallic", s.metallic);
m.SetFloat("_AlphaClip", s.alphaClip ? 1f : 0f); m.SetFloat("_Cutoff", s.cutoff);
if (s.alphaClip) m.EnableKeyword("_ALPHATEST_ON"); else m.DisableKeyword("_ALPHATEST_ON");
m.SetFloat("_Surface", 0f);
m.renderQueue = s.alphaClip ? 2450 : -1;
EditorUtility.SetDirty(m);
converted++;
}
if (!dryRun) AssetDatabase.SaveAssets();
return (dryRun ? "[DRY RUN] " : "") + "MapToToonPro " + folder + " converted=" + converted + " skipped=" + skipped + "\n" + log + "SKIPPED:\n" + string.Join("\n", skippedList);
}
// ---------- Toon Shaders Pro tint tuning (dark shadow band fix) ----------
// Default converted materials have _ShadowTint = black and _MiddleTint = 0.5, which with ambientIntensity 0 makes every shaded face black.
public static object TuneToonPro(string folder, float shadowLum, float middleLum)
{
var guids = AssetDatabase.FindAssets("t:Material", new[] { folder });
int tuned = 0;
foreach (var g in guids)
{
var m = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(g));
if (m == null || m.shader == null || m.shader.name != ToonProName) continue;
Undo.RecordObject(m, "TuneToonPro");
m.SetColor("_ShadowTint", new Color(shadowLum, shadowLum, shadowLum * 1.05f, 1f));
m.SetColor("_MiddleTint", new Color(middleLum, middleLum, middleLum, 1f));
m.SetColor("_LightTint", Color.white);
EditorUtility.SetDirty(m); tuned++;
}
AssetDatabase.SaveAssets();
return "TuneToonPro " + folder + " tuned=" + tuned + " shadow=" + shadowLum + " middle=" + middleLum;
}
// ---------- characters → UTS (Toon/Toon) ----------
public static object CharsToUTS(string folder, bool dryRun)
{
var target = Shader.Find(UtsName);
if (target == null) return "ERROR: shader not found: " + UtsName;
var guids = AssetDatabase.FindAssets("t:Material", new[] { folder });
int converted = 0, skipped = 0; var skippedList = new List<string>(); var log = new StringBuilder();
foreach (var g in guids)
{
var path = AssetDatabase.GUIDToAssetPath(g);
var m = AssetDatabase.LoadAssetAtPath<Material>(path);
if (m == null || m.shader == null) { skipped++; skippedList.Add(path + " (null)"); continue; }
if (m.shader.name == UtsName) { skipped++; continue; }
var s = ReadSource(m);
if (s.family == null || s.transparent)
{ skipped++; skippedList.Add(path + " (" + m.shader.name + (s.transparent ? " transparent" : "") + ")"); continue; }
log.Append(path).Append(" : ").Append(m.shader.name).Append(" -> UTS\n");
if (dryRun) { converted++; continue; }
Undo.RecordObject(m, "ToonConvert");
m.shader = target;
m.SetTexture("_MainTex", s.baseMap); m.SetTextureScale("_MainTex", s.scale); m.SetTextureOffset("_MainTex", s.offset);
if (m.HasProperty("_BaseMap")) m.SetTexture("_BaseMap", s.baseMap);
m.SetColor("_BaseColor", s.baseColor); if (m.HasProperty("_Color")) m.SetColor("_Color", s.baseColor);
// shade maps reuse the base map (UTS convention) with slightly darker tints for two-band toon shading
m.SetFloat("_Use_BaseAs1st", 1f); m.SetFloat("_Use_1stAs2nd", 1f);
m.SetColor("_1st_ShadeColor", s.baseColor * 0.85f); m.SetColor("_2nd_ShadeColor", s.baseColor * 0.7f);
m.SetTexture("_NormalMap", s.normalMap); if (m.HasProperty("_BumpScale")) m.SetFloat("_BumpScale", s.normalScale);
m.SetFloat("_Is_NormalMapToBase", s.normalMap != null ? 1f : 0f);
if (s.alphaClip) { m.SetFloat("_ClippingMode", 1f); m.SetFloat("_Clipping_Level", 1f - s.cutoff); m.SetFloat("_IsBaseMapAlphaAsClippingMask", 1f); }
EditorUtility.SetDirty(m);
converted++;
}
if (!dryRun) AssetDatabase.SaveAssets();
return (dryRun ? "[DRY RUN] " : "") + "CharsToUTS " + folder + " converted=" + converted + " skipped=" + skipped + "\n" + log + "SKIPPED:\n" + string.Join("\n", skippedList);
}
}