206 lines
7.6 KiB
C#
206 lines
7.6 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()
|
|
{
|
|
if (Input.GetKeyDown(KeyCode.F3))
|
|
_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
|