Files

154 lines
5.8 KiB
C#
Raw Permalink Normal View History

2026-03-30 03:23:36 -04:00
// BlendUnlitShaderGUI.cs
// Custom Material Inspector for Soullies/BlendUnlit
// Drives the GPU Blend equation based on the user-selected Blend Mode.
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
public class BlendUnlitShaderGUI : ShaderGUI
{
// -------------------------------------------------------------------------
// Blend mode definitions
// -------------------------------------------------------------------------
enum BlendMode
{
Alpha = 0, // SrcAlpha, OneMinusSrcAlpha standard transparency
Additive = 1, // SrcAlpha, One additive / glow, black = invisible
Multiply = 2, // DstColor, Zero darkens below
Premultiplied = 3, // One, OneMinusSrcAlpha pre-multiplied alpha / HDR
}
static readonly string[] BlendModeNames =
{
"Alpha (SrcAlpha, 1-SrcAlpha)",
"Additive (SrcAlpha, One)",
"Multiply (DstColor, Zero)",
"Premultiplied (One, 1-SrcAlpha)",
};
// Src / Dst for each BlendMode entry
static readonly (UnityEngine.Rendering.BlendMode src, UnityEngine.Rendering.BlendMode dst)[] BlendEquations =
{
(UnityEngine.Rendering.BlendMode.SrcAlpha, UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha), // Alpha
(UnityEngine.Rendering.BlendMode.SrcAlpha, UnityEngine.Rendering.BlendMode.One), // Additive
(UnityEngine.Rendering.BlendMode.DstColor, UnityEngine.Rendering.BlendMode.Zero), // Multiply
(UnityEngine.Rendering.BlendMode.One, UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha), // Premultiplied
};
// -------------------------------------------------------------------------
// GUI
// -------------------------------------------------------------------------
public override void OnGUI(MaterialEditor editor, MaterialProperty[] props)
{
Material mat = editor.target as Material;
EditorGUI.BeginChangeCheck();
// Draw all standard properties EXCEPT our hidden blend props
foreach (var prop in props)
{
// Hide internal blend-equation float props from inspector
if (prop.name == "_SrcBlendRGB" || prop.name == "_DstBlendRGB")
continue;
// Replace the raw _BlendMode float with our friendly enum popup
if (prop.name == "_BlendMode")
{
EditorGUILayout.Space(4);
DrawBlendModePopup(editor, mat, prop);
EditorGUILayout.Space(4);
continue;
}
editor.ShaderProperty(prop, prop.displayName);
}
if (EditorGUI.EndChangeCheck())
{
// Apply blend equations to all selected materials
foreach (Object obj in editor.targets)
{
ApplyBlendMode((Material)obj);
}
}
EditorGUILayout.Space(8);
editor.RenderQueueField();
editor.EnableInstancingField();
editor.DoubleSidedGIField();
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
static void DrawBlendModePopup(MaterialEditor editor, Material mat, MaterialProperty prop)
{
int current = (int)prop.floatValue;
current = Mathf.Clamp(current, 0, BlendModeNames.Length - 1);
EditorGUI.BeginChangeCheck();
int selected = EditorGUILayout.Popup("Blend Mode", current, BlendModeNames);
if (EditorGUI.EndChangeCheck())
{
editor.RegisterPropertyChangeUndo("Blend Mode");
prop.floatValue = selected;
}
}
static void ApplyBlendMode(Material mat)
{
int index = Mathf.Clamp((int)mat.GetFloat("_BlendMode"), 0, BlendEquations.Length - 1);
BlendMode mode = (BlendMode)index;
// Disable all keyword variants, then enable the correct one
mat.DisableKeyword("_BLENDMODE_ALPHA");
mat.DisableKeyword("_BLENDMODE_ADDITIVE");
mat.DisableKeyword("_BLENDMODE_MULTIPLY");
mat.DisableKeyword("_BLENDMODE_PREMULTIPLIED");
switch (mode)
{
case BlendMode.Alpha:
mat.EnableKeyword("_BLENDMODE_ALPHA");
break;
case BlendMode.Additive:
mat.EnableKeyword("_BLENDMODE_ADDITIVE");
break;
case BlendMode.Multiply:
mat.EnableKeyword("_BLENDMODE_MULTIPLY");
break;
case BlendMode.Premultiplied:
mat.EnableKeyword("_BLENDMODE_PREMULTIPLIED");
break;
}
// Write the actual Blend equation floats that the Shader reads
var (src, dst) = BlendEquations[index];
mat.SetFloat("_SrcBlendRGB", (float)src);
mat.SetFloat("_DstBlendRGB", (float)dst);
// Adjust RenderQueue hint for Multiply mode
// (Multiply should typically not write ZBuffer and renders as transparent)
if (mode == BlendMode.Multiply)
{
mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
}
else
{
// Keep queue at Transparent for all other modes (default)
if (mat.renderQueue < (int)UnityEngine.Rendering.RenderQueue.Transparent)
mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
}
EditorUtility.SetDirty(mat);
}
// Called when the Shader is assigned to a material for the first time
public override void AssignNewShaderToMaterial(Material mat, Shader oldShader, Shader newShader)
{
base.AssignNewShaderToMaterial(mat, oldShader, newShader);
ApplyBlendMode(mat);
}
}