Files
CartoonRPG/Assets/StixGames/GrassShader/Editor/GrassEditor.cs
Caleb Sandford deQuincey 02c4b5ab66 Adding in new packages
2025-06-05 22:59:18 +01:00

548 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using StixGames.GrassShader;
using StixGames.NatureCore.Utility;
using StixGames.NatureCore.Utility.Localization;
using UnityEditor;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
// ReSharper disable once CheckNamespace
public class GrassEditor : MaterialEditor
{
// Shader variants
private static readonly string[] grassTypeLabels =
{
"Grass.GrassType.Simple", "Grass.GrassType.OneTex", "Grass.GrassType.TwoTex", "Grass.GrassType.ThreeTex",
"Grass.GrassType.FourTex"
};
private static readonly string[] grassTypeString =
{
"SIMPLE_GRASS", "ONE_GRASS_TYPE", "TWO_GRASS_TYPES", "THREE_GRASS_TYPES", "FOUR_GRASS_TYPES"
};
private static readonly string[] densityModeLabels =
{"Grass.DensityMode.Value", "Grass.DensityMode.Vertex", "Grass.DensityMode.Texture"};
private static readonly string[] lightingModes =
{"GRASS_UNLIT_LIGHTING", "GRASS_UNSHADED_LIGHTING", "GRASS_PBR_INVERTED_LIGHTING", "GRASS_PBR_LIGHTING"};
private static readonly string[] lightingModeLabels =
{
"Grass.LightingMode.Unlit", "Grass.LightingMode.Unshaded",
"Grass.LightingMode.InvertedSpecularPBR", "Grass.LightingMode.DefaultPBR"
};
private static readonly string[] lightingNormalModes =
{
"GRASS_REGULAR_NORMAL_LIGHTING", "GRASS_HYBRID_NORMAL_LIGHTING", "GRASS_SURFACE_NORMAL_LIGHTING",
};
private static readonly string[] lightingNormalLabels =
{
"Grass.LightingNormal.Regular", "Grass.LightingNormal.Hybrid", "Grass.LightingNormal.Surface"
};
// Defaults
private static readonly string[] defaultKeywords =
{"SIMPLE_GRASS", "GRASS_HEIGHT_SMOOTHING", "GRASS_CALC_GLOBAL_WIND", "GRASS_IGNORE_GI_SPECULAR"};
private const int defaultGrassType = 0;
private const int defaultLightingMode = 2;
private const int defaultLightingNormalMode = 0;
public override void OnInspectorGUI()
{
Profiler.BeginSample("GrassEditor.OnInspectorGUI");
LocalizationManager.LoadLocalizedText(
FileAnchor.GetFilePath("GrassShaderDataAnchor", "GrassShaderStrings.json"));
if (!isVisible)
{
return;
}
bool forceUpdate = false;
Material targetMat = target as Material;
string[] originalKeywords = targetMat.shaderKeywords;
//Set default values when the material is newly created
if (originalKeywords.Length == 0)
{
originalKeywords = defaultKeywords;
targetMat.shaderKeywords = defaultKeywords;
EditorUtility.SetDirty(targetMat);
}
//Grass type
int grassType = -1;
for (int i = 0; i < grassTypeLabels.Length; i++)
{
if (originalKeywords.Contains(grassTypeString[i]))
{
grassType = i;
break;
}
}
if (grassType < 0)
{
grassType = defaultGrassType;
forceUpdate = true;
}
//Lighting mode
int lightingMode = -1;
for (int i = 0; i < lightingModeLabels.Length; i++)
{
if (originalKeywords.Contains(lightingModes[i]))
{
lightingMode = i;
break;
}
}
if (lightingMode < 0)
{
lightingMode = defaultLightingMode;
forceUpdate = true;
}
int lightingNormalMode = -1;
for (int i = 0; i < lightingNormalLabels.Length; i++)
{
if (originalKeywords.Contains(lightingNormalModes[i]))
{
lightingNormalMode = i;
break;
}
}
if (lightingNormalMode < 0)
{
lightingNormalMode = defaultLightingNormalMode;
forceUpdate = true;
}
//Density mode
var densityMode = GrassUtility.GetDensityMode(targetMat);
bool deferredMode;
if (Camera.main == null || Camera.main.renderingPath == RenderingPath.UsePlayerSettings)
{
var renderingPath = EditorGraphicsSettings.GetTierSettings(BuildTargetGroup.Standalone, GraphicsTier.Tier3)
.renderingPath;
deferredMode = renderingPath == RenderingPath.DeferredLighting || renderingPath == RenderingPath.DeferredShading;
}
else
{
deferredMode = Camera.main.renderingPath == RenderingPath.DeferredLighting ||
Camera.main.renderingPath == RenderingPath.DeferredShading;
}
//HDRP Warning
var isHdrp = GrassUtility.IsHDRPGrassMaterial(targetMat);
if (isHdrp)
{
GUILayout.Label(new GUIContent("The High Definition Render Pipeline is not yet supported.\n" +
"It will be supported in an upcoming version."));
}
//Force forward mode
if (GrassUtility.IsForwardOnlyGrassMaterial(targetMat))
{
GUILayout.Label(new GUIContent("This version of the shader is equivalent to the regular\n" +
"Grass shader, except that it disables deferred rendering.\n" +
"Use it if you require the additional lighting options.\n" +
"If your grass is affected by many lights, you should consider\n" +
"using the deferred version instead."));
deferredMode = false;
}
bool ignoreGISpecular = originalKeywords.Contains("GRASS_IGNORE_GI_SPECULAR");
bool widthSmoothing = originalKeywords.Contains("GRASS_WIDTH_SMOOTHING");
bool heightSmoothing = originalKeywords.Contains("GRASS_HEIGHT_SMOOTHING");
bool alphaSmoothing = originalKeywords.Contains("GRASS_ALPHA_SMOOTHING");
bool objectMode = originalKeywords.Contains(GrassUtility.GrassObjectModeKeyword);
bool topViewCompensation = originalKeywords.Contains("GRASS_TOP_VIEW_COMPENSATION");
bool surfaceNormal = originalKeywords.Contains(GrassUtility.FollowSurfaceNormalKeyword);
bool useTextureAtlas = originalKeywords.Contains("GRASS_USE_TEXTURE_ATLAS");
bool grassRandomDirection = deferredMode || originalKeywords.Contains("GRASS_RANDOM_DIR");
bool calcGlobalWind = originalKeywords.Contains("GRASS_CALC_GLOBAL_WIND");
//Grass painter
if (Selection.activeObject == null || AssetDatabase.Contains(Selection.activeObject))
{
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.HowToOpenGrassPainter"));
}
else
{
if (GUILayout.Button(LocalizationManager.GetGUIContent("Grass.OpenGrassPainter")))
{
GrassPainterWindow.OpenWindow();
}
}
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
// Shader variants
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.ShaderVariantsHeading"),
EditorStyles.boldLabel);
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.GrassModesHeading"),
EditorStyles.boldLabel);
grassType = EditorGUILayout.Popup(LocalizationManager.GetGUIContent("Grass.GrassType.Label"), grassType,
LocalizationManager.GetGUIContents(grassTypeLabels));
densityMode = (DensityMode) EditorGUILayout.Popup(LocalizationManager.GetGUIContent("Grass.DensityMode.Label"),
(int) densityMode, LocalizationManager.GetGUIContents(densityModeLabels));
using (new EditorGUI.DisabledGroupScope(deferredMode))
{
grassRandomDirection = GUILayout.Toggle(grassRandomDirection,
LocalizationManager.GetGUIContent("Grass.RandomGrass"));
}
EditorGUILayout.Separator();
// Lighting modes
using (new EditorGUI.DisabledGroupScope(deferredMode))
{
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.LightingHeading"),
EditorStyles.boldLabel);
lightingMode = EditorGUILayout.Popup(LocalizationManager.GetGUIContent("Grass.LightingMode.Label"),
lightingMode, LocalizationManager.GetGUIContents(lightingModeLabels));
ignoreGISpecular = GUILayout.Toggle(ignoreGISpecular,
LocalizationManager.GetGUIContent("Grass.IgnoreSpecularGI"));
EditorGUILayout.Separator();
}
lightingNormalMode = EditorGUILayout.Popup(LocalizationManager.GetGUIContent("Grass.LightingNormal.Label"),
lightingNormalMode, LocalizationManager.GetGUIContents(lightingNormalLabels));
EditorGUILayout.Separator();
// Tessellation smoothing
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.LODSmoothingHeading"),
EditorStyles.boldLabel);
widthSmoothing = GUILayout.Toggle(widthSmoothing, LocalizationManager.GetGUIContent("Grass.SmoothWidth"));
heightSmoothing = GUILayout.Toggle(heightSmoothing, LocalizationManager.GetGUIContent("Grass.SmoothHeight"));
using (new EditorGUI.DisabledGroupScope(IsSimpleGrass(grassType)))
{
alphaSmoothing = GUILayout.Toggle(alphaSmoothing, LocalizationManager.GetGUIContent("Grass.SmoothAlpha"));
}
EditorGUILayout.Separator();
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.ObjectWorldSpaceHeading"),
EditorStyles.boldLabel);
if (isHdrp && !objectMode)
{
objectMode = true;
forceUpdate = true;
}
using (new EditorGUI.DisabledGroupScope(isHdrp))
{
objectMode = GUILayout.Toggle(objectMode, LocalizationManager.GetGUIContent("Grass.ObjectSpace"));
}
surfaceNormal = GUILayout.Toggle(surfaceNormal, LocalizationManager.GetGUIContent("Grass.FollowSurfaceNormal"));
EditorGUILayout.Separator();
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.OtherVariantsHeading"),
EditorStyles.boldLabel);
topViewCompensation = GUILayout.Toggle(topViewCompensation,
LocalizationManager.GetGUIContent("Grass.ImproveViewingFromAbove"));
calcGlobalWind = GUILayout.Toggle(calcGlobalWind, LocalizationManager.GetGUIContent("Grass.GlobalWind"));
EditorGUILayout.Separator();
using (new EditorGUI.DisabledGroupScope(grassType == 0))
{
useTextureAtlas =
GUILayout.Toggle(useTextureAtlas, LocalizationManager.GetGUIContent("Grass.TextureAtlas"));
}
EditorGUILayout.Separator();
if (EditorGUI.EndChangeCheck() || forceUpdate)
{
Undo.RecordObject(targetMat, "Changed grass shader keywords");
var keywords = new List<string>();
keywords.Add(grassTypeString[grassType]);
keywords.Add(lightingModes[lightingMode]);
keywords.Add(lightingNormalModes[lightingNormalMode]);
keywords.Add(GrassUtility.DensityModes[(int) densityMode]);
if (ignoreGISpecular)
{
keywords.Add("GRASS_IGNORE_GI_SPECULAR");
}
if (widthSmoothing)
{
keywords.Add("GRASS_WIDTH_SMOOTHING");
}
if (heightSmoothing)
{
keywords.Add("GRASS_HEIGHT_SMOOTHING");
}
if (alphaSmoothing)
{
keywords.Add("GRASS_ALPHA_SMOOTHING");
}
if (objectMode)
{
keywords.Add(GrassUtility.GrassObjectModeKeyword);
}
if (topViewCompensation)
{
keywords.Add("GRASS_TOP_VIEW_COMPENSATION");
}
if (surfaceNormal)
{
keywords.Add(GrassUtility.FollowSurfaceNormalKeyword);
}
if (useTextureAtlas)
{
keywords.Add("GRASS_USE_TEXTURE_ATLAS");
}
if (grassRandomDirection)
{
keywords.Add("GRASS_RANDOM_DIR");
}
if (calcGlobalWind)
{
keywords.Add("GRASS_CALC_GLOBAL_WIND");
}
targetMat.shaderKeywords = keywords.ToArray();
EditorUtility.SetDirty(targetMat);
}
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.ShaderSettingsHeading"),
EditorStyles.boldLabel);
serializedObject.Update();
var theShader = serializedObject.FindProperty("m_Shader");
if (isVisible && !theShader.hasMultipleDifferentValues && theShader.objectReferenceValue != null)
{
EditorGUIUtility.fieldWidth = 64;
EditorGUI.BeginChangeCheck();
int grassLabel = 1;
var properties = GetMaterialProperties(new Object[] {targetMat});
foreach (var property in properties)
{
//Ignore unused grass types
if ((grassType < 2 && property.name.Contains("01")) ||
(grassType < 3 && property.name.Contains("02")) ||
(grassType < 4 && property.name.Contains("03")))
{
DisableFollowingProperties();
}
// =========== Labels ==================
if (property.name == "_TargetDensity")
{
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.PerformanceHeading"),
EditorStyles.boldLabel);
}
if (property.name == "_Disorder")
{
EditorGUILayout.Space();
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.VisualsHeading"),
EditorStyles.boldLabel);
}
if (property.name == "_ColorMap")
{
EditorGUILayout.Space();
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.BaseTexturesHeading"),
EditorStyles.boldLabel);
}
if (property.name == "_WindParams")
{
EditorGUILayout.Space();
EditorGUILayout.LabelField(LocalizationManager.GetGUIContent("Grass.WindSettingsHeading"),
EditorStyles.boldLabel);
}
//Grass type label
if (property.name.Contains("_GrassTex"))
{
EditorGUILayout.Space();
var localizedText =
LocalizationManager.GetLocalizedValue("Grass.GrassTypeNrHeading.Text", "Grass Type Nr. {0}");
var localizedTooltip = LocalizationManager.GetLocalizedValue("Grass.GrassTypeNrHeading.Tooltip",
LocalizationManager.MissingTooltipMessage);
EditorGUILayout.LabelField(
new GUIContent(string.Format(localizedText, grassLabel), localizedTooltip),
EditorStyles.boldLabel);
grassLabel++;
}
// ============ Non standard settings =============
if (property.name == "_CullMode")
{
//Cull Mode is only set by the editor, don't show it in the inspector
property.floatValue = grassRandomDirection ? 2 : 0;
continue;
}
//Hide texture atlas settings if not active
if (property.name.Contains("_TextureAtlas"))
{
using (new EditorGUI.DisabledScope(!useTextureAtlas))
{
property.floatValue =
Math.Max(EditorGUILayout.IntField(GetGUIContent(property), (int) property.floatValue), 1);
}
continue;
}
//Wind should only be active when activated
if (property.name.StartsWith("_Wind"))
{
using (new EditorGUI.DisabledScope(!calcGlobalWind))
{
ShaderProperty(property, GetGUIContent(property));
}
continue;
}
// ============ Standard settings =============
//Density mode
if (property.name == "_DensityValues" || property.name == "_DensityTexture")
{
//Vertex density
if (densityMode == DensityMode.Vertex)
{
DisableSingleProperty();
}
//Texture density
if (densityMode == DensityMode.Texture && property.name == "_DensityValues")
{
DisableSingleProperty();
}
//Density value
if (densityMode == DensityMode.Value && property.name == "_DensityTexture")
{
DisableSingleProperty();
}
}
//In simple grass, ignore grass texture
if (IsSimpleGrass(grassType) && (property.name.Contains("_GrassTex") || property.name.StartsWith("_AtlasOffset")))
{
DisableSingleProperty();
}
//For billboard grass (not randomized direction grass) the subsurface scattering setting is not in use (yet?)
if (!grassRandomDirection && property.name.Contains("Subsurface"))
{
DisableSingleProperty();
}
ShaderProperty(property, GetGUIContent(property));
EnableSingleProperty();
}
EnableFollowingProperties();
if (EditorGUI.EndChangeCheck())
{
PropertiesChanged();
}
}
Profiler.EndSample();
}
private bool disableSingle = false;
private bool disableFollowing = false;
private void DisableSingleProperty()
{
if (disableSingle || disableFollowing)
{
return;
}
disableSingle = true;
EditorGUI.BeginDisabledGroup(true);
}
private void DisableFollowingProperties()
{
if (disableFollowing)
{
return;
}
if (!disableSingle)
{
EditorGUI.BeginDisabledGroup(true);
}
disableSingle = false;
disableFollowing = true;
}
private void EnableSingleProperty()
{
if (disableSingle)
{
disableSingle = false;
EditorGUI.EndDisabledGroup();
}
}
private void EnableFollowingProperties()
{
if (disableFollowing)
{
disableFollowing = false;
EditorGUI.EndDisabledGroup();
}
}
private static GUIContent GetGUIContent(MaterialProperty property)
{
return LocalizationManager.GetGUIContent(string.Format("Grass.{0}", property.name), property.displayName,
"No tooltip found.");
}
private static bool IsSimpleGrass(int grassType)
{
return grassType == 0;
}
}