Files
Project-M/Assets/_Project/Scripts/Client/Debug/PixelArtDevControls.cs
T
kronic a4b6bb9dfe Console noise purge: deprecated-API fixes + PixelArtDevControls legacy-Input exception
MenuUi FindAnyObjectByType; GA prefabAssetPath->assetPath x2; Synty sample
FindObjectsByType overload; dead death_b field removed. Real bug caught by
the sweep: the F3 pixel-art toggle used legacy Input.GetKeyDown under
Input System-only handling -> InvalidOperationException every frame in Play.
Suite green (455).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:00:16 -07:00

207 lines
7.7 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
namespace ProjectM.Client
{
/// <summary>
/// EDITOR-ONLY live tuner for the "3D pixel art" full-screen render style — the
/// <c>Hidden/ProjectM/PixelOutline</c> shader driven by <c>PixelOutline.mat</c> via the
/// PC_Renderer <c>FullScreenPassRendererFeature</c>. Self-spawns on Play (no scene wiring),
/// so it works in Game.unity and DevSandbox.unity alike. Toggle the panel with <b>F3</b>.
///
/// It writes straight to the shared material ASSET, so every drag applies to the running
/// game instantly AND sticks after you exit Play mode (material assets aren't reverted the
/// way scene objects are). "Save Asset" force-writes to disk now; "Reset" restores the
/// shader's shipped defaults. Stripped from player builds (#if UNITY_EDITOR).
/// </summary>
public class PixelArtDevControls : MonoBehaviour
{
const string MaterialPath = "Assets/_Project/Shaders/PixelOutline.mat";
static PixelArtDevControls _instance;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void Bootstrap()
{
if (_instance != null)
return;
var go = new GameObject("~PixelArtDevControls") { hideFlags = HideFlags.HideAndDontSave };
DontDestroyOnLoad(go);
_instance = go.AddComponent<PixelArtDevControls>();
}
Material _mat;
bool _open;
Vector2 _scroll;
GUIStyle _wrap;
Material Mat
{
get
{
if (_mat == null)
_mat = AssetDatabase.LoadAssetAtPath<Material>(MaterialPath);
return _mat;
}
}
GUIStyle Wrap => _wrap ??= new GUIStyle(GUI.skin.label) { wordWrap = true, fontSize = 10 };
void OnDisable() => AimPresentation.ForceCursorVisible = false;
void Update()
{
var kb = UnityEngine.InputSystem.Keyboard.current; // legacy Input throws under active Input System handling
if (kb != null && kb.f3Key.wasPressedThisFrame)
_open = !_open;
}
void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 128, 24), _open ? "PIXEL ▲ (F3)" : "PIXEL ▼ (F3)"))
_open = !_open;
if (!_open)
return;
AimPresentation.ForceCursorVisible = true;
var mat = Mat;
if (mat == null)
{
GUILayout.BeginArea(new Rect(10, 40, 270, 64), GUI.skin.box);
GUILayout.Label("PixelOutline.mat not found at\n" + MaterialPath, Wrap);
GUILayout.EndArea();
return;
}
float panelH = Mathf.Min(660f, Screen.height - 60f);
GUILayout.BeginArea(new Rect(10, 40, 272, panelH), GUI.skin.box);
GUILayout.Label("PIXEL-ART RENDER STYLE (live)");
_scroll = GUILayout.BeginScrollView(_scroll);
Toggle(mat, "_MasterEnabled", "MASTER (whole effect on/off)");
GUILayout.Space(6);
GUILayout.Label("- Toggles -");
Toggle(mat, "_PixelateEnabled", "Pixelate");
Toggle(mat, "_PosterizeEnabled", "Posterize (banded color)");
Toggle(mat, "_DepthEdgesEnabled", "Depth edges (silhouette)");
Toggle(mat, "_NormalEdgesEnabled", "Normal edges (creases)");
GUILayout.Space(6);
GUILayout.Label("- Pixelation -");
Slider(mat, "_PixelHeight", "Grid height (px)", 40f, 720f, "0");
GUILayout.Space(6);
GUILayout.Label("- Color / tone -");
Slider(mat, "_ColorLevels", "Posterize levels", 2f, 64f, "0");
Slider(mat, "_Brightness", "Brightness", 0.5f, 2f, "0.00");
Slider(mat, "_Contrast", "Contrast", 0.5f, 2f, "0.00");
Slider(mat, "_Saturation", "Saturation", 0f, 2f, "0.00");
GUILayout.Space(6);
GUILayout.Label("- Outlines -");
Slider(mat, "_DepthThreshold", "Depth threshold", 0f, 1f, "0.000");
Slider(mat, "_NormalThreshold", "Normal threshold", 0f, 4f, "0.00");
Slider(mat, "_OutlineThickness", "Thickness (texels)", 0.25f, 4f, "0.00");
Slider(mat, "_EdgeStrength", "Edge strength", 0f, 1f, "0.00");
ColorRow(mat, "_OutlineColorOuter", "Silhouette color");
ColorRow(mat, "_OutlineColorInner", "Crease color");
GUILayout.Space(8);
GUILayout.BeginHorizontal();
if (GUILayout.Button("Reset defaults"))
ResetDefaults(mat);
if (GUILayout.Button("Save Asset"))
SaveAsset(mat);
GUILayout.EndHorizontal();
GUILayout.Label("Drags apply live and persist after Play. 'Save Asset' writes to disk now.", Wrap);
GUILayout.EndScrollView();
GUILayout.EndArea();
}
static void Toggle(Material mat, string prop, string label)
{
bool cur = mat.GetFloat(prop) > 0.5f;
bool now = GUILayout.Toggle(cur, " " + label);
if (now != cur)
{
mat.SetFloat(prop, now ? 1f : 0f);
EditorUtility.SetDirty(mat);
}
}
static void Slider(Material mat, string prop, string label, float min, float max, string fmt)
{
float cur = mat.GetFloat(prop);
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(126));
GUILayout.Label(cur.ToString(fmt), GUILayout.Width(48));
GUILayout.EndHorizontal();
float now = GUILayout.HorizontalSlider(cur, min, max);
if (!Mathf.Approximately(now, cur))
{
mat.SetFloat(prop, now);
EditorUtility.SetDirty(mat);
}
}
static void ColorRow(Material mat, string prop, string label)
{
Color c = mat.GetColor(prop);
GUILayout.Label(label);
Color n = c;
n.r = ChannelSlider("R", c.r);
n.g = ChannelSlider("G", c.g);
n.b = ChannelSlider("B", c.b);
if (n != c)
{
n.a = 1f;
mat.SetColor(prop, n);
EditorUtility.SetDirty(mat);
}
}
static float ChannelSlider(string label, float v)
{
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(14));
float r = GUILayout.HorizontalSlider(v, 0f, 1f);
GUILayout.EndHorizontal();
return r;
}
// Shipped defaults from PixelOutline.shader / .mat.
static void ResetDefaults(Material mat)
{
mat.SetFloat("_MasterEnabled", 1f);
mat.SetFloat("_PixelHeight", 200f);
mat.SetFloat("_PosterizeEnabled", 1f);
mat.SetFloat("_ColorLevels", 12f);
mat.SetFloat("_Brightness", 1.1f);
mat.SetFloat("_Contrast", 1.05f);
mat.SetFloat("_Saturation", 1.35f);
mat.SetFloat("_DepthThreshold", 0.08f);
mat.SetFloat("_NormalThreshold", 1f);
mat.SetFloat("_OutlineThickness", 1f);
mat.SetFloat("_EdgeStrength", 1f);
mat.SetFloat("_PixelateEnabled", 1f);
mat.SetFloat("_DepthEdgesEnabled", 1f);
mat.SetFloat("_NormalEdgesEnabled", 1f);
mat.SetColor("_OutlineColorOuter", Color.black);
mat.SetColor("_OutlineColorInner", Color.black);
EditorUtility.SetDirty(mat);
}
static void SaveAsset(Material mat)
{
EditorUtility.SetDirty(mat);
AssetDatabase.SaveAssetIfDirty(mat);
}
}
}
#endif