Skip to content

Commit 196aa30

Browse files
KarlBKentKarl Kent
andauthored
Xp vfx user keywords (#46)
* User Keywords initial work * Update ShaderInputPropertyDrawer.cs Prevent shadergraph from adding nodes if limit is exceeded, so it doesnt serialize and cause UI Issues. * Update ShaderGraphImporter.cs Bring the Importer versioning up to latest Co-authored-by: Karl Kent <karl.kent@gmail.com>
1 parent 59e5a2b commit 196aa30

File tree

11 files changed

+519
-19
lines changed

11 files changed

+519
-19
lines changed

com.unity.shadergraph/Editor/Drawing/Inspector/PropertyDrawers/ShaderInputPropertyDrawer.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,12 @@ void KeywordAddEntry(ReorderableList list)
12341234
if(!(shaderInput is ShaderKeyword keyword))
12351235
return;
12361236

1237+
if (graphData.GetKeywordPermutationCount() > ShaderGraphPreferences.variantLimit)
1238+
{
1239+
Debug.LogError($"Error in Shader Graph: {ShaderKeyword.kVariantLimitWarning}");
1240+
return;
1241+
}
1242+
12371243
this._preChangeValueCallback("Add Keyword Entry");
12381244

12391245
int index = GetFirstUnusedID();

com.unity.shadergraph/Editor/Generation/GraphCode.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ public struct GraphCode
88
public string code { get; internal set; }
99
public ShaderGraphRequirements requirements { get; internal set; }
1010
public IEnumerable<AbstractShaderProperty> properties;
11+
public IEnumerable<ShaderInput> keywords;
1112
}
1213
}

com.unity.shadergraph/Editor/Generation/ShaderGraphVfxAsset.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public sealed class ShaderGraphVfxAsset : ScriptableObject, ISerializationCallba
3232
private class ShaderGraphVfxAssetData : JsonObject
3333
{
3434
public List<JsonData<AbstractShaderProperty>> m_Properties = new List<JsonData<AbstractShaderProperty>>();
35+
public List<JsonData<ShaderKeyword>> m_Keywords = new List<JsonData<ShaderKeyword>>();
3536
}
3637

3738
public const int BaseColorSlotId = 1;
@@ -135,6 +136,14 @@ public List<AbstractShaderProperty> properties
135136
return m_Data.m_Properties.SelectValue().ToList();
136137
}
137138
}
139+
internal List<ShaderKeyword> Keywords
140+
{
141+
get
142+
{
143+
EnsureKeywords();
144+
return m_Data.m_Keywords.SelectValue().ToList();
145+
}
146+
}
138147

139148
internal void SetProperties(List<AbstractShaderProperty> propertiesList)
140149
{
@@ -148,6 +157,16 @@ internal void SetProperties(List<AbstractShaderProperty> propertiesList)
148157
m_SerializedVfxAssetData = new SerializationHelper.JSONSerializedElement() { JSONnodeData = json };
149158
m_Data = null;
150159
}
160+
internal void SetKeywords(List<ShaderKeyword> keywordList)
161+
{
162+
m_Data.m_Keywords.Clear();
163+
foreach(var keyword in keywordList)
164+
{
165+
m_Data.m_Keywords.Add(keyword);
166+
}
167+
var json = MultiJson.Serialize(m_Data);
168+
m_SerializedVfxAssetData = new SerializationHelper.JSONSerializedElement() { JSONnodeData = json };
169+
}
151170

152171
void EnsureProperties()
153172
{
@@ -163,6 +182,15 @@ void EnsureProperties()
163182
}
164183
}
165184

185+
void EnsureKeywords()
186+
{
187+
if((m_Data == null || m_Data.m_Keywords == null) && !String.IsNullOrEmpty(m_SerializedVfxAssetData.JSONnodeData))
188+
{
189+
m_Data = new ShaderGraphVfxAssetData();
190+
MultiJson.Deserialize(m_Data , m_SerializedVfxAssetData.JSONnodeData);
191+
}
192+
}
193+
166194
void ISerializationCallbackReceiver.OnAfterDeserialize()
167195
{
168196
m_Data = null;
@@ -201,7 +229,7 @@ public GraphCode GetCode(OutputMetadata[] outputs)
201229
Array.Sort(propertyIndices);
202230
var filteredProperties = propertyIndices.Select(i => properties[i]).ToArray();
203231
graphCode.properties = filteredProperties;
204-
232+
205233
return graphCode;
206234
}
207235
}

com.unity.shadergraph/Editor/Importers/ShaderGraphImporter.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ namespace UnityEditor.ShaderGraph
3333
// + 1 Bump ShaderImporter version after bugfix to DotsDeformation.hlsl::FetchComputeVertexData() to tangentOS.w in tangentOS output so mirrored normals produce correct normal maps.
3434
// + 1 Bump ShaderImporter version after change to support dynamic GI extraction pass
3535
// + 1 Bump ShaderImporter version after bugfixes to dynamic GI extraction pass
36+
// + 1 Bump ShaderImporter version after VFXGraph Keyword Support Added.
3637
// [ScriptedImporter(115, Extension, -902)]
37-
[ScriptedImporter(122, Extension, -902)]
38+
[ScriptedImporter(123, Extension, -902)]
3839
#else
3940
// [ScriptedImporter(47, Extension, -902)]
40-
[ScriptedImporter(54, Extension, -902)]
41+
[ScriptedImporter(55, Extension, -902)]
4142
// custom-end
4243
#endif
4344

@@ -655,7 +656,17 @@ void AddCoordinateSpaceSnippets(InterpolatorType interpolatorType, Func<ShaderGr
655656
sharedCodeIndices.Add(codeSnippets.Count);
656657
codeSnippets.Add($"{outputStructName} {evaluationFunctionName}({nl}{indent}{inputStructName} IN");
657658

659+
var keywords = new List<ShaderKeyword>();
660+
foreach ( var keyword in graph.keywords)
661+
{
662+
if (keyword.isExposable && !keyword.isBuiltIn)
663+
{
664+
keywords.Add(keyword);
665+
}
666+
}
667+
658668
var inputProperties = new List<AbstractShaderProperty>();
669+
659670
var portPropertyIndices = new List<int>[ports.Count];
660671
for (var portIndex = 0; portIndex < ports.Count; portIndex++)
661672
{
@@ -757,6 +768,7 @@ void AddCoordinateSpaceSnippets(InterpolatorType interpolatorType, Func<ShaderGr
757768
asset.outputStructName = outputStructName;
758769
asset.portRequirements = portRequirements;
759770
asset.concretePrecision = graph.concretePrecision;
771+
asset.SetKeywords(keywords);
760772
asset.SetProperties(inputProperties);
761773
asset.outputPropertyIndices = new IntArray[ports.Count];
762774
for (var portIndex = 0; portIndex < ports.Count; portIndex++)

com.unity.visualeffectgraph/Editor/Core/VFXSerializer.cs

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,11 @@ public static string Save(object obj)
323323
}
324324
return JsonUtility.ToJson(gw);
325325
}
326+
else if (obj is VFXUserKeyword)
327+
{
328+
VFXUserKeyword keyword = obj as VFXUserKeyword;
329+
return JsonUtility.ToJson(keyword);
330+
}
326331
else if (obj is string)
327332
{
328333
return "\"" + ((string)obj).Replace("\"", "\\\"") + "\"";
@@ -334,18 +339,23 @@ public static string Save(object obj)
334339
else if (obj.GetType().IsArrayOrList())
335340
{
336341
IList list = (IList)obj;
337-
338-
System.Text.StringBuilder sb = new System.Text.StringBuilder();
339-
sb.Append('[');
340-
for (int i = 0; i < list.Count; ++i)
342+
if (list.Count > 0)
341343
{
342-
sb.Append(Save(list[i]));
343-
sb.Append(',');
344+
System.Text.StringBuilder sb = new System.Text.StringBuilder();
345+
sb.Append('[');
346+
for (int i = 0; i < list.Count; ++i)
347+
{
348+
sb.Append(Save(list[i]));
349+
sb.Append(',');
350+
}
351+
352+
sb.Length = sb.Length - 1;
353+
sb.Append(']');
354+
355+
return sb.ToString();
344356
}
345-
sb.Length = sb.Length - 1;
346-
sb.Append(']');
347357

348-
return sb.ToString();
358+
return "[]";
349359
}
350360
else
351361
{
@@ -472,6 +482,23 @@ public static object Load(System.Type type, string text, object oldValue)
472482
var obj = new SerializableType(text.Substring(1, text.Length - 2));
473483
return obj;
474484
}
485+
else if (type.IsAssignableFrom(typeof(List<VFXUserKeyword>)))
486+
{
487+
List<string> TopLevelObjectsElements = ParseTopLevelObjectsFromJsonObjectArrayString(text);
488+
489+
List<VFXUserKeyword> ObjectElements = new List<VFXUserKeyword>();
490+
491+
foreach (var topLevelObject in TopLevelObjectsElements)
492+
{
493+
var element = JsonUtility.FromJson<VFXUserKeyword>(topLevelObject);
494+
if (element != null)
495+
{
496+
ObjectElements.Add((element));
497+
}
498+
}
499+
500+
return ObjectElements;
501+
}
475502
else if (type.IsArrayOrList())
476503
{
477504
List<string> elements = ParseArray(text);
@@ -596,8 +623,58 @@ internal static List<string> ParseArray(string arrayText)
596623
}
597624
error:
598625
Debug.LogError("Couln't parse array" + arrayText + " from " + cur);
599-
600626
return null;
601627
}
628+
/*
629+
* Used to parse top-level objects form a JSON string, returning the JSON specific to that object in each element.
630+
*/
631+
internal static List<string> ParseTopLevelObjectsFromJsonObjectArrayString(string arrayText)
632+
{
633+
List<string> elements = new List<string>();
634+
635+
int cur = 0;
636+
637+
bool ignoreNext = false;
638+
int depth = 0;
639+
bool isInString = false;
640+
int prevElementStart = 0;
641+
642+
foreach (char c in arrayText)
643+
{
644+
switch (c)
645+
{
646+
case '{':
647+
if (!isInString)
648+
prevElementStart = cur;
649+
depth++;
650+
break;
651+
case '}':
652+
if (!isInString)
653+
depth--;
654+
if (depth == 0)
655+
{
656+
elements.Add(arrayText.Substring(prevElementStart, cur - prevElementStart + 1));
657+
}
658+
break;
659+
case '"':
660+
if (!isInString)
661+
isInString = true;
662+
else if (!ignoreNext)
663+
isInString = false;
664+
break;
665+
case '\\':
666+
if (isInString)
667+
{
668+
ignoreNext = !ignoreNext;
669+
}
670+
break;
671+
default:
672+
ignoreNext = false;
673+
break;
674+
}
675+
++cur;
676+
}
677+
return elements;
678+
}
602679
}
603680
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using EnumField = UnityEditor.VFX.UIElements.VFXEnumField;
4+
using ShaderKeyword = UnityEditor.ShaderGraph.ShaderKeyword;
5+
using System.Linq;
6+
using UnityEditor.ShaderGraph;
7+
using UnityEngine;
8+
using UnityEngine.Serialization;
9+
10+
11+
namespace UnityEditor.VFX
12+
{
13+
[Serializable]
14+
internal class VFXUserKeyword
15+
{
16+
public string KeywordLabel = string.Empty;
17+
public string[] KeywordEntries = new string[]{};
18+
public int SelectedIndex = 0;
19+
public string SelectedEntry = string.Empty;
20+
21+
public VFXUserKeyword(ShaderKeyword keyword)
22+
{
23+
KeywordLabel = keyword.displayName;
24+
SetShaderKeywordEntries(keyword);
25+
SetIndexOfEntry();
26+
}
27+
28+
public bool hasEqualEntries(ShaderKeyword shaderKeyword)
29+
{
30+
if (shaderKeyword.keywordType == KeywordType.Enum)
31+
{
32+
if (shaderKeyword.entries.Count != KeywordEntries.Length) return false;
33+
34+
for (int i = 0; i < shaderKeyword.entries.Count; i++)
35+
{
36+
if (shaderKeyword.entries[i].displayName != KeywordEntries[i]) return false;
37+
}
38+
}
39+
return true;
40+
}
41+
42+
public void SetIndexOfEntry()
43+
{
44+
if (string.IsNullOrEmpty(SelectedEntry) && KeywordEntries.Length > 0)
45+
{
46+
SelectedIndex = 0;
47+
SelectedEntry = KeywordEntries[SelectedIndex];
48+
}
49+
50+
if (KeywordEntries.Length > 0)
51+
{
52+
int idx = Array.IndexOf(KeywordEntries, SelectedEntry); //entry may have moved order, removed, or renamed
53+
SelectedIndex = Math.Max(0, idx);
54+
SelectedEntry = KeywordEntries[SelectedIndex];
55+
}
56+
}
57+
58+
public VFXUserKeyword(){}
59+
public void SetShaderKeywordEntries(ShaderKeyword keyword)
60+
{
61+
if (keyword.keywordScope == KeywordScope.Local)
62+
{
63+
switch (keyword.keywordType)
64+
{
65+
case KeywordType.Enum:
66+
{
67+
KeywordEntries = keyword.entries.Select(obj => obj.displayName).Distinct().ToArray();
68+
break;
69+
}
70+
case KeywordType.Boolean:
71+
{
72+
KeywordEntries = new []{ keyword.displayName +"_OFF",keyword.displayName + "_ON"};
73+
break;
74+
}
75+
}
76+
}
77+
}
78+
79+
public void FindSelectedEntryIndex(ShaderKeyword keyword)
80+
{
81+
int index = SelectedIndex > keyword.entries.Count ? keyword.value : SelectedIndex;;
82+
if (KeywordEntries.Length > 0)
83+
{
84+
if (!string.IsNullOrEmpty(SelectedEntry))
85+
{
86+
int idx = Array.FindIndex(KeywordEntries, x => x.Equals(SelectedEntry));
87+
if (idx > 0)
88+
{
89+
index = idx;
90+
}
91+
}
92+
}
93+
94+
SelectedIndex = index;
95+
SelectedEntry = KeywordEntries[SelectedIndex];
96+
}
97+
98+
public void SetSelectedEntryIndex(int selectedIndex)
99+
{
100+
if( selectedIndex < KeywordEntries.Length && selectedIndex >= 0)
101+
{
102+
// SelectedEntry = KeywordEntries[SelectedIndex];
103+
SelectedIndex = selectedIndex;
104+
}
105+
else
106+
{
107+
// SelectedEntry = KeywordEntries[0];
108+
SelectedIndex = 0;
109+
}
110+
111+
}
112+
113+
}
114+
}

com.unity.visualeffectgraph/Editor/GraphView/VFXUserKeyword.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

com.unity.visualeffectgraph/Editor/GraphView/Views/Properties/PropertyRM.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ public virtual float effectiveLabelWidth
364364
{typeof(Gradient), typeof(GradientPropertyRM)},
365365
{typeof(AnimationCurve), typeof(CurvePropertyRM)},
366366
{typeof(Object), typeof(ObjectPropertyRM)},
367-
{typeof(string), typeof(StringPropertyRM)}
367+
{typeof(string), typeof(StringPropertyRM)},
368+
{typeof(List<VFXUserKeyword>), typeof(UserShaderKeywordPropertyRM)}
368369
};
369370

370371
static Type GetPropertyType(IPropertyRMProvider controller)

0 commit comments

Comments
 (0)