Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 118 additions & 9 deletions Editor/ShaderGraphEditor/OpenGraphGUIEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,18 @@ public class OpenGraphGUIEditor : ShaderGUI
/// Amount of tab spacing for single line texture property.
/// </summary>
const float singleLineTexTabSpace = 2f;
/// <summary>
/// Amount of spacing above label properties.
/// </summary>
const float labelTopSpace = 4f;

const string centeredSpacingName = "[centered]";
const string rightBoundSpacingName = "[rightbound]";
const string maxFieldSpacingName = "[maxfield]";
const string minFieldSpacingName = "[minfield]";

const string labelPrefix = "*";
const string foldoutPrefix = "#";
const string singleLineTexPrefix = "%";
const string dependentVisibleTextPrefix = "^";
const string linkedPropertyPrefix = "&";
Expand All @@ -83,11 +88,26 @@ class LinkedProperty
private bool fieldCenteredMode = false;
private bool fieldExpandedMode = false;

private bool hadOneFoldout = false;
private bool currentlyInFoldout = false;
private int currentFoldoutIndex = 0;
private bool bottomOptionsFoldout = true;

/// <summary>
/// Bool list for each foldout encountered. Supports up to 128 foldouts.
/// </summary>
private bool[] foldoutArray = new bool[128];

protected Dictionary<string, System.Action<MaterialEditor, MaterialProperty>> renderExtensions = null;

public OpenGraphGUIEditor()
{
renderExtensions = null;
for(int i = 0; i < foldoutArray.Length; i++)
{
//Initialize foldouts to show by default
foldoutArray[i] = true;
}
}

//BASE GUI STRUCTURE
Expand All @@ -104,6 +124,8 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro

fieldCenteredMode = false;
fieldExpandedMode = false;
hadOneFoldout = false;
currentlyInFoldout = false;
SetUtilityLabelWidth();

RenderPropertiesList(properties);
Expand All @@ -120,6 +142,9 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro
/// <param name="properties"></param>
void RenderPropertiesList(MaterialProperty[] properties)
{
//Track count of foldouts encountered
int foldoutCount = 0;

//Track if the last property was non-texture type or
//contained a non-null input texture
bool lastWasPopulated = true;
Expand Down Expand Up @@ -147,8 +172,17 @@ void RenderPropertiesList(MaterialProperty[] properties)

currentLinkedProperties.Add(thisProp.displayName, link);
}
else if (thisProp.displayName.StartsWith(foldoutPrefix))
{
//This is a foldout property

foldoutCount++;
}
}

//Reset current foldout to 0
currentFoldoutIndex = 0;

//Now iterate across the properties for real and render them
for (int i = 0; i < properties.Length; i++)
{
Expand Down Expand Up @@ -192,7 +226,7 @@ void RenderPropertiesList(MaterialProperty[] properties)
//Use min field width and don't render this property
SetFieldExpandedMode(false);
}
else if(currentLinkedProperties.ContainsKey(propName))
else if(currentLinkedProperties.ContainsKey(propName) && DoRenderProp())
{
//This is a linked property, so check if it was rendered already
var thisLinkedProp = currentLinkedProperties[propName];
Expand All @@ -210,7 +244,51 @@ void RenderPropertiesList(MaterialProperty[] properties)
RenderVisibleProperty(thisLinkedProp.matProperty, propName, i);
}
}
else if(propName.StartsWith(labelPrefix))
else if (propName.StartsWith(foldoutPrefix))
{
//This is a foldout type, so create a new group

//Trim the foldout prefix
propName = propName.Substring(foldoutPrefix.Length);
if(propName.Trim().Length > 0)
{
//There is a foldout name to use

if(currentlyInFoldout)
{
//Stop the previous foldout
EditorGUILayout.EndFoldoutHeaderGroup();
}

//Update the current foldout index to the new value before setting it
currentFoldoutIndex++;
//This is done first so that later on, DoRenderProp() can tell if the last foldout is unfolded,
//While still allowing this value to change when it encountered a new foldout.

//This actually means the first item (0) will be skipped
//But that's okay because it is never referenced.

//Render the foldout
foldoutArray[currentFoldoutIndex] = EditorGUILayout.BeginFoldoutHeaderGroup(foldoutArray[currentFoldoutIndex], propName);

//Finally, track that we encountered at least one foldout
hadOneFoldout = true;
//And tell the next properties that we are in a foldout
currentlyInFoldout = true;

}
else
{
//End the last foldout if there is one
if(currentlyInFoldout)
{
EditorGUILayout.EndFoldoutHeaderGroup();
currentlyInFoldout = false;
}
}

}
else if(propName.StartsWith(labelPrefix) && DoRenderProp())
{
//This is a label type, so show a bold header instead of the property

Expand All @@ -219,7 +297,7 @@ void RenderPropertiesList(MaterialProperty[] properties)

RenderLabelProperty(propName);
}
else if (propName.StartsWith(dependentVisibleTextPrefix))
else if (propName.StartsWith(dependentVisibleTextPrefix) && DoRenderProp())
{
//It is dependent, so we will conditionally render it

Expand All @@ -235,7 +313,7 @@ void RenderPropertiesList(MaterialProperty[] properties)
//Don't render this property
}
}
else
else if (DoRenderProp())
{
//It's not dependent, so update populated state based on this
if (thisProp.type == MaterialProperty.PropType.Texture)
Expand All @@ -260,11 +338,27 @@ void RenderPropertiesList(MaterialProperty[] properties)
/// </summary>
void RenderBottomOptions()
{
matEditor.RenderQueueField();
//If we had one foldout earlier, draw this as it's own foldout group
if(hadOneFoldout)
{
if(currentlyInFoldout)
{
EditorGUILayout.EndFoldoutHeaderGroup();
}
bottomOptionsFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(bottomOptionsFoldout, "Advanced");
}

//If we don't use the group OR we do & it's unfolded, show the options
if(!hadOneFoldout || bottomOptionsFoldout)
{
matEditor.RenderQueueField();

matEditor.EnableInstancingField();
matEditor.DoubleSidedGIField();
matEditor.EmissionEnabledProperty();
matEditor.EnableInstancingField();
matEditor.DoubleSidedGIField();
matEditor.EmissionEnabledProperty();
//Lightmap Emission may be a built-in only concept(?)
//matEditor.LightmapEmissionProperty();
}
}

//PROPERTY RENDERING
Expand All @@ -279,6 +373,7 @@ void RenderBottomOptions()
/// <param name="index"></param>
void RenderDependentVisibleProperty(MaterialProperty v, string labelName, int index)
{

//Shift over by a small amount to show the dependency
EditorGUILayout.BeginHorizontal();

Expand Down Expand Up @@ -309,7 +404,7 @@ void RenderDependentVisibleProperty(MaterialProperty v, string labelName, int in
void RenderVisibleProperty(MaterialProperty v, string labelName, int index)
{

if(labelName.StartsWith(singleLineTexPrefix))
if (labelName.StartsWith(singleLineTexPrefix))
{
if(v.type == MaterialProperty.PropType.Texture)
{
Expand Down Expand Up @@ -360,6 +455,7 @@ void RenderVisibleProperty(MaterialProperty v, string labelName, int index)
/// <param name="v"></param>
void RenderDefaultPropertyView(MaterialProperty v, string customName = "")
{

string finalName = (customName == "") ? v.displayName : customName;

switch(v.type)
Expand Down Expand Up @@ -394,9 +490,22 @@ void RenderDefaultPropertyView(MaterialProperty v, string customName = "")
/// <param name="propName"></param>
void RenderLabelProperty(string propName)
{
EditorGUILayout.Space(labelTopSpace);
EditorGUILayout.LabelField(propName, EditorStyles.boldLabel);
}

//QUERY

/// <summary>
/// Check if we should render the current prop
/// based on foldout status.
/// </summary>
/// <returns></returns>
bool DoRenderProp()
{
return (!currentlyInFoldout || foldoutArray[currentFoldoutIndex]);
}

//EDITOR GUI

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The default Inspector view for ShaderGraph-based materials can be somewhat bland

## Why use OpenGraphGUI?

**OpenGraphGUI** lets you customize the appearance of your material properties right from ShaderGraph. Simply prefix your property names in the Shader's Blackboard with certain special characters, and any material using that Shader will display the custom GUI.
**OpenGraphGUI** lets you customize the appearance of your material properties right from ShaderGraph. Simply prefix your property names in the Shader's Blackboard with certain special characters, and any material using that Shader will display the custom GUI. This is a lightweight and easy to use script that provides more control over the design of your Shaders.

<img width = "700" src="Documentation~/DocAssets/AllTagsScreen.jpg">

Expand Down Expand Up @@ -37,6 +37,10 @@ Use a property called **\[Centered\]** to adjust the spacing of the Inspector fi

<img width = "500" src="Documentation~/DocAssets/FieldWidthScreenshot.jpg">

**New!** Use the **hashtag symbol (#)** as a prefix for one of your properties and you will create a Foldout Group with your property name as the title. Create up to 128 unique foldout groups by creating new foldout properties in sequence without having to tag the end of each group. If you do wish to close the previous Foldout Group, simply create a property that consists of only a **hashtag symbol (#)** without any name. The following properties will exist outside of the last group.

<img width = "550" src="Documentation~/DocAssets/FoldoutGroupsScreenshot.jpg">

### Property Rendering Features

Prefix a texture property with the **percent symbol (%)** and it will show as a single line texture property instead of the big thumbnail version. Single line textures are commonly used in the built-in materials and offer a cleaner look that takes up less space in your Inspector.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class RPOpenGraphGUIExtension : RPOpenGraphGUI
/// There is one property which we can override to add our extension.
/// This is done from within the constructor to improve performance.
/// </summary>
public RPOpenGraphGUIExtension()
public RPOpenGraphGUIExtension() : base()
{
//First initialize the property
renderExtensions = new Dictionary<string, System.Action<MaterialEditor, MaterialProperty>>();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.robproductions.opengraphgui",
"version": "1.1.0",
"version": "1.2.0",
"displayName": "Open Graph GUI",
"description": "An open-source generic Shader GUI for use with URP ShaderGraphs. This package aims to help developers clean up the look of their Material properties while maintaining the built-in style.",
"unity": "2020.3",
Expand Down