UniVRM/Assets/VRM/MToon/Editor/MToonInspector.cs
2024-07-19 17:00:09 +09:00

459 lines
22 KiB
C#

using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace MToon
{
public class MToonInspector : ShaderGUI
{
private const float RoundsToDegree = 360f;
private const float RoundsToRadian = (float) Math.PI * 2f;
private static bool isAdvancedLightingPanelFoldout = false;
private static EditorRotationUnit editorRotationUnit = EditorRotationUnit.Rounds;
private MaterialProperty _version;
private MaterialProperty _blendMode;
private MaterialProperty _bumpMap;
private MaterialProperty _bumpScale;
private MaterialProperty _color;
private MaterialProperty _cullMode;
// private MaterialProperty _outlineCullMode;
private MaterialProperty _cutoff;
private MaterialProperty _debugMode;
private MaterialProperty _emissionColor;
private MaterialProperty _emissionMap;
private MaterialProperty _lightColorAttenuation;
private MaterialProperty _indirectLightIntensity;
private MaterialProperty _mainTex;
private MaterialProperty _outlineColor;
private MaterialProperty _outlineColorMode;
private MaterialProperty _outlineLightingMix;
private MaterialProperty _outlineWidth;
private MaterialProperty _outlineScaledMaxDistance;
private MaterialProperty _outlineWidthMode;
private MaterialProperty _outlineWidthTexture;
private MaterialProperty _receiveShadowRate;
private MaterialProperty _receiveShadowTexture;
private MaterialProperty _shadingGradeRate;
private MaterialProperty _shadingGradeTexture;
private MaterialProperty _shadeColor;
private MaterialProperty _shadeShift;
private MaterialProperty _shadeTexture;
private MaterialProperty _shadeToony;
private MaterialProperty _sphereAdd;
private MaterialProperty _rimColor;
private MaterialProperty _rimTexture;
private MaterialProperty _rimLightingMix;
private MaterialProperty _rimFresnelPower;
private MaterialProperty _rimLift;
private MaterialProperty _uvAnimMaskTexture;
private MaterialProperty _uvAnimScrollX;
private MaterialProperty _uvAnimScrollY;
private MaterialProperty _uvAnimRotation;
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
_version = FindProperty(Utils.PropVersion, properties);
_debugMode = FindProperty(Utils.PropDebugMode, properties);
_outlineWidthMode = FindProperty(Utils.PropOutlineWidthMode, properties);
_outlineColorMode = FindProperty(Utils.PropOutlineColorMode, properties);
_blendMode = FindProperty(Utils.PropBlendMode, properties);
_cullMode = FindProperty(Utils.PropCullMode, properties);
// _outlineCullMode = FindProperty(Utils.PropOutlineCullMode, properties);
_cutoff = FindProperty(Utils.PropCutoff, properties);
_color = FindProperty(Utils.PropColor, properties);
_shadeColor = FindProperty(Utils.PropShadeColor, properties);
_mainTex = FindProperty(Utils.PropMainTex, properties);
_shadeTexture = FindProperty(Utils.PropShadeTexture, properties);
_bumpScale = FindProperty(Utils.PropBumpScale, properties);
_bumpMap = FindProperty(Utils.PropBumpMap, properties);
_receiveShadowRate = FindProperty(Utils.PropReceiveShadowRate, properties);
_receiveShadowTexture = FindProperty(Utils.PropReceiveShadowTexture, properties);
_shadingGradeRate = FindProperty(Utils.PropShadingGradeRate, properties);
_shadingGradeTexture = FindProperty(Utils.PropShadingGradeTexture, properties);
_shadeShift = FindProperty(Utils.PropShadeShift, properties);
_shadeToony = FindProperty(Utils.PropShadeToony, properties);
_lightColorAttenuation = FindProperty(Utils.PropLightColorAttenuation, properties);
_indirectLightIntensity = FindProperty(Utils.PropIndirectLightIntensity, properties);
_rimColor = FindProperty(Utils.PropRimColor, properties);
_rimTexture = FindProperty(Utils.PropRimTexture, properties);
_rimLightingMix = FindProperty(Utils.PropRimLightingMix, properties);
_rimFresnelPower = FindProperty(Utils.PropRimFresnelPower, properties);
_rimLift = FindProperty(Utils.PropRimLift, properties);
_sphereAdd = FindProperty(Utils.PropSphereAdd, properties);
_emissionColor = FindProperty(Utils.PropEmissionColor, properties);
_emissionMap = FindProperty(Utils.PropEmissionMap, properties);
_outlineWidthTexture = FindProperty(Utils.PropOutlineWidthTexture, properties);
_outlineWidth = FindProperty(Utils.PropOutlineWidth, properties);
_outlineScaledMaxDistance = FindProperty(Utils.PropOutlineScaledMaxDistance, properties);
_outlineColor = FindProperty(Utils.PropOutlineColor, properties);
_outlineLightingMix = FindProperty(Utils.PropOutlineLightingMix, properties);
_uvAnimMaskTexture = FindProperty(Utils.PropUvAnimMaskTexture, properties);
_uvAnimScrollX = FindProperty(Utils.PropUvAnimScrollX, properties);
_uvAnimScrollY = FindProperty(Utils.PropUvAnimScrollY, properties);
_uvAnimRotation = FindProperty(Utils.PropUvAnimRotation, properties);
var materials = materialEditor.targets.Select(x => x as Material).ToArray();
Draw(materialEditor, materials);
}
private void Draw(MaterialEditor materialEditor, Material[] materials)
{
EditorGUI.BeginChangeCheck();
{
_version.floatValue = Utils.VersionNumber;
EditorGUILayout.LabelField("Rendering", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
EditorGUILayout.LabelField("Mode", EditorStyles.boldLabel);
if (PopupEnum<RenderMode>("Rendering Type", _blendMode, materialEditor))
{
ModeChanged(materials, isBlendModeChangedByUser: true);
}
if ((RenderMode) _blendMode.floatValue == RenderMode.TransparentWithZWrite)
{
EditorGUILayout.HelpBox("TransparentWithZWrite mode can cause problems with rendering.", MessageType.Warning);
}
if (PopupEnum<CullMode>("Cull Mode", _cullMode, materialEditor))
{
ModeChanged(materials);
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Color", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
EditorGUILayout.LabelField("Texture", EditorStyles.boldLabel);
{
materialEditor.TexturePropertySingleLine(new GUIContent("Lit Color, Alpha", "Lit (RGB), Alpha (A)"),
_mainTex, _color);
materialEditor.TexturePropertySingleLine(new GUIContent("Shade Color", "Shade (RGB)"), _shadeTexture,
_shadeColor);
}
var bm = (RenderMode) _blendMode.floatValue;
if (bm == RenderMode.Cutout)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Alpha", EditorStyles.boldLabel);
{
materialEditor.ShaderProperty(_cutoff, "Cutoff");
}
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Lighting", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
{
materialEditor.ShaderProperty(_shadeToony,
new GUIContent("Shading Toony",
"0.0 is Lambert. Higher value get toony shading."));
// Normal
EditorGUI.BeginChangeCheck();
materialEditor.TexturePropertySingleLine(new GUIContent("Normal Map [Normal]", "Normal Map (RGB)"),
_bumpMap,
_bumpScale);
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo("BumpEnabledDisabled");
ModeChanged(materials);
}
}
EditorGUILayout.Space();
EditorGUI.indentLevel++;
{
isAdvancedLightingPanelFoldout = EditorGUILayout.Foldout(isAdvancedLightingPanelFoldout, "Advanced Settings", EditorStyles.boldFont);
if (isAdvancedLightingPanelFoldout)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.HelpBox(
"The default settings are suitable for Advanced Settings if you want to toony result.",
MessageType.Info);
if (GUILayout.Button("Use Default"))
{
_shadeShift.floatValue = 0;
_receiveShadowTexture.textureValue = null;
_receiveShadowRate.floatValue = 1;
_shadingGradeTexture.textureValue = null;
_shadingGradeRate.floatValue = 1;
_lightColorAttenuation.floatValue = 0;
_indirectLightIntensity.floatValue = 0.1f;
}
EditorGUILayout.EndHorizontal();
materialEditor.ShaderProperty(_shadeShift,
new GUIContent("Shading Shift",
"Zero is Default. Negative value increase lit area. Positive value increase shade area."));
materialEditor.TexturePropertySingleLine(
new GUIContent("Shadow Receive Multiplier",
"Texture (R) * Rate. White is Default. Black attenuates shadows."),
_receiveShadowTexture,
_receiveShadowRate);
materialEditor.TexturePropertySingleLine(
new GUIContent("Lit & Shade Mixing Multiplier",
"Texture (R) * Rate. Compatible with UTS2 ShadingGradeMap. White is Default. Black amplifies shade."),
_shadingGradeTexture,
_shadingGradeRate);
materialEditor.ShaderProperty(_lightColorAttenuation, "LightColor Attenuation");
materialEditor.ShaderProperty(_indirectLightIntensity, "GI Intensity");
}
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Emission", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
TextureWithHdrColor(materialEditor, "Emission", "Emission (RGB)",
_emissionMap, _emissionColor);
materialEditor.TexturePropertySingleLine(new GUIContent("MatCap", "MatCap Texture (RGB)"),
_sphereAdd);
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Rim", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
TextureWithHdrColor(materialEditor, "Color", "Rim Color (RGB)",
_rimTexture, _rimColor);
materialEditor.DefaultShaderProperty(_rimLightingMix, "Lighting Mix");
materialEditor.ShaderProperty(_rimFresnelPower,
new GUIContent("Fresnel Power",
"If you increase this value, you get sharpness rim light."));
materialEditor.ShaderProperty(_rimLift,
new GUIContent("Lift",
"If you increase this value, you can lift rim light."));
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Outline", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
// Outline
EditorGUILayout.LabelField("Width", EditorStyles.boldLabel);
{
if (PopupEnum<OutlineWidthMode>("Mode", _outlineWidthMode, materialEditor))
{
ModeChanged(materials);
}
if ((RenderMode) _blendMode.floatValue == RenderMode.Transparent &&
(OutlineWidthMode) _outlineWidthMode.floatValue != OutlineWidthMode.None)
{
EditorGUILayout.HelpBox("Outline with Transparent material cause problem with rendering.", MessageType.Warning);
}
var widthMode = (OutlineWidthMode) _outlineWidthMode.floatValue;
if (widthMode != OutlineWidthMode.None)
{
materialEditor.TexturePropertySingleLine(
new GUIContent("Width", "Outline Width Texture (RGB)"),
_outlineWidthTexture, _outlineWidth);
}
if (widthMode == OutlineWidthMode.ScreenCoordinates)
{
materialEditor.ShaderProperty(_outlineScaledMaxDistance, "Width Scaled Max Distance");
}
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Color", EditorStyles.boldLabel);
{
var widthMode = (OutlineWidthMode) _outlineWidthMode.floatValue;
if (widthMode != OutlineWidthMode.None)
{
EditorGUI.BeginChangeCheck();
if (PopupEnum<OutlineColorMode>("Mode", _outlineColorMode, materialEditor))
{
ModeChanged(materials);
}
var colorMode = (OutlineColorMode) _outlineColorMode.floatValue;
materialEditor.ShaderProperty(_outlineColor, "Color");
if (colorMode == OutlineColorMode.MixedLighting)
materialEditor.DefaultShaderProperty(_outlineLightingMix, "Lighting Mix");
}
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("UV Coordinates", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
// UV
EditorGUILayout.LabelField("Scale & Offset", EditorStyles.boldLabel);
{
materialEditor.TextureScaleOffsetProperty(_mainTex);
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Auto Animation", EditorStyles.boldLabel);
{
materialEditor.TexturePropertySingleLine(new GUIContent("Mask", "Auto Animation Mask Texture (R)"), _uvAnimMaskTexture);
materialEditor.ShaderProperty(_uvAnimScrollX, "Scroll X (per second)");
materialEditor.ShaderProperty(_uvAnimScrollY, "Scroll Y (per second)");
{
var control = EditorGUILayout.GetControlRect(hasLabel: true);
const int popupMargin = 5;
const int popupWidth = 80;
var floatControl = new Rect(control);
floatControl.width -= popupMargin + popupWidth;
var popupControl = new Rect(control);
popupControl.x = floatControl.x + floatControl.width + popupMargin;
popupControl.width = popupWidth;
EditorGUI.BeginChangeCheck();
var inspectorRotationValue = GetInspectorRotationValue(editorRotationUnit, _uvAnimRotation.floatValue);
inspectorRotationValue = EditorGUI.FloatField(floatControl, "Rotation value (per second)", inspectorRotationValue);
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo("UvAnimRotationValueChanged");
_uvAnimRotation.floatValue = GetRawRotationValue(editorRotationUnit, inspectorRotationValue);
}
editorRotationUnit = (EditorRotationUnit) EditorGUI.EnumPopup(popupControl, editorRotationUnit);
}
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Options", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
{
EditorGUILayout.LabelField("Debugging Options", EditorStyles.boldLabel);
{
if (PopupEnum<DebugMode>("Visualize", _debugMode, materialEditor))
{
ModeChanged(materials);
}
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Advanced Options", EditorStyles.boldLabel);
{
#if UNITY_5_6_OR_NEWER
// materialEditor.EnableInstancingField();
materialEditor.DoubleSidedGIField();
#endif
EditorGUI.BeginChangeCheck();
materialEditor.RenderQueueField();
if (EditorGUI.EndChangeCheck())
{
ModeChanged(materials);
}
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
EditorGUI.EndChangeCheck();
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
base.AssignNewShaderToMaterial(material, oldShader, newShader);
Utils.ValidateProperties(material, isBlendModeChangedByUser: true);
}
private static void ModeChanged(Material[] materials, bool isBlendModeChangedByUser = false)
{
foreach (var material in materials)
{
Utils.ValidateProperties(material, isBlendModeChangedByUser);
}
}
private static bool PopupEnum<T>(string name, MaterialProperty property, MaterialEditor editor) where T : struct
{
EditorGUI.showMixedValue = property.hasMixedValue;
EditorGUI.BeginChangeCheck();
var ret = EditorGUILayout.Popup(name, (int) property.floatValue, Enum.GetNames(typeof(T)));
var changed = EditorGUI.EndChangeCheck();
if (changed)
{
editor.RegisterPropertyChangeUndo("EnumPopUp");
property.floatValue = ret;
}
EditorGUI.showMixedValue = false;
return changed;
}
private static void TextureWithHdrColor(MaterialEditor materialEditor, string label, string description,
MaterialProperty texProp, MaterialProperty colorProp)
{
materialEditor.TexturePropertyWithHDRColor(new GUIContent(label, description),
texProp,
colorProp,
#if UNITY_2018_1_OR_NEWER
#else
new ColorPickerHDRConfig(minBrightness: 0, maxBrightness: 10, minExposureValue: -10,
maxExposureValue: 10),
#endif
showAlpha: false);
}
private static float GetRawRotationValue(EditorRotationUnit unit, float inspectorValue)
{
switch (unit)
{
case EditorRotationUnit.Rounds:
return inspectorValue;
case EditorRotationUnit.Degrees:
return inspectorValue / RoundsToDegree;
case EditorRotationUnit.Radians:
return inspectorValue / RoundsToRadian;
default:
throw new ArgumentOutOfRangeException();
}
}
private static float GetInspectorRotationValue(EditorRotationUnit unit, float rawValue)
{
switch (unit)
{
case EditorRotationUnit.Rounds:
return rawValue;
case EditorRotationUnit.Degrees:
return rawValue * RoundsToDegree;
case EditorRotationUnit.Radians:
return rawValue * RoundsToRadian;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}