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 props = new Dictionary(); 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 tColor = new Dictionary(); Dictionary tFloat = new Dictionary(); Dictionary tTexture = new Dictionary(); // 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 e in tColor) { SetColorProperty(material, e.Key, e.Value); }; foreach (KeyValuePair e in tFloat) { SetFloatProperty(material, e.Key, e.Value); }; foreach (KeyValuePair 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)); } } } } }