1629 lines
56 KiB
C#
1629 lines
56 KiB
C#
using UnityEditor;
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.Rendering;
|
|
using Object = UnityEngine.Object;
|
|
using static SilentCelShading.Unity.InspectorCommon;
|
|
using SilentCelShading.Unity.Baking;
|
|
|
|
// Parts of this file are based on https://github.com/Microsoft/MixedRealityToolkit-Unity/
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
namespace SilentCelShading.Unity
|
|
{
|
|
public class Inspector : SCSSShaderGUI
|
|
{
|
|
|
|
public enum ShadowMaskType
|
|
{
|
|
Occlusion,
|
|
Tone,
|
|
Auto
|
|
}
|
|
|
|
public enum LightRampType
|
|
{
|
|
Horizontal,
|
|
Vertical,
|
|
None
|
|
}
|
|
|
|
public enum ToneSeparationType
|
|
{
|
|
Combined,
|
|
Separate
|
|
}
|
|
|
|
public enum IndirectShadingType
|
|
{
|
|
Dynamic,
|
|
Directional,
|
|
Flatten
|
|
}
|
|
|
|
public enum SettingsComplexityMode
|
|
{
|
|
Complex,
|
|
Normal,
|
|
Simple
|
|
}
|
|
|
|
public enum TransparencyMode
|
|
{
|
|
Soft,
|
|
Sharp
|
|
}
|
|
|
|
public enum DetailEmissionMode
|
|
{
|
|
Phase,
|
|
AudioLink
|
|
}
|
|
|
|
protected Material target;
|
|
protected MaterialEditor editor;
|
|
protected Dictionary<string, MaterialProperty> props = new Dictionary<string, MaterialProperty>();
|
|
|
|
public int scssSettingsComplexityMode = (int)SettingsComplexityMode.Simple;
|
|
|
|
protected bool usingLightramp = true; // Compatibility
|
|
protected bool usingCrosstone = false;
|
|
|
|
protected void CheckShaderType(Material material)
|
|
{
|
|
// Check material type
|
|
const string crosstoneName = "Crosstone";
|
|
usingCrosstone = material.shader.name.Contains(crosstoneName);
|
|
|
|
const string lightrampName = "Lightramp";
|
|
usingLightramp = material.shader.name.Contains(lightrampName);
|
|
|
|
// Short circuit for old materials.
|
|
const string hiddenName = "Old";
|
|
if (material.shader.name.Contains(hiddenName)) UpgradeVariantCheck(material);
|
|
}
|
|
|
|
protected override void FindProperties(MaterialProperty[] matProps)
|
|
{
|
|
base.FindProperties(matProps);
|
|
|
|
foreach (MaterialProperty prop in matProps)
|
|
{
|
|
props[prop.name] = FindProperty(prop.name, matProps, false);
|
|
}
|
|
}
|
|
|
|
protected override void MaterialChanged(Material material)
|
|
{
|
|
InitialiseStyles();
|
|
|
|
if (!Int32.TryParse(EditorUserSettings.GetConfigValue("scss_settings_complexity_mode"), out scssSettingsComplexityMode))
|
|
{
|
|
scssSettingsComplexityMode = (int)SettingsComplexityMode.Simple;
|
|
}
|
|
|
|
// Handle old materials
|
|
UpgradeMatcaps(material);
|
|
UpgradeVariantCheck(material);
|
|
|
|
SetupMaterialWithAlbedo(material,
|
|
props["_MainTex"],
|
|
props["_AlbedoAlphaMode"]);
|
|
|
|
|
|
MaterialProperty outlineProp;
|
|
if (props.TryGetValue("_OutlineMode", out outlineProp))
|
|
{
|
|
SetupMaterialWithOutlineMode(material, (OutlineMode)outlineProp.floatValue);
|
|
}
|
|
|
|
MaterialProperty specProp;
|
|
if (props.TryGetValue("_SpecularType", out specProp))
|
|
{
|
|
SetupMaterialWithSpecularType(material, (SpecularType)specProp.floatValue);
|
|
}
|
|
|
|
SetMaterialKeywords(material);
|
|
|
|
base.MaterialChanged(material);
|
|
}
|
|
|
|
protected MaterialProperty Property(string i)
|
|
{
|
|
MaterialProperty prop;
|
|
if (props.TryGetValue(i, out prop))
|
|
{
|
|
return prop;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected GUIContent Content(string i)
|
|
{
|
|
GUIContent style;
|
|
if (!styles.TryGetValue(i, out style))
|
|
{
|
|
style = new GUIContent(i);
|
|
}
|
|
return style;
|
|
}
|
|
|
|
protected Rect DisabledLabel(GUIContent style)
|
|
{
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
Rect rect = EditorGUILayout.GetControlRect();
|
|
EditorGUI.LabelField(rect, style);
|
|
EditorGUI.EndDisabledGroup();
|
|
return rect;
|
|
}
|
|
|
|
protected Rect TexturePropertySingleLine(string i)
|
|
{
|
|
MaterialProperty prop = Property(i);
|
|
GUIContent style = Content(i);
|
|
if (prop != null)
|
|
{
|
|
return editor.TexturePropertySingleLine(style, prop);
|
|
} else {
|
|
return DisabledLabel(style);
|
|
}
|
|
}
|
|
|
|
protected Rect TexturePropertySingleLine(string i, string i2)
|
|
{
|
|
GUIContent style = Content(i);
|
|
MaterialProperty prop = Property(i);
|
|
MaterialProperty prop2 = Property(i2);
|
|
if (prop != null)
|
|
{
|
|
return editor.TexturePropertySingleLine(style, prop, prop2);
|
|
} else {
|
|
return DisabledLabel(style);
|
|
}
|
|
}
|
|
|
|
protected Rect TexturePropertySingleLine(string i, string i2, string i3)
|
|
{
|
|
GUIContent style = Content(i);
|
|
MaterialProperty prop = Property(i);
|
|
MaterialProperty prop2 = Property(i2);
|
|
MaterialProperty prop3 = Property(i3);
|
|
if (prop != null)
|
|
{
|
|
return editor.TexturePropertySingleLine(style, prop, prop2, prop3);
|
|
} else {
|
|
return DisabledLabel(style);
|
|
}
|
|
}
|
|
|
|
protected Rect TextureColorPropertyWithColorReset(string tex, string col)
|
|
{
|
|
bool hadTexture = props[tex].textureValue != null;
|
|
Rect returnRect = TexturePropertySingleLine(tex, col);
|
|
|
|
float brightness = props[col].colorValue.maxColorComponent;
|
|
if (props[tex].textureValue != null && !hadTexture && brightness <= 0f)
|
|
props[col].colorValue = Color.white;
|
|
return returnRect;
|
|
}
|
|
|
|
protected Rect TextureColorPropertyWithColorReset(string tex, string col, string prop)
|
|
{
|
|
bool hadTexture = props[tex].textureValue != null;
|
|
Rect returnRect = TexturePropertySingleLine(tex, col, prop);
|
|
|
|
float brightness = props[col].colorValue.maxColorComponent;
|
|
if (props[tex].textureValue != null && !hadTexture && brightness <= 0f)
|
|
props[col].colorValue = Color.white;
|
|
return returnRect;
|
|
}
|
|
|
|
protected Rect TexturePropertyWithHDRColor(string i, string i2)
|
|
{
|
|
GUIContent style = Content(i);
|
|
MaterialProperty prop = Property(i);
|
|
MaterialProperty prop2 = Property(i2);
|
|
if (prop != null)
|
|
{
|
|
return editor.TexturePropertyWithHDRColor(style, prop, prop2, false);
|
|
} else {
|
|
return DisabledLabel(style);
|
|
}
|
|
}
|
|
|
|
protected bool ShaderProperty(string i)
|
|
{
|
|
MaterialProperty prop;
|
|
GUIContent style;
|
|
|
|
if (!styles.TryGetValue(i, out style))
|
|
{
|
|
style = new GUIContent(i);
|
|
}
|
|
|
|
if (props.TryGetValue(i, out prop))
|
|
{
|
|
editor.ShaderProperty(prop, style);
|
|
return true;
|
|
} else {
|
|
DisabledLabel(style);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected bool TogglePropertyHeader(string i, bool display = true)
|
|
{
|
|
if (display) return ShaderProperty(i);
|
|
return false;
|
|
}
|
|
|
|
protected static void Vector2Property(MaterialProperty property, GUIContent name)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector2 vector2 = EditorGUILayout.Vector2Field(name,new Vector2(property.vectorValue.x, property.vectorValue.y),null);
|
|
if (EditorGUI.EndChangeCheck())
|
|
property.vectorValue = new Vector4(vector2.x, vector2.y, property.vectorValue.z, property.vectorValue.w);
|
|
}
|
|
protected static void Vector2PropertyZW(MaterialProperty property, GUIContent name)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector2 vector2 = EditorGUILayout.Vector2Field(name,new Vector2(property.vectorValue.z, property.vectorValue.w),null);
|
|
if (EditorGUI.EndChangeCheck())
|
|
property.vectorValue = new Vector4(property.vectorValue.x, property.vectorValue.y, vector2.x, vector2.y);
|
|
}
|
|
|
|
protected void DrawShaderPropertySameLine(string i) {
|
|
MaterialProperty prop;
|
|
|
|
int HEADER_HEIGHT = 22; // Arktoon default
|
|
Rect r = EditorGUILayout.GetControlRect(true,0,EditorStyles.layerMaskField);
|
|
r.y -= HEADER_HEIGHT;
|
|
r.height = MaterialEditor.GetDefaultPropertyHeight(props[i]);
|
|
|
|
if (props.TryGetValue(i, out prop))
|
|
{
|
|
editor.ShaderProperty(r, prop, " ");
|
|
}
|
|
}
|
|
|
|
protected GUIStyle scmStyle;
|
|
protected GUIStyle sectionHeader;
|
|
protected GUIStyle sectionHeaderBox;
|
|
|
|
protected void InitialiseStyles()
|
|
{
|
|
scmStyle = new GUIStyle("DropDownButton");
|
|
sectionHeader = new GUIStyle(EditorStyles.miniBoldLabel);
|
|
sectionHeader.padding.left = 24;
|
|
sectionHeader.padding.right = -24;
|
|
sectionHeaderBox = new GUIStyle( GUI.skin.box );
|
|
sectionHeaderBox.alignment = TextAnchor.MiddleLeft;
|
|
sectionHeaderBox.padding.left = 5;
|
|
sectionHeaderBox.padding.right = -5;
|
|
sectionHeaderBox.padding.top = 0;
|
|
sectionHeaderBox.padding.bottom = 0;
|
|
}
|
|
|
|
protected Rect DrawSectionHeaderArea(GUIContent content)
|
|
{
|
|
Rect r = EditorGUILayout.GetControlRect(true,0,EditorStyles.layerMaskField);
|
|
r.x -= 2.0f;
|
|
r.y += 2.0f;
|
|
r.height = 18.0f;
|
|
r.width -= 0.0f;
|
|
GUI.Box(r, EditorGUIUtility.IconContent("d_FilterByType"), sectionHeaderBox);
|
|
EditorGUILayout.LabelField(content, sectionHeader);
|
|
return r;
|
|
}
|
|
|
|
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] matProps)
|
|
{
|
|
this.target = materialEditor.target as Material;
|
|
this.editor = materialEditor;
|
|
Material material = this.target;
|
|
|
|
CheckShaderType(material);
|
|
|
|
ShaderBakeHeader();
|
|
|
|
bool isBaked = false;
|
|
{
|
|
MaterialProperty bakedSettings;
|
|
props.TryGetValue("__Baked", out bakedSettings);
|
|
isBaked = (bakedSettings != null && bakedSettings.floatValue == 1);
|
|
}
|
|
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
base.OnGUI(materialEditor, matProps);
|
|
}
|
|
SettingsComplexityArea();
|
|
|
|
switch ((SettingsComplexityMode)scssSettingsComplexityMode)
|
|
{
|
|
case SettingsComplexityMode.Simple:
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
MainOptions();
|
|
ShadingOptions();
|
|
DrawSectionHeaderArea(Content("s_renderingOptions"));
|
|
EmissionOptions();
|
|
OutlineOptions();
|
|
}
|
|
ManualButtonArea();
|
|
break;
|
|
case SettingsComplexityMode.Normal:
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
MainOptions();
|
|
ShadingOptions();
|
|
RenderingOptions();
|
|
OutlineOptions();
|
|
EmissionOptions();
|
|
}
|
|
RuntimeLightOptions();
|
|
InventoryOptions(isBaked);
|
|
ManualButtonArea();
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
AdvancedOptions();
|
|
}
|
|
break;
|
|
default:
|
|
case SettingsComplexityMode.Complex:
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
MainOptions();
|
|
ShadingOptions();
|
|
RenderingOptions();
|
|
OutlineOptions();
|
|
DetailOptions();
|
|
EmissionOptions();
|
|
MiscOptions();
|
|
}
|
|
RuntimeLightOptions();
|
|
InventoryOptions(isBaked);
|
|
ManualButtonArea();
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
AdvancedOptions();
|
|
}
|
|
break;
|
|
}
|
|
|
|
FooterOptions();
|
|
}
|
|
|
|
protected string[] SettingsComplexityModeOptions = new string[]
|
|
{
|
|
"Complex", "Normal", "Simple"
|
|
};
|
|
|
|
protected void SettingsComplexityArea()
|
|
{
|
|
SettingsComplexityModeOptions[0] = Content("s_fullComplexity").text;
|
|
SettingsComplexityModeOptions[1] = Content("s_normalComplexity").text;
|
|
SettingsComplexityModeOptions[2] = Content("s_simpleComplexity").text;
|
|
EditorGUILayout.Space();
|
|
|
|
if (WithChangeCheck(() =>
|
|
{
|
|
scssSettingsComplexityMode = EditorGUILayout.Popup(scssSettingsComplexityMode, SettingsComplexityModeOptions, scmStyle);
|
|
}))
|
|
{
|
|
EditorUserSettings.SetConfigValue("scss_settings_complexity_mode", scssSettingsComplexityMode.ToString());
|
|
}
|
|
}
|
|
|
|
protected void ShaderBakeHeader()
|
|
{
|
|
Rect r = EditorGUILayout.GetControlRect(true,0,EditorStyles.layerMaskField);
|
|
r.x -= 12.0f;
|
|
r.y -= 8.0f;
|
|
r.height = 18.0f;
|
|
r.width += 4.0f;
|
|
float maxWidth = 128.0f;
|
|
Rect r2 = r;
|
|
r2.x = r.width - maxWidth + 14.0f;
|
|
r2.width = maxWidth;
|
|
GUI.Box(r, "", EditorStyles.toolbar);
|
|
|
|
GUIContent s_bakeButton;
|
|
MaterialProperty shaderOptimizer;
|
|
// Create the GUIContent for the button so it can be rendered.
|
|
if (!props.TryGetValue("__Baked", out shaderOptimizer))
|
|
{
|
|
s_bakeButton = new GUIContent ("s_bakeButton");
|
|
}
|
|
else
|
|
{
|
|
// Determine whether we're baking or unbaking materials.
|
|
if (shaderOptimizer.floatValue == 1)
|
|
{
|
|
if (!styles.TryGetValue("s_bakeButtonRevert", out s_bakeButton))
|
|
s_bakeButton = new GUIContent ("s_bakeButtonRevert");
|
|
}
|
|
else
|
|
{
|
|
if (editor.targets.Length == 1)
|
|
{
|
|
if (!styles.TryGetValue("s_bakeButton", out s_bakeButton))
|
|
s_bakeButton = new GUIContent ("s_bakeButton");
|
|
}
|
|
else
|
|
{
|
|
if (!styles.TryGetValue("s_bakeButtonPlural", out s_bakeButton))
|
|
s_bakeButton = new GUIContent ("s_bakeButtonPlural");
|
|
s_bakeButton = new GUIContent(s_bakeButton);
|
|
s_bakeButton.text = String.Format(s_bakeButton.text, "" + editor.targets.Length.ToString());
|
|
}
|
|
}
|
|
}
|
|
// Draw the button. Because of Unity shenanigans, if we don't always draw the button,
|
|
// the layout will explode on the first update of the inspector.
|
|
if (GUI.Button(r2, s_bakeButton, EditorStyles.miniButtonMid))
|
|
{
|
|
// If it's a mixed value, then only allow baking. It shouldn't be a mixed value,
|
|
// but a material might think it's baked when it isn't, which needs to be handled anyway.
|
|
if (shaderOptimizer.hasMixedValue)
|
|
{
|
|
foreach (Material m in editor.targets)
|
|
{
|
|
m.SetFloat(shaderOptimizer.name, 1);
|
|
MaterialProperty[] props = MaterialEditor.GetMaterialProperties(new UnityEngine.Object[] { m });
|
|
if (!ShaderOptimizer.Lock(m, props)) // Error locking shader, revert property
|
|
m.SetFloat(shaderOptimizer.name, 0);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
shaderOptimizer.floatValue = shaderOptimizer.floatValue == 1 ? 0 : 1;
|
|
if (shaderOptimizer.floatValue == 1)
|
|
{
|
|
foreach (Material m in editor.targets)
|
|
{
|
|
MaterialProperty[] props = MaterialEditor.GetMaterialProperties(new UnityEngine.Object[] { m });
|
|
if (!ShaderOptimizer.Lock(m, props))
|
|
m.SetFloat(shaderOptimizer.name, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (Material m in editor.targets)
|
|
{
|
|
if (!ShaderOptimizer.Unlock(m))
|
|
m.SetFloat(shaderOptimizer.name, 1);
|
|
MaterialChanged(m);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EditorGUILayout.LabelField("", EditorStyles.label); // Spacing only
|
|
}
|
|
|
|
protected void MainOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
DrawSectionHeaderArea(Content("s_mainOptions"));
|
|
|
|
EditorGUILayout.Space();
|
|
TexturePropertySingleLine("_MainTex", "_Color");
|
|
|
|
TexturePropertySingleLine("_BumpMap", "_BumpScale");
|
|
|
|
TexturePropertySingleLine("_ColorMask");
|
|
|
|
// For Standard compatibility, but not sure what the purpose is
|
|
if (WithChangeCheck(() =>
|
|
{
|
|
editor.TextureScaleOffsetProperty(props["_MainTex"]);
|
|
}))
|
|
{
|
|
props["_EmissionMap"].textureScaleAndOffset = props["_MainTex"].textureScaleAndOffset;
|
|
}
|
|
|
|
if ((AlbedoAlphaMode)props["_AlbedoAlphaMode"].floatValue == AlbedoAlphaMode.ClippingMask)
|
|
{
|
|
EditorGUILayout.Space();
|
|
TexturePropertySingleLine("_ClippingMask", "_Tweak_Transparency");
|
|
editor.TextureScaleOffsetProperty(props["_ClippingMask"]);
|
|
}
|
|
EditorGUILayout.Space();
|
|
|
|
if ((RenderingMode)props[BaseStyles.renderingModeName].floatValue > 0)
|
|
{
|
|
foreach (Material mat in WithMaterialPropertyDropdown(props["_AlphaSharp"], Enum.GetNames(typeof(TransparencyMode)), editor))
|
|
{
|
|
SetupMaterialWithTransparencyMode(mat, (TransparencyMode)props["_AlphaSharp"].floatValue);
|
|
}
|
|
ShaderProperty("_Cutoff");
|
|
}
|
|
}
|
|
|
|
protected void ShadingOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
DrawSectionHeaderArea(Content("s_shadingOptions"));
|
|
if (usingLightramp) LightrampOptions();
|
|
if (usingCrosstone) CrosstoneOptions();
|
|
}
|
|
|
|
protected void RenderingOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
DrawSectionHeaderArea(Content("s_renderingOptions"));
|
|
|
|
SpecularOptions();
|
|
RimlightOptions();
|
|
MatcapOptions();
|
|
}
|
|
|
|
protected void DetailOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
DrawSectionHeaderArea(Content("s_detailOptions"));
|
|
SubsurfaceOptions();
|
|
DetailMapOptions();
|
|
}
|
|
|
|
protected void EmissionOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
MaterialProperty emissionMapProp;
|
|
if (props.TryGetValue("_EmissionMap", out emissionMapProp))
|
|
{
|
|
bool hadEmissionTexture = emissionMapProp.textureValue != null;
|
|
TexturePropertyWithHDRColor("_EmissionMap", "_EmissionColor");
|
|
// If texture was assigned and color was black set color to white
|
|
float brightness = props["_EmissionColor"].colorValue.maxColorComponent;
|
|
if (emissionMapProp.textureValue != null && !hadEmissionTexture && brightness <= 0f)
|
|
props["_EmissionColor"].colorValue = Color.white;
|
|
editor.TextureScaleOffsetProperty(props["_EmissionMap"]);
|
|
EditorGUILayout.Space();
|
|
}
|
|
|
|
if (ShaderProperty("_UseAdvancedEmission") && PropertyEnabled(props["_UseAdvancedEmission"]))
|
|
{
|
|
target.EnableKeyword("_EMISSION");
|
|
TexturePropertySingleLine("_DetailEmissionMap");
|
|
editor.TextureScaleOffsetProperty(props["_DetailEmissionMap"]);
|
|
ShaderProperty("_DetailEmissionUVSec");
|
|
EditorGUI.indentLevel ++;
|
|
|
|
WithMaterialPropertyDropdown(props["_EmissionDetailType"], Enum.GetNames(typeof(DetailEmissionMode)), editor);
|
|
MaterialProperty deProp;
|
|
if (props.TryGetValue("_EmissionDetailType", out deProp))
|
|
{
|
|
switch ((DetailEmissionMode)deProp.floatValue)
|
|
{
|
|
case DetailEmissionMode.Phase:
|
|
//ShaderProperty("_EmissionDetailParams");
|
|
Vector2Property(props["_EmissionDetailParams"], Content("s_EmissionDetailScroll"));
|
|
Vector2PropertyZW(props["_EmissionDetailParams"], Content("s_EmissionDetailPhase"));
|
|
break;
|
|
case DetailEmissionMode.AudioLink:
|
|
// AudioLink
|
|
ShaderProperty("_alColorR");
|
|
ShaderProperty("_alColorG");
|
|
ShaderProperty("_alColorB");
|
|
ShaderProperty("_alColorA");
|
|
ShaderProperty("_alBandR");
|
|
ShaderProperty("_alBandG");
|
|
ShaderProperty("_alBandB");
|
|
ShaderProperty("_alBandA");
|
|
ShaderProperty("_alModeR");
|
|
ShaderProperty("_alModeG");
|
|
ShaderProperty("_alModeB");
|
|
ShaderProperty("_alModeA");
|
|
ShaderProperty("_alTimeRangeR");
|
|
ShaderProperty("_alTimeRangeG");
|
|
ShaderProperty("_alTimeRangeB");
|
|
ShaderProperty("_alTimeRangeA");
|
|
ShaderProperty("_alUseFallback");
|
|
ShaderProperty("_alFallbackBPM");
|
|
ShaderProperty("_UseEmissiveLightSense");
|
|
ShaderProperty("_EmissiveLightSenseStart");
|
|
ShaderProperty("_EmissiveLightSenseEnd");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
EditorGUI.indentLevel --;
|
|
} else {
|
|
target.DisableKeyword("_EMISSION");
|
|
}
|
|
EditorGUILayout.Space();
|
|
ShaderProperty("_CustomFresnelColor");
|
|
// For some reason, this property doesn't have spacing after it
|
|
EditorGUILayout.Space();
|
|
}
|
|
|
|
protected void MiscOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
DrawSectionHeaderArea(Content("s_miscOptions"));
|
|
EditorGUILayout.Space();
|
|
ShaderProperty("_PixelSampleMode");
|
|
AnimationOptions();
|
|
VanishingOptions();
|
|
}
|
|
|
|
protected void LightrampOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
foreach (Material mat in WithMaterialPropertyDropdown(props["_LightRampType"], Enum.GetNames(typeof(LightRampType)), editor))
|
|
{
|
|
SetupMaterialWithLightRampType(mat, (LightRampType)props["_LightRampType"].floatValue);
|
|
}
|
|
|
|
if ((LightRampType)props["_LightRampType"].floatValue != LightRampType.None)
|
|
{
|
|
WithGroupHorizontal(() =>
|
|
{
|
|
TexturePropertySingleLine("_Ramp");
|
|
if (GUILayout.Button(Content("s_gradientEditorButton"), "button"))
|
|
{
|
|
XSGradientEditor.callGradientEditor(target);
|
|
}
|
|
});
|
|
}
|
|
ShaderProperty("_ShadowLift");
|
|
ShaderProperty("_IndirectLightingBoost");
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
TexturePropertySingleLine("_ShadowMask", "_ShadowMaskColor");
|
|
|
|
foreach (Material mat in WithMaterialPropertyDropdown(props["_ShadowMaskType"], Enum.GetNames(typeof(ShadowMaskType)), editor))
|
|
{
|
|
SetupMaterialWithShadowMaskType(mat, (ShadowMaskType)props["_ShadowMaskType"].floatValue);
|
|
}
|
|
|
|
ShaderProperty("_Shadow");
|
|
}
|
|
|
|
protected void CrosstoneOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
WithGroupHorizontal(() => {
|
|
TextureColorPropertyWithColorReset("_1st_ShadeMap", "_1st_ShadeColor");
|
|
WithMaterialPropertyDropdownNoLabel(props["_CrosstoneToneSeparation"], Enum.GetNames(typeof(ToneSeparationType)), editor);
|
|
});
|
|
ShaderProperty("_1st_ShadeColor_Step");
|
|
ShaderProperty("_1st_ShadeColor_Feather");
|
|
EditorGUILayout.Space();
|
|
|
|
WithGroupHorizontal(() => {
|
|
TextureColorPropertyWithColorReset("_2nd_ShadeMap", "_2nd_ShadeColor");
|
|
WithMaterialPropertyDropdownNoLabel(props["_Crosstone2ndSeparation"], Enum.GetNames(typeof(ToneSeparationType)), editor);
|
|
});
|
|
ShaderProperty("_2nd_ShadeColor_Step");
|
|
ShaderProperty("_2nd_ShadeColor_Feather");
|
|
EditorGUILayout.Space();
|
|
|
|
TexturePropertySingleLine("_ShadingGradeMap", "_Tweak_ShadingGradeMapLevel");
|
|
}
|
|
|
|
protected void SpecularOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
MaterialProperty specProp;
|
|
if (props.TryGetValue("_SpecularType", out specProp))
|
|
{
|
|
foreach (Material mat in WithMaterialPropertyDropdown(specProp, Enum.GetNames(typeof(SpecularType)), editor))
|
|
{
|
|
SetupMaterialWithSpecularType(mat, (SpecularType)specProp.floatValue);
|
|
}
|
|
TogglePropertyHeader("_SpecularType", false);
|
|
|
|
switch ((SpecularType)specProp.floatValue)
|
|
{
|
|
case SpecularType.Standard:
|
|
case SpecularType.Cloth:
|
|
TextureColorPropertyWithColorReset("_SpecGlossMap", "_SpecColor");
|
|
ShaderProperty("_Smoothness");
|
|
ShaderProperty("_UseMetallic");
|
|
ShaderProperty("_UseEnergyConservation");
|
|
break;
|
|
case SpecularType.Cel:
|
|
TextureColorPropertyWithColorReset("_SpecGlossMap", "_SpecColor");
|
|
ShaderProperty("_Smoothness");
|
|
ShaderProperty("_CelSpecularSoftness");
|
|
ShaderProperty("_CelSpecularSteps");
|
|
ShaderProperty("_UseMetallic");
|
|
ShaderProperty("_UseEnergyConservation");
|
|
break;
|
|
case SpecularType.Anisotropic:
|
|
TextureColorPropertyWithColorReset("_SpecGlossMap", "_SpecColor");
|
|
ShaderProperty("_Smoothness");
|
|
ShaderProperty("_Anisotropy");
|
|
ShaderProperty("_UseMetallic");
|
|
ShaderProperty("_UseEnergyConservation");
|
|
break;
|
|
case SpecularType.CelStrand:
|
|
TextureColorPropertyWithColorReset("_SpecGlossMap", "_SpecColor");
|
|
ShaderProperty("_Smoothness");
|
|
ShaderProperty("_CelSpecularSoftness");
|
|
ShaderProperty("_CelSpecularSteps");
|
|
ShaderProperty("_Anisotropy");
|
|
ShaderProperty("_UseMetallic");
|
|
ShaderProperty("_UseEnergyConservation");
|
|
break;
|
|
case SpecularType.Disable:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void RimlightOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
MaterialProperty rimProp;
|
|
if (props.TryGetValue("_UseFresnel", out rimProp))
|
|
{
|
|
TogglePropertyHeader("_UseFresnel");
|
|
bool isTintable =
|
|
(AmbientFresnelType)rimProp.floatValue == AmbientFresnelType.Lit
|
|
|| (AmbientFresnelType)rimProp.floatValue == AmbientFresnelType.Ambient;
|
|
|
|
if (PropertyEnabled(rimProp))
|
|
{
|
|
ShaderProperty("_FresnelWidth");
|
|
ShaderProperty("_FresnelStrength");
|
|
if (isTintable) ShaderProperty("_FresnelTint");
|
|
|
|
ShaderProperty("_UseFresnelLightMask");
|
|
if (PropertyEnabled(props["_UseFresnelLightMask"]))
|
|
{
|
|
ShaderProperty("_FresnelLightMask");
|
|
if (isTintable) ShaderProperty("_FresnelTintInv");
|
|
ShaderProperty("_FresnelWidthInv");
|
|
ShaderProperty("_FresnelStrengthInv");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawMatcapField(string texture, string blend, string tint, string strength)
|
|
{
|
|
WithGroupHorizontal(() => {
|
|
TextureColorPropertyWithColorReset(texture, tint);
|
|
WithMaterialPropertyDropdownNoLabel(props[blend], Enum.GetNames(typeof(MatcapBlendModes)), editor);
|
|
});
|
|
EditorGUI.indentLevel+=2;
|
|
ShaderProperty(strength);
|
|
EditorGUI.indentLevel-=2;
|
|
}
|
|
|
|
protected void MatcapOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
MaterialProperty matcapProp;
|
|
if (props.TryGetValue("_UseMatcap", out matcapProp))
|
|
{
|
|
var mMode = (MatcapType)matcapProp.floatValue;
|
|
if (WithChangeCheck(() =>
|
|
{
|
|
mMode = (MatcapType)EditorGUILayout.Popup(Content("_UseMatcap"),
|
|
(int)mMode, Enum.GetNames(typeof(MatcapType)));
|
|
})) {
|
|
editor.RegisterPropertyChangeUndo(Content("_UseMatcap").text);
|
|
matcapProp.floatValue = (float)mMode;
|
|
}
|
|
TogglePropertyHeader("_UseMatcap", false);
|
|
|
|
if (PropertyEnabled(matcapProp))
|
|
{
|
|
TexturePropertySingleLine("_MatcapMask");
|
|
DrawMatcapField("_Matcap1", "_Matcap1Blend", "_Matcap1Tint", "_Matcap1Strength");
|
|
DrawMatcapField("_Matcap2", "_Matcap2Blend", "_Matcap2Tint", "_Matcap2Strength");
|
|
DrawMatcapField("_Matcap3", "_Matcap3Blend", "_Matcap3Tint", "_Matcap3Strength");
|
|
DrawMatcapField("_Matcap4", "_Matcap4Blend", "_Matcap4Tint", "_Matcap4Strength");
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void SubsurfaceOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
if (TogglePropertyHeader("_UseSubsurfaceScattering"))
|
|
{
|
|
if (PropertyEnabled(props["_UseSubsurfaceScattering"]))
|
|
{
|
|
TexturePropertySingleLine("_ThicknessMap");
|
|
ShaderProperty("_ThicknessMapPower");
|
|
ShaderProperty("_ThicknessMapInvert");
|
|
ShaderProperty("_SSSCol");
|
|
ShaderProperty("_SSSIntensity");
|
|
ShaderProperty("_SSSPow");
|
|
ShaderProperty("_SSSDist");
|
|
ShaderProperty("_SSSAmbient");
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void DetailMapOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
if (TogglePropertyHeader("_UseDetailMaps")){
|
|
if (PropertyEnabled(props["_UseDetailMaps"]))
|
|
{
|
|
target.EnableKeyword("_DETAIL_MULX2");
|
|
TexturePropertySingleLine("_DetailAlbedoMap", "_DetailAlbedoMapScale");
|
|
TexturePropertySingleLine("_DetailNormalMap", "_DetailNormalMapScale");
|
|
TexturePropertySingleLine("_SpecularDetailMask", "_SpecularDetailStrength");
|
|
|
|
editor.TextureScaleOffsetProperty(props["_DetailAlbedoMap"]);
|
|
ShaderProperty("_UVSec");
|
|
} else {
|
|
target.DisableKeyword("_DETAIL_MULX2");
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void AnimationOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
if (TogglePropertyHeader("_UseAnimation") && PropertyEnabled(props["_UseAnimation"]))
|
|
{
|
|
ShaderProperty("_AnimationSpeed");
|
|
ShaderProperty("_TotalFrames");
|
|
ShaderProperty("_FrameNumber");
|
|
ShaderProperty("_Columns");
|
|
ShaderProperty("_Rows");
|
|
}
|
|
|
|
}
|
|
|
|
protected void VanishingOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
if (TogglePropertyHeader("_UseVanishing") && PropertyEnabled(props["_UseVanishing"]))
|
|
{
|
|
ShaderProperty("_VanishingStart");
|
|
ShaderProperty("_VanishingEnd");
|
|
}
|
|
}
|
|
|
|
protected void OutlineOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
MaterialProperty outlineProp;
|
|
if (props.TryGetValue("_OutlineMode", out outlineProp))
|
|
{
|
|
foreach (Material mat in WithMaterialPropertyDropdown(outlineProp, Enum.GetNames(typeof(OutlineMode)), editor))
|
|
{
|
|
SetupMaterialWithOutlineMode(mat, (OutlineMode)outlineProp.floatValue);
|
|
}
|
|
TogglePropertyHeader("_OutlineMode", false);
|
|
|
|
switch ((OutlineMode)outlineProp.floatValue)
|
|
{
|
|
case OutlineMode.Tinted:
|
|
case OutlineMode.Colored:
|
|
TexturePropertySingleLine("_OutlineMask");
|
|
ShaderProperty("_outline_color");
|
|
ShaderProperty("_outline_width");
|
|
ShaderProperty("_OutlineZPush");
|
|
break;
|
|
case OutlineMode.None:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void ManualButtonArea()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
DrawSectionHeaderArea(Content("Resources"));
|
|
|
|
Rect r = EditorGUILayout.GetControlRect(true,0,EditorStyles.layerMaskField);
|
|
r.x -= 2.0f;
|
|
r.y += 2.0f;
|
|
r.height = 18.0f;
|
|
Rect r2 = r;
|
|
r2.width = r.width / 2.0f;
|
|
//GUI.Box(r, EditorGUIUtility.IconContent("Toolbar"), EditorStyles.toolbar);
|
|
if (GUI.Button(r2, Content("s_manualButton"), EditorStyles.miniButtonLeft)) Application.OpenURL("https://gitlab.com/s-ilent/SCSS/wikis/Manual/Setting-Overview");
|
|
r2.x += r2.width;
|
|
if (GUI.Button(r2, Content("s_socialButton"), EditorStyles.miniButtonRight)) Application.OpenURL("https://discord.gg/uHJx4g629K");
|
|
EditorGUILayout.LabelField("", EditorStyles.label);
|
|
}
|
|
|
|
protected void RuntimeLightOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
ShaderProperty("_LightMultiplyAnimated");
|
|
ShaderProperty("_LightClampAnimated");
|
|
}
|
|
|
|
protected void InventoryOptions(bool isBaked)
|
|
{
|
|
EditorGUILayout.Space();
|
|
DrawSectionHeaderArea(Content("s_inventoryOptions"));
|
|
EditorGUILayout.Space();
|
|
|
|
MaterialProperty invProp;
|
|
bool[] enabledItems = new bool[16];
|
|
float toggleOptionWidth = (EditorGUIUtility.currentViewWidth / 5.0f); // blursed
|
|
|
|
if (props.TryGetValue("_UseInventory", out invProp))
|
|
{
|
|
using (new EditorGUI.DisabledScope(isBaked == true))
|
|
{
|
|
TogglePropertyHeader("_UseInventory");
|
|
if (PropertyEnabled(invProp)) ShaderProperty("_InventoryStride");
|
|
}
|
|
if (PropertyEnabled(invProp))
|
|
{
|
|
for (int i = 1; i <= 16; i++)
|
|
{
|
|
enabledItems[i-1] = Property(String.Format("_InventoryItem{0:00}Animated", i)).floatValue == 1;
|
|
}
|
|
EditorGUI.BeginChangeCheck();
|
|
for (int i = 0; i < (16/4); i++)
|
|
{ EditorGUILayout.BeginHorizontal("Box");
|
|
enabledItems[i*4+0] = EditorGUILayout.ToggleLeft(
|
|
(i*4+1).ToString(), enabledItems[i*4+0], GUILayout.Width(toggleOptionWidth));
|
|
enabledItems[i*4+1] = EditorGUILayout.ToggleLeft(
|
|
(i*4+2).ToString(), enabledItems[i*4+1], GUILayout.Width(toggleOptionWidth));
|
|
enabledItems[i*4+2] = EditorGUILayout.ToggleLeft(
|
|
(i*4+3).ToString(), enabledItems[i*4+2], GUILayout.Width(toggleOptionWidth));
|
|
enabledItems[i*4+3] = EditorGUILayout.ToggleLeft(
|
|
(i*4+4).ToString(), enabledItems[i*4+3], GUILayout.Width(toggleOptionWidth));
|
|
EditorGUILayout.EndHorizontal();
|
|
};
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
for (int i = 1; i <= 16; i++)
|
|
{
|
|
Property(String.Format("_InventoryItem{0:00}Animated", i)).floatValue = enabledItems[i-1] ? 1 : 0;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void AdvancedOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
DrawSectionHeaderArea(Content("s_advancedOptions"));
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
foreach (Material mat in WithMaterialPropertyDropdown(props["_VertexColorType"], Enum.GetNames(typeof(VertexColorType)), editor))
|
|
{
|
|
SetupMaterialWithVertexColorType(mat, (VertexColorType)props["_VertexColorType"].floatValue);
|
|
}
|
|
|
|
foreach (Material mat in WithMaterialPropertyDropdown(props["_AlbedoAlphaMode"], CommonStyles.albedoAlphaModeNames, editor))
|
|
{
|
|
SetupMaterialWithAlbedo(mat, props["_MainTex"], props["_AlbedoAlphaMode"]);
|
|
}
|
|
|
|
foreach (Material mat in WithMaterialPropertyDropdown(props["_LightingCalculationType"], Enum.GetNames(typeof(LightingCalculationType)), editor))
|
|
{
|
|
SetupMaterialWithLightingCalculationType(mat, (LightingCalculationType)props["_LightingCalculationType"].floatValue);
|
|
}
|
|
|
|
ShaderProperty("_IndirectShadingType");
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
ShaderProperty("_DiffuseGeomShadowFactor");
|
|
ShaderProperty("_LightWrappingCompensationFactor");
|
|
|
|
ShaderProperty("_LightSkew");
|
|
|
|
MaterialProperty specProp;
|
|
if (props.TryGetValue("_SpecularType", out specProp) && specProp.floatValue >= 1.0f)
|
|
{
|
|
if (WithChangeCheck(() =>
|
|
{
|
|
ShaderProperty("_SpecularHighlights");
|
|
ShaderProperty("_GlossyReflections");
|
|
})) {
|
|
MaterialChanged(target);
|
|
}
|
|
};
|
|
|
|
StencilOptions(editor, target);
|
|
}
|
|
|
|
protected void FooterOptions()
|
|
{
|
|
EditorGUILayout.Space();
|
|
|
|
if (WithChangeCheck(() =>
|
|
{
|
|
editor.ShaderProperty(renderQueueOverride, BaseStyles.renderQueueOverride);
|
|
})) {
|
|
MaterialChanged(target);
|
|
}
|
|
|
|
// Show the RenderQueueField but do not allow users to directly manipulate it. That is done via the renderQueueOverride.
|
|
GUI.enabled = false;
|
|
editor.RenderQueueField();
|
|
|
|
if (!GUI.enabled && !target.enableInstancing)
|
|
{
|
|
target.enableInstancing = true;
|
|
}
|
|
|
|
editor.EnableInstancingField();
|
|
}
|
|
|
|
protected static void SetupMaterialWithTransparencyMode(Material material, TransparencyMode shadowMaskType)
|
|
{
|
|
switch ((TransparencyMode)material.GetFloat("_AlphaSharp"))
|
|
{
|
|
case TransparencyMode.Sharp:
|
|
material.SetFloat("_AlphaSharp", 1);
|
|
break;
|
|
default:
|
|
case TransparencyMode.Soft:
|
|
material.SetFloat("_AlphaSharp", 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithShadowMaskType(Material material, ShadowMaskType shadowMaskType)
|
|
{
|
|
switch ((ShadowMaskType)material.GetFloat("_ShadowMaskType"))
|
|
{
|
|
case ShadowMaskType.Occlusion:
|
|
material.SetFloat("_ShadowMaskType", 0);
|
|
break;
|
|
case ShadowMaskType.Tone:
|
|
material.SetFloat("_ShadowMaskType", 1);
|
|
break;
|
|
case ShadowMaskType.Auto:
|
|
material.SetFloat("_ShadowMaskType", 2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithLightRampType(Material material, LightRampType lightRampType)
|
|
{
|
|
switch ((LightRampType)material.GetFloat("_LightRampType"))
|
|
{
|
|
case LightRampType.Horizontal:
|
|
material.SetFloat("_LightRampType", 0);
|
|
break;
|
|
case LightRampType.Vertical:
|
|
material.SetFloat("_LightRampType", 1);
|
|
break;
|
|
case LightRampType.None:
|
|
material.SetFloat("_LightRampType", 2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected float? GetSerializedMaterialFloat(Material material, string propName)
|
|
{
|
|
float? floatVal = new SerializedObject(material).FindProperty("m_SavedProperties.m_Floats." + propName).floatValue;
|
|
return floatVal;
|
|
}
|
|
|
|
protected Vector4? GetSerializedMaterialVector4(Material material, string propName)
|
|
{
|
|
Vector4? colorVal = new SerializedObject(material).FindProperty("m_SavedProperties.m_Colors." + propName).colorValue;
|
|
return colorVal;
|
|
}
|
|
|
|
protected void UpgradeMatcaps(Material material)
|
|
{
|
|
// Check if the new properties exist.
|
|
// NOTE: This is written with the current Unity behaviour in mind.
|
|
// - GetFloat returns NULL for properties not in the CURRENT shader.
|
|
// - GetTexture returns textures for properties not in the current shader.
|
|
// If GetFloat gets changed, intensity transfer will work.
|
|
// If GetTexture gets changed, the whole thing will break.
|
|
|
|
bool oldMatcaps =
|
|
(material.GetFloat("_UseMatcap") == 1.0) &&
|
|
(material.GetFloat("_Matcap1Strength") == 1.0 && material.GetFloat("_Matcap2Strength") == 1.0 &&
|
|
material.GetFloat("_Matcap3Strength") == 1.0 && material.GetFloat("_Matcap4Strength") == 1.0) &&
|
|
(props["_Matcap1"].textureValue == null && props["_Matcap2"].textureValue == null &&
|
|
props["_Matcap3"].textureValue == null && props["_Matcap4"].textureValue == null) &&
|
|
GetTextureProperty(material, "_AdditiveMatcap"); // Only exists in old materials.
|
|
if (oldMatcaps)
|
|
{
|
|
// GetFloat is bugged but GetTexture is not, so we use GetFloatProperty so we can handle null.
|
|
float? additiveStrength = GetFloatProperty(material, "_AdditiveMatcapStrength");
|
|
float? multiplyStrength = GetFloatProperty(material, "_MultiplyMatcapStrength");
|
|
float? medianStrength = GetFloatProperty(material, "_MidBlendMatcapStrength");
|
|
Texture additiveMatcap = GetTextureProperty(material, "_AdditiveMatcap");
|
|
Texture multiplyMatcap = GetTextureProperty(material, "_MultiplyMatcap");
|
|
Texture medianMatcap = GetTextureProperty(material, "_MidBlendMatcap");
|
|
|
|
// Mask layout is RGBA
|
|
if (additiveMatcap)
|
|
{
|
|
props["_Matcap2"].textureValue = additiveMatcap;
|
|
props["_Matcap2Blend"].floatValue = (float)MatcapBlendModes.Additive;
|
|
props["_Matcap2Strength"].floatValue = additiveStrength ?? 1;
|
|
}
|
|
if (multiplyMatcap)
|
|
{
|
|
props["_Matcap4"].textureValue = multiplyMatcap;
|
|
props["_Matcap4Blend"].floatValue = (float)MatcapBlendModes.Multiply;
|
|
props["_Matcap4Strength"].floatValue = multiplyStrength ?? 0;
|
|
// Multiply at 1.0 is usually wrong. This also prevents oldMatcaps from being true.
|
|
}
|
|
if (medianMatcap)
|
|
{
|
|
props["_Matcap3"].textureValue = medianMatcap;
|
|
props["_Matcap3Blend"].floatValue = (float)MatcapBlendModes.Median;
|
|
props["_Matcap3Strength"].floatValue = medianStrength ?? 1;
|
|
}
|
|
}
|
|
}
|
|
// Taken from Standard. Only Standard keywords are set here!
|
|
protected static void SetMaterialKeywords(Material material)
|
|
{
|
|
// Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation
|
|
// (MaterialProperty value might come from renderer material property block)
|
|
SetKeyword(material, "_NORMALMAP",
|
|
GetTextureProperty(material, "_BumpMap") && GetTextureProperty(material, "_DetailNormalMap"));
|
|
/*
|
|
SetKeyword(material, "_SPECGLOSSMAP", GetTextureProperty(material, "_SpecGlossMap"));
|
|
SetKeyword(material, "_PARALLAXMAP", GetTextureProperty(material, "_ParallaxMap"));
|
|
SetKeyword(material, "_DETAIL_MULX2", GetTextureProperty(material, "_DetailAlbedoMap")
|
|
&& GetTextureProperty(material, "_DetailNormalMap")
|
|
&& GetTextureProperty(material, "_DetailEmissionMap")
|
|
&& GetTextureProperty(material, "_SpecularDetailMask"));
|
|
*/
|
|
/*
|
|
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
|
|
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.
|
|
// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.
|
|
MaterialEditor.FixupEmissiveFlag(material);
|
|
bool shouldEmissionBeEnabled = (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
|
|
SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
|
|
*/
|
|
}
|
|
|
|
|
|
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
|
|
{
|
|
// Use nullable types for Color and float, because Texture is nullable.
|
|
Dictionary<string, Color?> tColor = new Dictionary<string, Color?>();
|
|
Dictionary<string, float?> tFloat = new Dictionary<string, float?>();
|
|
Dictionary<string, Texture> tTexture = new Dictionary<string, Texture>();
|
|
|
|
// Cache old shader properties with potentially different names than the new shader.
|
|
Vector4? textureScaleOffset = null;
|
|
float? cullMode = GetFloatProperty(material, "_Cull");
|
|
|
|
// Register properties that already exist but may be overridden.
|
|
string[] colorProps = {
|
|
"_EmissionColor",
|
|
"_FresnelTint",
|
|
"_FresnelTintInv",
|
|
"_Matcap1Tint",
|
|
"_outline_color",
|
|
"_SpecColor"
|
|
};
|
|
|
|
string[] floatProps = {
|
|
"_1st_ShadeColor_Feather",
|
|
"_1st_ShadeColor_Step",
|
|
"_2nd_ShadeColor_Feather",
|
|
"_2nd_ShadeColor_Step",
|
|
"_BumpScale",
|
|
"_CelSpecularSoftness",
|
|
"_Crosstone2ndSeparation",
|
|
"_CrosstoneToneSeparation",
|
|
"_FresnelLightMask",
|
|
"_FresnelStrength",
|
|
"_FresnelStrengthInv",
|
|
"_FresnelWidth",
|
|
"_FresnelWidthInv",
|
|
"_Matcap1Blend",
|
|
"_Matcap1Strength",
|
|
"_outline_width",
|
|
"_OutlineMode",
|
|
"_Smoothness",
|
|
"_SpecularType",
|
|
"_UseFresnel",
|
|
"_UseFresnelLightMask",
|
|
"_UseMatcap"
|
|
};
|
|
|
|
string[] textureProps = {
|
|
"_1st_ShadeMap",
|
|
"_2nd_ShadeMap",
|
|
"_BumpMap",
|
|
"_EmissionMap",
|
|
"_Matcap1",
|
|
"_MatcapMask",
|
|
"_OutlineMask",
|
|
"_SpecGlossMap",
|
|
"_SpecularDetailMask"
|
|
};
|
|
|
|
foreach (string p in colorProps) { tColor[p] = GetColorProperty(material, p); };
|
|
foreach (string p in floatProps) { tFloat[p] = GetFloatProperty(material, p); };
|
|
foreach (string p in textureProps) { tTexture[p] = GetTextureProperty(material, p); };
|
|
|
|
int? stencilReference = GetIntProperty(material, "_Stencil");
|
|
int? stencilComparison = GetIntProperty(material, "_StencilComp");
|
|
int? stencilOperation = GetIntProperty(material, "_StencilOp");
|
|
int? stencilFail = GetIntProperty(material, "_StencilFail");
|
|
|
|
if (oldShader)
|
|
{
|
|
if (oldShader.name.Contains("Silent's Cel Shading"))
|
|
{
|
|
// Handle the case where someone swaps the outline mode by changing from
|
|
// the (Outline) to the no outline shader.
|
|
if (oldShader.name.Contains("Outline") && !newShader.name.Contains("Outline"))
|
|
{
|
|
tFloat["_OutlineMode"] = 0.0f;
|
|
}
|
|
if (!oldShader.name.Contains("Outline") && newShader.name.Contains("Outline"))
|
|
{
|
|
tFloat["_OutlineMode"] = 1.0f;
|
|
}
|
|
// Handle transferring from really old versions.
|
|
if (oldShader.name.Contains(TransparentCutoutShadersPath))
|
|
{
|
|
tFloat[BaseStyles.renderingModeName] = (float)RenderingMode.Cutout;
|
|
tFloat[BaseStyles.customRenderingModeName] = (float)CustomRenderingMode.Cutout;
|
|
}
|
|
else if (oldShader.name.Contains(TransparentShadersPath))
|
|
{
|
|
tFloat[BaseStyles.renderingModeName] = (float)RenderingMode.Fade;
|
|
tFloat[BaseStyles.customRenderingModeName] = (float)CustomRenderingMode.Fade;
|
|
}
|
|
}
|
|
if (oldShader.name.Contains("UnityChanToonShader"))
|
|
{
|
|
// Build translation table.
|
|
tTexture["_BumpMap"] = GetTextureProperty(material, "_NormalMap");
|
|
// _Tweak_ShadingGradeMapLevel is named the same.
|
|
|
|
if (GetFloatProperty(material, "_Inverse_Clipping") == 1) Debug.Log("Note: Inverse clipping currently not supported.");
|
|
if (GetTextureProperty(material, "_ClippingMask")) tFloat["_AlbedoAlphaMode"] = (float)AlbedoAlphaMode.ClippingMask;
|
|
tFloat["_Tweak_Transparency"] = GetFloatProperty(material, "_Tweak_transparency");
|
|
tFloat["_Cutoff"] = 1.0f - GetFloatProperty(material, "_Clipping_Level") ?? 0;
|
|
|
|
// Tone seperation is based on whether BaseAs1st is set.
|
|
// 2nd seperation is based on whether 1stAs2nd is set.
|
|
tFloat["_CrosstoneToneSeparation"] = 1.0f - GetFloatProperty(material, "_Use_BaseAs1st") ?? 0;
|
|
tFloat["_Crosstone2ndSeparation"] = 1.0f - GetFloatProperty(material, "_Use_1stAs2nd") ?? 0;
|
|
|
|
if (oldShader.name.Contains("DoubleShadeWithFeather"))
|
|
{
|
|
tFloat["_1st_ShadeColor_Step"] = GetFloatProperty(material, "_BaseColor_Step");
|
|
tFloat["_1st_ShadeColor_Feather"] = GetFloatProperty(material, "_BaseShade_Feather");
|
|
tFloat["_2nd_ShadeColor_Step"] = GetFloatProperty(material, "_ShadeColor_Step");
|
|
tFloat["_2nd_ShadeColor_Feather"] = GetFloatProperty(material, "_1st2nd_Shades_Feather");
|
|
}
|
|
|
|
// Emission properties are not fully supported.
|
|
tTexture["_EmissionMap"] = GetTextureProperty(material, "_Emissive_Tex");
|
|
tColor["_EmissionColor"] = GetColorProperty(material, "_Emissive_Color");
|
|
|
|
// HighColor is only supported in Specular mode
|
|
Texture highColorTex = GetTextureProperty(material, "_HighColor_Tex");
|
|
Texture highColorMask = GetTextureProperty(material, "_Set_HighColorMask");
|
|
if (highColorTex)
|
|
{
|
|
tTexture["_SpecGlossMap"] = highColorTex;
|
|
tTexture["_SpecularDetailMask"] = highColorMask;
|
|
} else {
|
|
tTexture["_SpecGlossMap"] = highColorMask;
|
|
};
|
|
|
|
tFloat["_SpecularType"] = (float)SpecularType.Cel * GetFloatProperty(material, "_Is_SpecularToHighColor") ?? 0 ;
|
|
|
|
tColor["_SpecColor"] = new Vector4(1,1,1,0.1f) * GetColorProperty(material, "_HighColor") ?? (Color.white);
|
|
|
|
float? smoothness = GetFloatProperty(material, "_HighColor_Power");
|
|
if (smoothness.HasValue) tFloat["_Smoothness"] = 1.0f - smoothness;
|
|
tFloat["_CelSpecularSoftness"] = GetFloatProperty(material, "_Is_SpecularToHighColor");
|
|
|
|
// Rim lighting works differently here, but there's not much we can do about it.
|
|
tFloat["_UseFresnel"] = (float)AmbientFresnelType.Lit * GetFloatProperty(material, "_RimLight") ?? 0;
|
|
tColor["_FresnelTint"] = GetColorProperty(material, "_RimLightColor");
|
|
tFloat["_FresnelWidth"] = GetFloatProperty(material, "_RimLight_Power") ?? 0 * 10;
|
|
tFloat["_FresnelStrength"] = 1.0f - GetFloatProperty(material, "_RimLight_FeatherOff") ?? 0;
|
|
|
|
tFloat["_UseFresnelLightMask"] = GetFloatProperty(material, "_LightDirection_MaskOn");
|
|
tFloat["_FresnelLightMask"] = 1.0f + GetFloatProperty(material, "_Tweak_LightDirection_MaskLevel") ?? 0;
|
|
//GetFloatProperty(material, "_Add_Antipodean_RimLight");
|
|
tColor["_FresnelTintInv"] = GetColorProperty(material, "_Ap_RimLightColor");
|
|
tFloat["_FresnelWidthInv"] = 10 * GetFloatProperty(material, "_Ap_RimLight_Power") ?? 0;
|
|
tFloat["_FresnelStrengthInv"] = 1.0f - GetFloatProperty(material, "_Ap_RimLight_FeatherOff") ?? 0;
|
|
//GetTextureProperty(material, "_Set_RimLightMask");
|
|
|
|
// Matcap properties are not fully supported
|
|
tFloat["_UseMatcap"] = GetFloatProperty(material, "_MatCap");
|
|
tTexture["_Matcap1"] = GetTextureProperty(material, "_MatCap_Sampler");
|
|
tTexture["_MatcapMask"] = GetTextureProperty(material, "_Set_MatcapMask");
|
|
tColor["_Matcap1Tint"] = GetColorProperty(material, "_MatCapColor");
|
|
// _Is_LightColor_MatCap is not supported.
|
|
tFloat["_Matcap1Blend"] = 1.0f - GetFloatProperty(material, "_Is_BlendAddToMatCap") ?? 0;
|
|
// This seems to be used as a strength setting.
|
|
tFloat["_Matcap1Strength"] = 1.0f - GetFloatProperty(material, "_Tweak_MatcapMaskLevel");
|
|
// _Tweak_MatCapUV, _Rotate_MatCapUV are not yet supported.
|
|
// _Is_NormalMapForMatCap, _NormalMapForMatCap, _BumpScaleMatcap, _Rotate_NormalMapForMatCapUV
|
|
// are not supported.
|
|
|
|
tFloat["_OutlineMode"] = 1.0f;
|
|
if (oldShader.name.Contains("NoOutline"))
|
|
{
|
|
tFloat["_OutlineMode"] = 0.0f;
|
|
}
|
|
tColor["_outline_color"] = GetColorProperty(material, "_Outline_Color");
|
|
tFloat["_outline_width"] = 0.1f * GetFloatProperty(material, "_Outline_Width") ?? 1.0f;
|
|
tFloat["_OutlineZPush"] = GetFloatProperty(material, "_Offset_Z");
|
|
tTexture["_OutlineMask"] = GetTextureProperty(material, "_Outline_Sampler");
|
|
|
|
// Stencil properties
|
|
if (oldShader.name.Contains("StencilMask"))
|
|
{
|
|
//Debug.Log(GetIntProperty(material, "_StencilNo") % 256);
|
|
stencilReference = (int)GetIntProperty(material, "_StencilNo") % 256;
|
|
stencilComparison = (int)CompareFunction.Always;
|
|
stencilOperation = (int)StencilOp.Replace;
|
|
stencilFail = (int)StencilOp.Replace;
|
|
|
|
}
|
|
if (oldShader.name.Contains("StencilOut"))
|
|
{
|
|
//Debug.Log(GetIntProperty(material, "_StencilNo") % 256);
|
|
stencilReference = (int)GetIntProperty(material, "_StencilNo") % 256;
|
|
stencilComparison = (int)CompareFunction.NotEqual;
|
|
stencilOperation = (int)StencilOp.Keep;
|
|
stencilFail = (int)StencilOp.Keep;
|
|
}
|
|
|
|
// Transparency modes
|
|
if (oldShader.name.Contains("Clipping"))
|
|
{
|
|
// Treat Clipping as cutout
|
|
tFloat[BaseStyles.renderingModeName] = (float)RenderingMode.Cutout;
|
|
tFloat[BaseStyles.customRenderingModeName] = (float)CustomRenderingMode.Cutout;
|
|
}
|
|
if (oldShader.name.Contains("TransClipping"))
|
|
{
|
|
// TransClipping mode depends on a depth prepass with cutout
|
|
// This is difficult to support and would have low performance, and more importantly,
|
|
// alpha to coverage can replicate it pretty well, so set to cutout.
|
|
tFloat[BaseStyles.renderingModeName] = (float)RenderingMode.Cutout;
|
|
tFloat[BaseStyles.customRenderingModeName] = (float)CustomRenderingMode.Cutout;
|
|
}
|
|
if (oldShader.name.Contains("Transparent"))
|
|
{
|
|
// Treat Transparent mode as Fade transparency.
|
|
tFloat[BaseStyles.renderingModeName] = (float)RenderingMode.Fade;
|
|
tFloat[BaseStyles.customRenderingModeName] = (float)CustomRenderingMode.Fade;
|
|
}
|
|
|
|
}
|
|
if (oldShader.name.Contains("Reflex Shader 2"))
|
|
{
|
|
// Todo
|
|
}
|
|
}
|
|
|
|
float? outlineMode = tFloat["_OutlineMode"];
|
|
float? specularType = tFloat["_SpecularType"];
|
|
|
|
base.AssignNewShaderToMaterial(material, oldShader, newShader);
|
|
|
|
// Apply old shader properties to the new shader.
|
|
SetVectorProperty(material, "_MainTex_ST", textureScaleOffset);
|
|
SetShaderFeatureActive(material, null, "_CullMode", cullMode);
|
|
|
|
// Assign gathered properties.
|
|
foreach (KeyValuePair<string, Color?> e in tColor) { SetColorProperty(material, e.Key, e.Value); };
|
|
foreach (KeyValuePair<string, float?> e in tFloat) { SetFloatProperty(material, e.Key, e.Value); };
|
|
foreach (KeyValuePair<string, Texture> e in tTexture) { material.SetTexture(e.Key, e.Value); };
|
|
|
|
SetIntProperty(material, "_Stencil", stencilReference);
|
|
SetIntProperty(material, "_StencilComp", stencilComparison);
|
|
SetIntProperty(material, "_StencilOp", stencilOperation);
|
|
SetIntProperty(material, "_StencilFail", stencilFail);
|
|
|
|
if (outlineMode.HasValue) SetupMaterialWithOutlineMode(material, (OutlineMode)outlineMode);
|
|
if (specularType.HasValue) SetupMaterialWithSpecularType(material, (SpecularType)specularType);
|
|
|
|
// Setup the rendering mode based on the old shader.
|
|
if (oldShader == null || !oldShader.name.Contains(LegacyShadersPath))
|
|
{
|
|
SetupMaterialWithRenderingMode(material, (RenderingMode)material.GetFloat(BaseStyles.renderingModeName), CustomRenderingMode.Opaque, -1);
|
|
}
|
|
else
|
|
{
|
|
MaterialChanged(material);
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithAlbedo(Material material, MaterialProperty albedoMap, MaterialProperty albedoAlphaMode)
|
|
{
|
|
switch ((AlbedoAlphaMode)albedoAlphaMode.floatValue)
|
|
{
|
|
case AlbedoAlphaMode.Transparency:
|
|
{
|
|
material.DisableKeyword(CommonStyles.albedoMapAlphaSmoothnessName);
|
|
}
|
|
break;
|
|
|
|
case AlbedoAlphaMode.Smoothness:
|
|
{
|
|
material.EnableKeyword(CommonStyles.albedoMapAlphaSmoothnessName);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithOutlineMode(Material material, OutlineMode outlineMode)
|
|
{
|
|
string[] oldShaderName = material.shader.name.Split('/');
|
|
const string outlineName = " (Outline)"; //
|
|
var currentlyOutline = oldShaderName[oldShaderName.Length - 1].Contains(outlineName);
|
|
switch ((OutlineMode)outlineMode)
|
|
{
|
|
case OutlineMode.None:
|
|
if (currentlyOutline) {
|
|
string[] newShaderName = oldShaderName;
|
|
string newSubShader = oldShaderName[oldShaderName.Length - 1].Replace(outlineName, "");
|
|
newShaderName[oldShaderName.Length - 1] = newSubShader;
|
|
Shader finalShader = Shader.Find(String.Join("/", newShaderName));
|
|
// If we can't find it, pass.
|
|
if (finalShader != null) {
|
|
material.shader = finalShader;
|
|
}
|
|
}
|
|
break;
|
|
case OutlineMode.Tinted:
|
|
case OutlineMode.Colored:
|
|
if (!currentlyOutline) {
|
|
string[] newShaderName = oldShaderName;
|
|
string newSubShader = oldShaderName[oldShaderName.Length - 1] + outlineName;
|
|
newShaderName[oldShaderName.Length - 1] = newSubShader;
|
|
Shader finalShader = Shader.Find(String.Join("/", newShaderName));
|
|
// If we can't find it, pass.
|
|
if (finalShader != null) {
|
|
material.shader = finalShader;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithSpecularType(Material material, SpecularType specularType)
|
|
{
|
|
// Note: _METALLICGLOSSMAP is used to avoid keyword problems with VRchat.
|
|
// It's only a coincidence that the metallic map needs to be present.
|
|
// Note: _SPECGLOSSMAP is used to switch to a version that doesn't sample
|
|
// reflection probes.
|
|
switch ((SpecularType)material.GetFloat("_SpecularType"))
|
|
{
|
|
case SpecularType.Standard:
|
|
material.SetFloat("_SpecularType", 1);
|
|
material.EnableKeyword("_METALLICGLOSSMAP");
|
|
material.DisableKeyword("_SPECGLOSSMAP");
|
|
break;
|
|
case SpecularType.Cloth:
|
|
material.SetFloat("_SpecularType", 2);
|
|
material.EnableKeyword("_METALLICGLOSSMAP");
|
|
material.DisableKeyword("_SPECGLOSSMAP");
|
|
break;
|
|
case SpecularType.Anisotropic:
|
|
material.SetFloat("_SpecularType", 3);
|
|
material.EnableKeyword("_METALLICGLOSSMAP");
|
|
material.DisableKeyword("_SPECGLOSSMAP");
|
|
break;
|
|
case SpecularType.Cel:
|
|
material.SetFloat("_SpecularType", 4);
|
|
material.EnableKeyword("_SPECGLOSSMAP");
|
|
material.DisableKeyword("_METALLICGLOSSMAP");
|
|
break;
|
|
case SpecularType.CelStrand:
|
|
material.SetFloat("_SpecularType", 5);
|
|
material.EnableKeyword("_SPECGLOSSMAP");
|
|
material.DisableKeyword("_METALLICGLOSSMAP");
|
|
break;
|
|
case SpecularType.Disable:
|
|
material.SetFloat("_SpecularType", 0);
|
|
material.DisableKeyword("_METALLICGLOSSMAP");
|
|
material.DisableKeyword("_SPECGLOSSMAP");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithVertexColorType(Material material, VertexColorType vertexColorType)
|
|
{
|
|
switch ((VertexColorType)material.GetFloat("_VertexColorType"))
|
|
{
|
|
case VertexColorType.Color:
|
|
material.SetFloat("_VertexColorType", 0);
|
|
break;
|
|
case VertexColorType.OutlineColor:
|
|
material.SetFloat("_VertexColorType", 1);
|
|
break;
|
|
case VertexColorType.AdditionalData:
|
|
material.SetFloat("_VertexColorType", 2);
|
|
break;
|
|
case VertexColorType.Ignore:
|
|
material.SetFloat("_VertexColorType", 3);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void SetupMaterialWithLightingCalculationType(Material material, LightingCalculationType LightingCalculationType)
|
|
{
|
|
switch ((LightingCalculationType)material.GetFloat("_LightingCalculationType"))
|
|
{
|
|
case LightingCalculationType.Standard:
|
|
material.SetFloat("_LightingCalculationType", 1);
|
|
break;
|
|
case LightingCalculationType.Cubed:
|
|
material.SetFloat("_LightingCalculationType", 2);
|
|
break;
|
|
case LightingCalculationType.Directional:
|
|
material.SetFloat("_LightingCalculationType", 3);
|
|
break;
|
|
case LightingCalculationType.Biased:
|
|
material.SetFloat("_LightingCalculationType", 4);
|
|
break;
|
|
default:
|
|
case LightingCalculationType.Unbiased:
|
|
material.SetFloat("_LightingCalculationType", 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected static void UpgradeVariantCheck(Material material)
|
|
{
|
|
const string oldNoOutlineName = "☓ No Outline";
|
|
string newShaderName = "Silent's Cel Shading/Lightramp";
|
|
const string upgradeNotice =
|
|
"Note: Updated the shader for material {0} to the new format.";
|
|
string[] currentShaderName = material.shader.name.Split('/');
|
|
// If they're the No Outline variant, it'll be in the path
|
|
var currentlyNoOutline = currentShaderName[currentShaderName.Length - 2].Equals(oldNoOutlineName);
|
|
newShaderName = currentlyNoOutline
|
|
? newShaderName
|
|
: newShaderName + " (Outline)";
|
|
// Old shaders start with "Hidden/Silent's Cel Shading Shader/Old/"
|
|
if (currentShaderName[0] == "Hidden" && currentShaderName[2] == "Old")
|
|
{
|
|
// SetupMaterialWithRenderingMode
|
|
Shader finalShader = Shader.Find(newShaderName);
|
|
// If we can't find it, pass.
|
|
if (finalShader != null) {
|
|
material.shader = finalShader;
|
|
Debug.Log(String.Format(upgradeNotice, material.name, material.shader.name, newShaderName));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
} |