Skip to content

Commit 5e3c342

Browse files
PaulDemeulenaereEvergreen
authored andcommitted
[VFX] Fix Position Box with Zero Scale
About UUM-62355, the Position Box has been migrated with this PR: https://github.cds.internal.unity3d.com/unity/unity/pull/40039 Since the normal/axis are aligned with the box, we can skip the scale if possible (aka the transform comes from a Translation/Rotation/Scale): https://media.github.cds.internal.unity3d.com/user/42/files/a979c270-ce82-4537-af32-d4ff6f0e5df3 ⚠️ If we are computing the box in other way, the scale won't be skipped and it still leads to invalid axis but it's an really rare case: https://media.github.cds.internal.unity3d.com/user/42/files/1aaaa3b8-d983-41fb-bb9c-5ce0222dfa1b About UUM-67233, the Position On SDF was incomplete: - The applyOrientation wasn't tested leading to compilation failure - The blending mode wasn't taken into account (Position Add/Mul/Blend, ...) - The axisX/Y/Z was never wrote, I made them consistent with the sphere orientation (see below) https://media.github.cds.internal.unity3d.com/user/42/files/43efeee4-0756-408f-9d46-5a3f0e6836f6
1 parent 76c98c1 commit 5e3c342

File tree

4 files changed

+133
-35
lines changed

4 files changed

+133
-35
lines changed

Packages/com.unity.visualeffectgraph/Editor/Models/Blocks/Implementations/Position/PositionBox.cs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,35 @@ public override IEnumerable<VFXNamedExpression> GetParameters(PositionShape posi
8686
boxSize = VFXOperatorUtility.OneExpression[VFXValueType.Float3];
8787
}
8888

89+
//If possible, remove scale to allow zero scale matrices (see UUM-62355)
90+
var transformForInversion = transform;
91+
var isInverseTransposeBoxOrthonormal = VFXOperatorUtility.FalseExpression;
92+
if (positionBase.inputSlots[0].space == VFXSpace.None || positionBase.inputSlots[0].space == positionBase.GetParent().space)
93+
{
94+
if (transform is VFXExpressionTRSToMatrix)
95+
{
96+
transformForInversion = new VFXExpressionTRSToMatrix(VFXOperatorUtility.ZeroExpression[VFXValueType.Float3], transform.parents[1], VFXOperatorUtility.OneExpression[VFXValueType.Float3]);
97+
isInverseTransposeBoxOrthonormal = VFXOperatorUtility.TrueExpression;
98+
}
99+
}
100+
else
101+
{
102+
if (transform is not VFXExpressionTransformMatrix)
103+
throw new InvalidOperationException("Unexpected missing space conversion");
104+
105+
var left = transform.parents[0];
106+
var right = transform.parents[1];
107+
if (right is VFXExpressionTRSToMatrix)
108+
{
109+
right = new VFXExpressionTRSToMatrix(VFXOperatorUtility.ZeroExpression[VFXValueType.Float3], right.parents[1], VFXOperatorUtility.OneExpression[VFXValueType.Float3]);
110+
transformForInversion = new VFXExpressionTransformMatrix(left, right);
111+
//inverseTransposeBoxOrthonormal still false, LocalToWorld can contains scale
112+
}
113+
}
114+
89115
yield return new VFXNamedExpression(transform, "Box");
90-
yield return new VFXNamedExpression(VFXOperatorUtility.InverseTransposeTRS(transform), "InverseTransposeBox");
116+
yield return new VFXNamedExpression(VFXOperatorUtility.InverseTransposeTRS(transformForInversion), "InverseTransposeBox");
117+
yield return new VFXNamedExpression(isInverseTransposeBoxOrthonormal, "IsInverseTransposeBoxOrthonormal");
91118
yield return new VFXNamedExpression(boxSize, "Box_size");
92119
foreach (var p in GetVolumeExpressions(positionBase.positionMode, boxSize, thickness))
93120
yield return p;
@@ -210,8 +237,11 @@ public override string GetSource(PositionShape positionBase)
210237
outPos = mul(Box, float4(outPos, 1.0f)).xyz;
211238
outUp = mul(InverseTransposeBox, float4(outUp, 0.0f)).xyz;
212239
outDir = mul(InverseTransposeBox, float4(outDir, 0.0f)).xyz;
213-
outDir = normalize(outDir);
214-
outUp = normalize(outUp);
240+
if (!IsInverseTransposeBoxOrthonormal)
241+
{
242+
outDir = normalize(outDir);
243+
outUp = normalize(outUp);
244+
}
215245
outTan = cross(outDir, outUp);
216246
";
217247

Packages/com.unity.visualeffectgraph/Editor/Models/Blocks/Implementations/Position/PositionSDF.cs

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using System.Collections.Generic;
4+
using System.Text;
45
using UnityEngine;
56

67
namespace UnityEditor.VFX.Block
@@ -45,7 +46,7 @@ public override IEnumerable<VFXNamedExpression> GetParameters(PositionShape posi
4546

4647
var extents = new VFXNamedExpression(new VFXExpressionExtractScaleFromMatrix(transform), "extents");
4748
yield return new VFXNamedExpression(VFX.VFXOperatorUtility.Max3(extents.exp), "scalingFactor");
48-
yield return new VFXNamedExpression(new VFXExpressionInverseTRSMatrix(transform), "InvFieldTransform");
49+
yield return new VFXNamedExpression(new VFXExpressionInverseTRSMatrix(transform), "inverseTransform");
4950
var minDim = new VFXExpressionCastUintToFloat(VFX.VFXOperatorUtility.Min3(new VFXExpressionTextureHeight(sdf), new VFXExpressionTextureWidth(sdf), new VFXExpressionTextureDepth(sdf)));
5051
var gradStep = VFXValue.Constant(0.01f); //kStep used in SampleSDFDerivativesFast and SampleSDFDerivatives
5152
var margin = VFXValue.Constant(0.5f) / minDim + gradStep + VFXValue.Constant(0.001f);
@@ -55,32 +56,33 @@ public override IEnumerable<VFXNamedExpression> GetParameters(PositionShape posi
5556

5657
public override string GetSource(PositionShape positionBase)
5758
{
58-
string outSource = @"float cosPhi = 2.0f * RAND - 1.0f;";
59+
var outSource = new StringBuilder(@"float cosPhi = 2.0f * RAND - 1.0f;");
5960
if (positionBase.spawnMode == PositionBase.SpawnMode.Random)
60-
outSource += @"float theta = TWO_PI * RAND;";
61+
outSource.AppendLine(@"float theta = TWO_PI * RAND;");
6162
else
62-
outSource += @"float theta = TWO_PI * ArcSequencer;";
63+
outSource.AppendLine(@"float theta = TWO_PI * ArcSequencer;");
6364
switch (positionBase.positionMode)
6465
{
6566
case (PositionBase.PositionMode.Surface):
66-
outSource += @" float Thickness = 0.0f;";
67+
outSource.AppendLine(@" float Thickness = 0.0f;");
6768
break;
6869
case (PositionBase.PositionMode.Volume):
69-
outSource += @" float Thickness = scalingFactor;";
70+
outSource.AppendLine(@" float Thickness = scalingFactor;");
7071
break;
7172
case (PositionBase.PositionMode.ThicknessRelative):
72-
outSource += @" Thickness *= scalingFactor * 0.5f;";
73+
outSource.AppendLine(@" Thickness *= scalingFactor * 0.5f;");
7374
break;
7475
}
75-
outSource += @"
76+
77+
outSource.Append(@"
7678
//Initialize position within texture bounds
7779
float2 sincosTheta;
7880
sincos(theta, sincosTheta.x, sincosTheta.y);
7981
sincosTheta *= sqrt(1.0f - cosPhi * cosPhi);
80-
direction = float3(sincosTheta, cosPhi) * sqrt(3)/2;
81-
float maxDir = max(0.5f, max(abs(direction.x), max(abs(direction.y), abs(direction.z))));
82-
direction = direction * (projectionRayWithMargin/maxDir);
83-
float3 tPos = direction * pow(RAND, 1.0f/3.0f);
82+
float3 currentAxisY = float3(sincosTheta, cosPhi) * sqrt(3)/2;
83+
float maxDir = max(0.5f, max(abs(currentAxisY.x), max(abs(currentAxisY.y), abs(currentAxisY.z))));
84+
currentAxisY = currentAxisY * (projectionRayWithMargin/maxDir);
85+
float3 tPos = currentAxisY * pow(RAND, 1.0f/3.0f);
8486
float3 coord = tPos + 0.5f;
8587
float3 wPos, n, worldNormal;
8688
@@ -92,33 +94,63 @@ public override string GetSource(PositionShape positionBase)
9294
9395
//Projection on surface/volume
9496
float3 delta;
95-
worldNormal = VFXSafeNormalize(mul(float4(n, 0), InvFieldTransform).xyz);
97+
worldNormal = VFXSafeNormalize(mul(float4(n, 0), inverseTransform).xyz);
9698
if (dist > 0)
9799
delta = dist * worldNormal;
98100
else
99101
{
100102
delta = min(dist + Thickness, 0) * worldNormal;
101103
}
102104
103-
wPos = mul(FieldTransform, float4(tPos,1)).xyz + delta;
104-
tPos = mul(InvFieldTransform, float4(wPos,1)).xyz;
105+
wPos = mul(FieldTransform, float4(tPos,1)).xyz + delta;
106+
tPos = mul(inverseTransform, float4(wPos, 1)).xyz;
105107
coord = tPos + 0.5f;
106108
109+
}");
110+
outSource.AppendFormat(positionBase.composePositionFormatString, "wPos");
111+
112+
if (positionBase.applyOrientation != PositionBase.Orientation.None)
113+
outSource.Append(@"currentAxisY = -worldNormal;");
114+
115+
if (positionBase.applyOrientation.HasFlag(PositionBase.Orientation.Axes))
116+
outSource.Append(@"
117+
float3 AxisZCandidateA = float3(-sincosTheta.y, sincosTheta.x, 0);
118+
float3 AxisZCandidateB = float3(sign(cosPhi), 0, 0);
119+
AxisZCandidateA = mul(float4(AxisZCandidateA, 0), inverseTransform).xyz;
120+
AxisZCandidateB = mul(float4(AxisZCandidateB, 0), inverseTransform).xyz;
121+
122+
float3 currentAxisZ = AxisZCandidateA;
123+
float3 currentAxisX = cross(currentAxisZ, currentAxisY);
124+
if (dot(currentAxisX, currentAxisX) < 0.00001f)
125+
{
126+
currentAxisZ = AxisZCandidateB;
127+
currentAxisX = cross(currentAxisZ, currentAxisY);
107128
}
108-
position = wPos;
109-
direction = -worldNormal;
110-
";
111-
if (positionBase.killOutliers)
129+
130+
currentAxisX = normalize(currentAxisX);
131+
currentAxisZ = normalize(cross(currentAxisX, currentAxisY));");
132+
133+
if (positionBase.applyOrientation.HasFlag(PositionBase.Orientation.Direction))
112134
{
113-
outSource += @"
135+
outSource.AppendFormat(positionBase.composeDirectionFormatString, "currentAxisY");
136+
}
114137

138+
if (positionBase.applyOrientation.HasFlag(PositionBase.Orientation.Axes))
139+
{
140+
outSource.AppendFormat(VFXBlockUtility.GetComposeString(positionBase.compositionAxes, "axisX", "currentAxisX", "blendAxes"));
141+
outSource.AppendFormat(VFXBlockUtility.GetComposeString(positionBase.compositionAxes, "axisY", "currentAxisY", "blendAxes"));
142+
outSource.AppendFormat(VFXBlockUtility.GetComposeString(positionBase.compositionAxes, "axisZ", "currentAxisZ", "blendAxes"));
143+
}
144+
145+
if (positionBase.killOutliers)
146+
{
147+
outSource.Append(@"
115148
float dist = SampleSDF(SDF, coord);
116149
if (dist * scalingFactor > 0.01)
117-
alive = false;
118-
";
150+
alive = false;");
119151
}
120152

121-
return outSource;
153+
return outSource.ToString();
122154
}
123155
}
124156
}

Packages/com.unity.visualeffectgraph/Editor/Models/Operators/VFXOperatorUtility.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public static Dictionary<VFXValueType, VFXExpression> GenerateExpressionConstant
2222
};
2323
}
2424

25+
public static readonly VFXExpression TrueExpression = VFXValue.Constant(true);
26+
public static readonly VFXExpression FalseExpression = VFXValue.Constant(false);
2527
public static readonly Dictionary<VFXValueType, VFXExpression> OneExpression = GenerateExpressionConstant(1.0f);
2628
public static readonly Dictionary<VFXValueType, VFXExpression> MinusOneExpression = GenerateExpressionConstant(-1.0f);
2729
public static readonly Dictionary<VFXValueType, VFXExpression> HalfExpression = GenerateExpressionConstant(0.5f);

Tests/SRPTests/Packages/com.unity.testing.visualeffectgraph/Tests/Editor/VFXCodeGenerationTest.cs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using UnityEditor.VFX.Block;
99
using UnityEngine.TestTools;
1010
using System.Collections;
11-
using static UnityEditor.VFX.Block.CollisionBase;
11+
using UnityEditor.Rendering;
1212

1313
namespace UnityEditor.VFX.Test
1414
{
@@ -191,16 +191,48 @@ public void Constant_Folding_With_ShaderKeyword([ValueSource("allCompilationMode
191191
Assert.AreEqual(4, shaderCount);
192192
vfx.GetOrCreateGraph().SetCompilationMode(VFXCompilationMode.Runtime);
193193
}
194-
194+
195+
private IEnumerable CheckCompilation(VFXGraph vfxGraph)
196+
{
197+
var resource = vfxGraph.GetResource();
198+
EditorUtility.SetDirty(resource);
199+
var path = AssetDatabase.GetAssetPath(vfxGraph);
200+
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport);
201+
202+
for (int i = 0; i < 4; ++i)
203+
yield return null;
204+
205+
while (ShaderUtil.anythingCompiling)
206+
yield return null;
207+
208+
var computeShaders = AssetDatabase.LoadAllAssetsAtPath(path).OfType<ComputeShader>().ToArray();
209+
Assert.AreEqual(3, computeShaders.Length);
210+
211+
foreach (var computeShader in computeShaders)
212+
{
213+
var messages = ShaderUtil.GetComputeShaderMessages(computeShader);
214+
foreach (var message in messages)
215+
Assert.AreNotEqual(ShaderCompilerMessageSeverity.Error, message.severity, message.message);
216+
217+
Assert.AreEqual(0, computeShader.FindKernel("CSMain"));
218+
Assert.IsTrue(computeShader.IsSupported(0));
219+
}
220+
yield return null;
221+
}
222+
195223
[UnityTest]
196224
public IEnumerator Combinatory_Position_Shape()
197225
{
198226
var vfxGraph = VFXTestCommon.CreateGraph_And_System();
199227
var initialize = vfxGraph.children.OfType<VFXBasicInitialize>().First();
200228

229+
var orientations = new List<PositionBase.Orientation>(Enum.GetValues(typeof(PositionBase.Orientation)).OfType<PositionBase.Orientation>());
230+
orientations.Add(PositionBase.Orientation.Axes | PositionBase.Orientation.Direction);
231+
201232
foreach (PositionBase.PositionMode positionMode in Enum.GetValues(typeof(PositionBase.PositionMode)))
202233
foreach (PositionBase.SpawnMode spawnMode in Enum.GetValues(typeof(PositionBase.SpawnMode)))
203234
foreach (PositionShapeBase.Type shape in Enum.GetValues(typeof(PositionShapeBase.Type)))
235+
foreach (PositionBase.Orientation orientation in orientations)
204236
{
205237
var positionShape = ScriptableObject.CreateInstance<PositionShape>();
206238
positionShape.SetSettingValue("positionMode", positionMode);
@@ -211,14 +243,15 @@ public IEnumerator Combinatory_Position_Shape()
211243
positionShape.SetSettingValue("compositionPosition", AttributeCompositionMode.Blend);
212244
positionShape.SetSettingValue("compositionAxes", AttributeCompositionMode.Blend);
213245
positionShape.SetSettingValue("compositionDirection", AttributeCompositionMode.Blend);
214-
positionShape.SetSettingValue("applyOrientation", PositionBase.Orientation.Direction | PositionBase.Orientation.Axes);
246+
positionShape.SetSettingValue("applyOrientation", orientation);
215247

216248
initialize.AddChild(positionShape);
217249
}
218250

219-
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(vfxGraph));
220-
for (int i = 0; i < 4; ++i) //Wait a few frame in case of shader compilation error
221-
yield return null;
251+
foreach (var yield in CheckCompilation(vfxGraph))
252+
{
253+
yield return yield;
254+
}
222255
}
223256

224257
[UnityTest]
@@ -259,9 +292,10 @@ public IEnumerator Combinatory_Collision_Shape()
259292
initialize.AddChild(collisionShape);
260293
}
261294

262-
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(vfxGraph));
263-
for (int i = 0; i < 4; ++i) //Wait a few frame in case of shader compilation error
264-
yield return null;
295+
foreach (var yield in CheckCompilation(vfxGraph))
296+
{
297+
yield return yield;
298+
}
265299
}
266300
}
267301
}

0 commit comments

Comments
 (0)