Skip to content

Commit c05c690

Browse files
ludovic-theobaldGitHub Enterprise
authored andcommitted
[VFX][Fix] Bounds helper feature polish (#263)
* Fix Error refresh not happening: set parent-child relation on data when pasting * Use VFXEnumField for unified appearance of enums * Added null check (silent but throw exception when debugging) * Changes cull mode when system is Automatic * Display warning when switching to Auto * Set Bounds Mode of templates to Recorded + Pre-recorded bounds * missing template * ComputedBounds are always in local space * Padding does not get accumulated * fix tooltip + changelog * More correct way of setting the graph as parent to the data The previous fix made targetData become a child of the VFXGraph, whereas currently it is an assymetrical relationship between VFXData and VFXGraph * Fix NullRefException when deleting VFX asset when attached * remove unnecessary null check * Add note about Automatic systems and culling flag * Avoids having bounds converted to infinity * Restore grey out when Automatic First() so it enters the catch statement if "bounds" doesn't exist * != operator failed, causing infinite recompile * fix effect after merge * Fix wrong old way of changing setting value * Attributes --> VFXAttributes * Remove try/catch + HasLink()
1 parent a6e9711 commit c05c690

File tree

24 files changed

+1161
-157
lines changed

24 files changed

+1161
-157
lines changed

com.unity.render-pipelines.high-definition/Editor/VFXGraph/Outputs/VFXLitMeshOutput.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ protected override void GenerateErrors(VFXInvalidateErrorReporter manager)
130130
{
131131
base.GenerateErrors(manager);
132132
var dataParticle = GetData() as VFXDataParticle;
133-
if (dataParticle != null && dataParticle.boundsSettingMode != BoundsSettingMode.Manual)
133+
if (dataParticle != null && dataParticle.boundsMode != BoundsSettingMode.Manual)
134134
manager.RegisterError("WarningBoundsComputation", VFXErrorType.Warning, $"Bounds computation have no sense of what the scale of the output mesh is," +
135135
$" so the resulted computed bounds can be too small or big" +
136136
$" Please use padding to mitigate this discrepancy.");

com.unity.visualeffectgraph/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
124124
- Fix culling of point output [Case 1225764](https://issuetracker.unity3d.com/product/unity/issues/guid/1225764/)
125125
- Compilation issue when normal is used in shadergraph for opacity with unlit output
126126
- Fix Exception on trying to invert a degenerate TRS matrix [Case 1307068](https://issuetracker.unity3d.com/product/unity/issues/guid/1307068/)
127+
- Fix bounds helper tool (automatic systems culling, world bounds computation, ...)
127128
- Fix IsFrontFace shader graph node for VFX.
128129
- Fix crash when loading SDF Baker settings holding a mesh prefab [Case 1343898](https://issuetracker.unity3d.com/product/unity/issues/guid/1343898/)
129130
- Exception using gizmo on exposed properties [Case 1340818](https://issuetracker.unity3d.com/product/unity/issues/guid/1340818/)

com.unity.visualeffectgraph/Documentation~/visual-effect-bounds.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Each System in a visual effect defines its bounds in the [Initialize Context](Co
88

99
- **Manual**: You set the bounds directly in the Initialize Context. You can calculate the bounds dynamically using Operators and send the output to the Initialize Context's **Bounds** input ports.
1010
- **Recorded**: Allows you to record the System from the Target visual effect GameObject panel. For information on how to do this, see [Bounds Recording](#bounds-recording). In this mode, you can also calculate the bounds using Operators and pass them to the Initialize Context, like in **Manual**. This overrides any recorded bounds.
11-
- **Automatic**: Unity calculates the bounds automatically.
11+
- **Automatic**: Unity calculates the bounds automatically. Note: This will force the culling flags of the VFX asset to "Always recompute bounds and simulate".
1212

1313
The Initialize Context also contains a **Bounds Padding** input port. This is a Vector3 that enlarges the per-axis bounds of the System. If a System uses **Recorded** or **Automatic** bounds, Unity calculates the bounds of the System during the Update Context. This means that any changes to the size, position, scale, or pivot of particles that occur in the Output Context don't affect the bounds during that frame. Adding padding to the bounds helps to mitigate this effect.
1414

com.unity.visualeffectgraph/Editor/Compiler/VFXGraphCompiledData.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class VFXDependentBuffersData
4343
class VFXGraphCompiledData
4444
{
4545
// 3: Serialize material
46-
public const uint compiledVersion = 3;
46+
// 4: Bounds helper change
47+
public const uint compiledVersion = 4;
4748

4849
public VFXGraphCompiledData(VFXGraph graph)
4950
{

com.unity.visualeffectgraph/Editor/Data/VFXDataParticle.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,11 @@ internal enum DataType
223223

224224
public bool NeedsComputeBounds() => needsComputeBounds;
225225

226+
[FormerlySerializedAs("boundsSettingMode")]
226227
[VFXSetting(VFXSettingAttribute.VisibleFlags.All),
227228
Tooltip("Specifies how the bounds are set. They can be set manually, recorded in the Target GameObject window, or computed automatically at a small performance cost."),
228229
SerializeField]
229-
public BoundsSettingMode boundsSettingMode = BoundsSettingMode.Recorded;
230+
public BoundsSettingMode boundsMode = BoundsSettingMode.Recorded;
230231

231232
public bool hasStrip { get { return dataType == DataType.ParticleStrip; } }
232233

@@ -240,19 +241,22 @@ public override void OnSettingModified(VFXSetting setting)
240241
stripCapacity = 1;
241242
else if (setting.name == "particlePerStripCount" && particlePerStripCount == 0)
242243
particlePerStripCount = 1;
243-
else if (setting.name == "boundsSettingMode")
244+
else if (setting.name == "boundsMode")
244245
{
245246
//Refresh errors on Output contexts
246247
var allSystemOutputContexts = owners.Where(ctx => ctx is VFXAbstractParticleOutput);
247248
foreach (var ctx in allSystemOutputContexts)
248249
{
249250
ctx.RefreshErrors(GetGraph());
250251
}
251-
if (boundsSettingMode == BoundsSettingMode.Automatic)
252+
253+
if (boundsMode == BoundsSettingMode.Automatic)
254+
{
252255
needsComputeBounds = true;
256+
var graph = GetGraph();
257+
graph.visualEffectResource.cullingFlags = VFXCullingFlags.CullNone;
258+
}
253259
}
254-
255-
256260
if (hasStrip)
257261
{
258262
if (setting.name == "dataType") // strip has just been set
@@ -674,15 +678,15 @@ public override void FillDescs(
674678
systemFlag |= VFXSystemFlag.SystemHasDirectLink;
675679
}
676680

677-
if (needsComputeBounds || boundsSettingMode == BoundsSettingMode.Automatic)
681+
if (needsComputeBounds || boundsMode == BoundsSettingMode.Automatic)
678682
{
679683
systemFlag |= VFXSystemFlag.SystemNeedsComputeBounds;
680684

681685
boundsBufferIndex = dependentBuffers.boundsBuffers[this];
682686
systemBufferMappings.Add(new VFXMapping("boundsBuffer", boundsBufferIndex));
683687
}
684688

685-
if (boundsSettingMode == BoundsSettingMode.Automatic)
689+
if (boundsMode == BoundsSettingMode.Automatic)
686690
{
687691
systemFlag |= VFXSystemFlag.SystemAutomaticBounds;
688692
}
@@ -1020,7 +1024,7 @@ public override void Sanitize(int version)
10201024
{
10211025
if (version < 8)
10221026
{
1023-
SetSettingValue("boundsSettingMode", BoundsSettingMode.Manual);
1027+
SetSettingValue("boundsMode", BoundsSettingMode.Manual);
10241028
}
10251029
base.Sanitize(version);
10261030
}

com.unity.visualeffectgraph/Editor/GraphView/BoundsRecorder/VFXBoundsRecorder.cs

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ VFXDataParticle GetSystem(string systemName)
100100

101101
public BoundsSettingMode GetSystemBoundsSettingMode(string systemName)
102102
{
103-
return GetSystem(systemName).boundsSettingMode;
103+
return GetSystem(systemName).boundsMode;
104104
}
105105

106106
public VFXBoundsRecorder(VisualEffect effect, VFXView view)
@@ -176,7 +176,7 @@ bool NeedsToBeRecorded(VFXDataParticle system)
176176
return false;
177177
}
178178
var boundsSlot = initContext.inputSlots.FirstOrDefault(s => s.name == "bounds");
179-
return system.boundsSettingMode == BoundsSettingMode.Recorded && !boundsSlot.AllChildrenWithLink().Any();
179+
return system.boundsMode == BoundsSettingMode.Recorded && !boundsSlot.AllChildrenWithLink().Any();
180180
}
181181

182182
bool NeedsToBeRecorded(VFXDataParticle system, out ExclusionCause cause)
@@ -195,16 +195,16 @@ bool NeedsToBeRecorded(VFXDataParticle system, out ExclusionCause cause)
195195
VFXSlot boundsSlot;
196196
try
197197
{
198-
boundsSlot = initContext.inputSlots.FirstOrDefault(s => s.name == "bounds");
199-
if (boundsSlot.AllChildrenWithLink().Any())
198+
boundsSlot = initContext.inputSlots.First(s => s.name == "bounds");
199+
if (boundsSlot != null && boundsSlot.HasLink(true))
200200
{
201201
cause = ExclusionCause.kGraphComputed;
202202
return false;
203203
}
204204
}
205205
catch
206206
{
207-
if (system.boundsSettingMode == BoundsSettingMode.Automatic)
207+
if (system.boundsMode == BoundsSettingMode.Automatic)
208208
{
209209
cause = ExclusionCause.kAutomatic;
210210
return false;
@@ -213,7 +213,7 @@ bool NeedsToBeRecorded(VFXDataParticle system, out ExclusionCause cause)
213213
return false;
214214
}
215215

216-
if (system.boundsSettingMode == BoundsSettingMode.Manual)
216+
if (system.boundsMode == BoundsSettingMode.Manual)
217217
{
218218
cause = ExclusionCause.kManual;
219219
return false;
@@ -233,7 +233,7 @@ void OnParamSystemModified(VFXModel model, VFXModel.InvalidationCause cause)
233233
if (model is VFXSlot)
234234
{
235235
var slot = model as VFXSlot;
236-
if (slot.name == "bounds")
236+
if (slot.name == "bounds" || slot.name == "boundsPadding")
237237
return;
238238
foreach (var data in GetAffectedData(slot))
239239
{
@@ -309,11 +309,8 @@ void UpdateBounds()
309309
Bounds currentBounds = m_Effect.GetComputedBounds(systemName);
310310
if (currentBounds.size == Vector3.zero)
311311
continue;
312-
if (system.space == VFXCoordinateSpace.World)
313-
{
314-
Matrix4x4 worldToLocal = m_Effect.transform.worldToLocalMatrix;
315-
currentBounds = TransformAABBSlow(currentBounds, worldToLocal);
316-
}
312+
var padding = m_Effect.GetCurrentPadding(systemName);
313+
currentBounds.extents -= padding;
317314
if (m_FirstBound[systemName])
318315
{
319316
m_Bounds[systemName] = currentBounds;
@@ -332,7 +329,6 @@ void UpdateBounds()
332329

333330
void RenderBounds(SceneView sv)
334331
{
335-
//TODO : Render all bounds when the selected system is not "Recorded"
336332
if (m_IsRecording && m_Effect.gameObject.activeSelf)
337333
{
338334
bool renderAllRecordedBounds = false;
@@ -376,8 +372,13 @@ void RenderBounds(SceneView sv)
376372
continue;
377373
}
378374

379-
if ((selectedSystems.Contains(systemName) || renderAllRecordedBounds) && m_Bounds.ContainsKey(systemName) && NeedsToBeRecorded(system))
380-
RenderBoundsSystem(m_Bounds[systemName]);
375+
if ((selectedSystems.Contains(systemName) || renderAllRecordedBounds) &&
376+
m_Bounds.ContainsKey(systemName) && NeedsToBeRecorded(system))
377+
{
378+
var padding = m_Effect.GetCurrentPadding(systemName);
379+
var paddedBounds = new Bounds(m_Bounds[systemName].center, 2 * (m_Bounds[systemName].extents + padding));
380+
RenderBoundsSystem(paddedBounds);
381+
}
381382
}
382383
}
383384
}
@@ -431,24 +432,10 @@ private Vector3[] ExtractVerticesFromBounds(Bounds bounds)
431432
return points;
432433
}
433434

434-
private Bounds TransformAABBSlow(Bounds bounds, Matrix4x4 transform)
435-
{
436-
Vector3[] v = ExtractVerticesFromBounds(bounds);
437-
Bounds transformed = new Bounds(transform.MultiplyPoint(v[0]), Vector3.zero);
438-
439-
for (int i = 1; i < 8; i++)
440-
{
441-
Vector3 point = transform.MultiplyPoint(v[i]);
442-
transformed.Encapsulate(point);
443-
}
444-
return transformed;
445-
}
446-
447435
public void ModifyMode(string syst, BoundsSettingMode mode)
448436
{
449437
VFXDataParticle system = GetSystem(syst);
450-
system.boundsSettingMode = mode;
451-
system.SetSettingValue("boundsSettingMode", mode);
438+
system.SetSettingValue("boundsMode", mode);
452439
}
453440

454441
public void ToggleRecording()
@@ -496,13 +483,16 @@ public void ApplyCurrentBounds()
496483
break;
497484
}
498485
var boundsSlot = initContext.inputSlots.FirstOrDefault(s => s.name == "bounds");
499-
if (initContext.GetOutputSpaceFromSlot(boundsSlot) == VFXCoordinateSpace.Local) //This should always be the case
500-
boundsSlot.value = new AABox() { center = m_Bounds[systemName].center, size = m_Bounds[systemName].size };
486+
// if (initContext.GetOutputSpaceFromSlot(boundsSlot) == VFXCoordinateSpace.Local) //TODO: Investigate why use space instead of GetOutputSpaceFromSlot
487+
var padding = m_Effect.GetCurrentPadding(systemName);
488+
var paddedBounds = new Bounds(m_Bounds[systemName].center, 2 * (m_Bounds[systemName].extents + padding));
489+
if (boundsSlot.space == VFXCoordinateSpace.Local)
490+
boundsSlot.value = new AABox() { center = paddedBounds.center, size = paddedBounds.size };
501491
else
502492
{
503-
var localToWorld = m_Effect.transform.localToWorldMatrix;
504-
var transformedBounds = TransformAABBSlow(m_Bounds[systemName], localToWorld);
505-
boundsSlot.value = new AABox() { center = transformedBounds.center, size = transformedBounds.size };
493+
//Subject to change depending on the future behavior of AABox w.r.t. to Spaceable
494+
var positionWorld = m_Effect.transform.TransformPoint(paddedBounds.center);
495+
boundsSlot.value = new AABox() { center = positionWorld, size = paddedBounds.size };
506496
}
507497
}
508498
}

com.unity.visualeffectgraph/Editor/GraphView/BoundsRecorder/VFXBoundsRecorderField.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public void Select(VisualElement selectionContainer, bool additive)
153153
selection.ClearSelection();
154154
selection.AddToSelection(this);
155155
}
156-
else // prevent heterogenous selections between stack child nodes and other nodes
156+
else
157157
{
158158
selection.AddToSelection(this);
159159
}

com.unity.visualeffectgraph/Editor/GraphView/VFXComponentBoard.cs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using UnityEditor.Experimental.GraphView;
77
using UnityEditor.SceneManagement;
88
using UnityEditor.UIElements;
9-
9+
using UnityEditor.VFX.UIElements;
1010
using UnityEngine;
1111
using UnityEngine.VFX;
1212
using UnityEngine.UIElements;
@@ -361,7 +361,7 @@ void DeleteBoundsRecorder()
361361

362362
void UpdateBoundsRecorder()
363363
{
364-
if (m_AttachedComponent != null)
364+
if (m_AttachedComponent != null && m_View.controller.graph != null)
365365
{
366366
controller.RecompileExpressionGraphIfNeeded();
367367
bool wasRecording = false;
@@ -932,10 +932,7 @@ public void Setup(string systemName, VFXBoundsRecorder boundsRecorder)
932932
var initContextUI = m_BoundsRecorder.GetInitContextController(m_SystemName);
933933
m_SystemNameButton.Setup(initContextUI, m_BoundsRecorder.view);
934934
m_SystemNameButton.text = m_SystemName;
935-
m_BoundsMode = this.Query<Button>("bounds-mode");
936-
m_BoundsMode.AddStyleSheetPathWithSkinVariant("VFXControls");
937-
m_BoundsMode.clickable.clicked += OnBoundsModeMenu;
938-
m_BoundsMode.text = m_BoundsRecorder.GetSystemBoundsSettingMode(systemName).ToString();
935+
InitBoundsModeElement();
939936
m_Colors = new Dictionary<string, StyleColor>()
940937
{
941938
{"included", m_SystemNameButton.style.color},
@@ -952,23 +949,22 @@ public void Setup(string systemName, VFXBoundsRecorder boundsRecorder)
952949
}
953950
}
954951

955-
private List<string> m_BoundsModes = new List<string> { "Manual", "Recorded", "Automatic" };
956-
957-
void OnBoundsModeMenu()
952+
void InitBoundsModeElement()
958953
{
959-
GenericMenu menu = new GenericMenu();
960-
foreach (var mode in Enum.GetValues(typeof(BoundsSettingMode)))
961-
{
962-
bool IsOn = (BoundsSettingMode)mode == m_CurrentMode;
963-
menu.AddItem(BoundsSystemContents.modesContent[(BoundsSettingMode)mode], IsOn, SetSystemBoundMode, mode);
964-
}
965-
menu.DropDown(m_BoundsMode.worldBound);
954+
m_BoundsMode = new VFXEnumField(s_EmptyEnumLabel, typeof(BoundsSettingMode));
955+
m_BoundsMode.OnValueChanged += OnValueChanged;
956+
m_BoundsMode.SetValue((int)m_CurrentMode);
957+
m_BoundsMode.AddToClassList("bounds-mode");
958+
Add(m_BoundsMode);
966959
}
967960

961+
private List<string> m_BoundsModes = new List<string> {"Manual", "Recorded", "Automatic"};
962+
968963
public void UpdateLabel()
969964
{
970965
m_CurrentMode = m_BoundsRecorder.GetSystemBoundsSettingMode(m_SystemName);
971-
m_BoundsMode.text = m_CurrentMode.ToString();
966+
m_BoundsMode.SetValue((int)m_CurrentMode);
967+
OnValueChanged();
972968
if (!m_BoundsRecorder.NeedsToBeRecorded(m_SystemName, out VFXBoundsRecorder.ExclusionCause cause))
973969
{
974970
m_SystemNameButton.text = $"{m_SystemName} {VFXBoundsRecorder.exclusionCauseString[cause]}";
@@ -994,10 +990,19 @@ public bool HasSystemBeenRenamed()
994990
void SetSystemBoundMode(object mode)
995991
{
996992
m_CurrentMode = (BoundsSettingMode)mode;
997-
m_BoundsMode.text = mode.ToString();
993+
m_BoundsMode.SetValue((int)mode);
998994
m_BoundsRecorder.ModifyMode(m_SystemName, (BoundsSettingMode)mode);
999995
}
1000996

997+
void OnValueChanged()
998+
{
999+
if (m_CurrentMode != (BoundsSettingMode)m_BoundsMode.value)
1000+
{
1001+
m_CurrentMode = (BoundsSettingMode)m_BoundsMode.value;
1002+
m_BoundsRecorder.ModifyMode(m_SystemName, m_CurrentMode);
1003+
}
1004+
}
1005+
10011006
public void ReleaseBoundsRecorder()
10021007
{
10031008
m_BoundsRecorder.isRecording = false;
@@ -1011,10 +1016,11 @@ public bool Unselect()
10111016

10121017
string m_SystemName;
10131018
VFXBoundsRecorderField m_SystemNameButton;
1014-
Button m_BoundsMode;
1019+
VFXEnumField m_BoundsMode;
10151020
BoundsSettingMode m_CurrentMode;
10161021
VFXBoundsRecorder m_BoundsRecorder;
10171022
Dictionary<string, StyleColor> m_Colors;
1023+
private static Label s_EmptyEnumLabel = new Label();
10181024

10191025
static class BoundsSystemContents
10201026
{

com.unity.visualeffectgraph/Editor/GraphView/Views/VFXPaste.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,10 @@ private void PasteDatas(ref SerializableGraph serializableGraph)
694694
serializableGraph.contexts[i].dataIndex >= 0)
695695
{
696696
var data = serializableGraph.datas[serializableGraph.contexts[i].dataIndex];
697+
698+
//At this stage, the context has the VFXGraph as its parent, so it can create a properly parented VFXData
699+
contextController.model.SetDefaultData(false);
700+
697701
VFXData targetData = contextController.model.GetData();
698702
if (targetData != null)
699703
{

0 commit comments

Comments
 (0)