Skip to content

Commit 2ddfec6

Browse files
committed
Exposed proper Spline mesh up vector control
1 parent aad76de commit 2ddfec6

7 files changed

Lines changed: 100 additions & 30 deletions

File tree

Content/Assets/Debug/LV_Debug.umap

44.5 KB
Binary file not shown.

PCGExExampleProject.uproject.DotSettings.user

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=01903EBC_002D3D9B_002D9DAB_002DA7CF_002DBDB20A54D0D5_002Ff_003Axxhash_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
33
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=11F4645C_002D5651_002DB61C_002DFEB4_002DEFE42D1B1D99_002Ff_003Acuda_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
44
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=1DD37E60_002D7AD7_002D8FAB_002D7880_002D115FFB143EF9_002Fd_003Aboost_002D1_005F82_005F0_002Fd_003Ainclude_002Fd_003Aboost_002Fd_003Ageometry_002Fd_003Aalgorithms_002Fd_003Adetail_002Ff_003Amax_005Finterval_005Fgap_002Ehpp/@EntryIndexedValue">ForceIncluded</s:String>
5+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=1DD37E60_002D7AD7_002D8FAB_002D7880_002D115FFB143EF9_002Fd_003Aboost_002D1_005F82_005F0_002Fd_003Ainclude_002Fd_003Aboost_002Fd_003Ageometry_002Fd_003Asrs_002Fd_003Aprojections_002Fd_003Aproj_002Ff_003Anzmg_002Ehpp/@EntryIndexedValue">ForceIncluded</s:String>
56
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=1DD37E60_002D7AD7_002D8FAB_002D7880_002D115FFB143EF9_002Fd_003Aboost_002D1_005F82_005F0_002Fd_003Ainclude_002Fd_003Aboost_002Fd_003Anumeric_002Fd_003Ainterval_002Fd_003Acompare_002Ff_003Acertain_002Ehpp/@EntryIndexedValue">ForceIncluded</s:String>
67
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=1DD37E60_002D7AD7_002D8FAB_002D7880_002D115FFB143EF9_002Fd_003Aboost_002D1_005F82_005F0_002Fd_003Ainclude_002Fd_003Aboost_002Fd_003Atest_002Fd_003Autils_002Ff_003Asetcolor_002Ehpp/@EntryIndexedValue">ForceIncluded</s:String>
78
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=299F1008_002DDC26_002D1217_002D6B75_002DE6284E982F05_002Fd_003APublic_002Ff_003AIndexTypes_002Eh/@EntryIndexedValue">ForceIncluded</s:String>

Plugins/PCGExtendedToolkit/Source/PCGExtendedToolkit/Private/Paths/PCGExPathSplineMesh.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111

1212
PCGEX_INITIALIZE_ELEMENT(PathSplineMesh)
1313

14+
UPCGExPathSplineMeshSettings::UPCGExPathSplineMeshSettings(
15+
const FObjectInitializer& ObjectInitializer)
16+
: Super(ObjectInitializer)
17+
{
18+
if (SplineMeshUpVectorAttribute.GetName() == FName("@Last")) { SplineMeshUpVectorAttribute.Update(TEXT("$Rotation.Up")); }
19+
}
20+
1421
TArray<FPCGPinProperties> UPCGExPathSplineMeshSettings::InputPinProperties() const
1522
{
1623
TArray<FPCGPinProperties> PinProperties = Super::InputPinProperties();
@@ -174,21 +181,32 @@ namespace PCGExPathSplineMesh
174181

175182
if (Settings->bApplyCustomTangents)
176183
{
177-
ArriveReader = PointDataFacade->GetReadable<FVector>(Settings->ArriveTangentAttribute);
178-
if (!ArriveReader)
184+
ArriveGetter = PointDataFacade->GetReadable<FVector>(Settings->ArriveTangentAttribute);
185+
if (!ArriveGetter)
179186
{
180187
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("Could not fetch tangent' Arrive attribute on some inputs."));
181188
return false;
182189
}
183190

184-
LeaveReader = PointDataFacade->GetReadable<FVector>(Settings->LeaveTangentAttribute);
185-
if (!ArriveReader)
191+
LeaveGetter = PointDataFacade->GetReadable<FVector>(Settings->LeaveTangentAttribute);
192+
if (!ArriveGetter)
186193
{
187194
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("Could not fetch tangent' Leave attribute on some inputs."));
188195
return false;
189196
}
190197
}
191198

199+
if (Settings->SplineMeshUpMode == EPCGExSplineMeshUpMode::Attribute)
200+
{
201+
UpGetter = PointDataFacade->GetScopedBroadcaster<FVector>(Settings->SplineMeshUpVectorAttribute);
202+
203+
if (!UpGetter)
204+
{
205+
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("Mesh Up Vector attribute is missing on some inputs."));
206+
return false;
207+
}
208+
}
209+
192210
LastIndex = PointDataFacade->GetNum() - 1;
193211

194212
PCGEx::InitArray(Segments, bClosedLoop ? LastIndex + 1 : LastIndex);
@@ -351,11 +369,13 @@ namespace PCGExPathSplineMesh
351369

352370
if (Settings->bApplyCustomTangents)
353371
{
354-
Segment.Params.StartTangent = LeaveReader->Read(Index);
355-
Segment.Params.EndTangent = ArriveReader->Read(NextIndex);
372+
Segment.Params.StartTangent = LeaveGetter->Read(Index);
373+
Segment.Params.EndTangent = ArriveGetter->Read(NextIndex);
356374
}
357375

358-
if (Settings->bFixGimbalLock) { Segment.FixGimbalLock(); }
376+
if (UpGetter) { Segment.UpVector = UpGetter->Read(Index); }
377+
else if (Settings->SplineMeshUpMode == EPCGExSplineMeshUpMode::Constant) { Segment.UpVector = Settings->SplineMeshUpVector; }
378+
else { Segment.FixGimbalLock(); }
359379
}
360380

361381
void FProcessor::CompleteWork()

Plugins/PCGExtendedToolkit/Source/PCGExtendedToolkit/Private/Paths/PCGExPathSplineMeshSimple.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111

1212
PCGEX_INITIALIZE_ELEMENT(PathSplineMeshSimple)
1313

14+
UPCGExPathSplineMeshSimpleSettings::UPCGExPathSplineMeshSimpleSettings(
15+
const FObjectInitializer& ObjectInitializer)
16+
: Super(ObjectInitializer)
17+
{
18+
if (SplineMeshUpVectorAttribute.GetName() == FName("@Last")) { SplineMeshUpVectorAttribute.Update(TEXT("$Rotation.Up")); }
19+
}
20+
21+
1422
PCGExData::EIOInit UPCGExPathSplineMeshSimpleSettings::GetMainOutputInitMode() const { return PCGExData::EIOInit::Duplicate; }
1523

1624
bool FPCGExPathSplineMeshSimpleElement::Boot(FPCGExContext* InContext) const
@@ -111,7 +119,7 @@ namespace PCGExPathSplineMeshSimple
111119

112120
if (!StartOffsetGetter)
113121
{
114-
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("StartOffset attribute is missing on some inputs.."));
122+
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("StartOffset attribute is missing on some inputs."));
115123
return false;
116124
}
117125
}
@@ -122,7 +130,18 @@ namespace PCGExPathSplineMeshSimple
122130

123131
if (!EndOffsetGetter)
124132
{
125-
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("EndOffset attribute is missing on some inputs.."));
133+
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("EndOffset attribute is missing on some inputs."));
134+
return false;
135+
}
136+
}
137+
138+
if (Settings->SplineMeshUpMode == EPCGExSplineMeshUpMode::Attribute)
139+
{
140+
UpGetter = PointDataFacade->GetScopedBroadcaster<FVector>(Settings->SplineMeshUpVectorAttribute);
141+
142+
if (!UpGetter)
143+
{
144+
PCGE_LOG_C(Error, GraphAndLog, ExecutionContext, FTEXT("Mesh Up Vector attribute is missing on some inputs."));
126145
return false;
127146
}
128147
}
@@ -257,7 +276,9 @@ namespace PCGExPathSplineMeshSimple
257276
Segment.Params.EndTangent = ArriveReader->Read(NextIndex);
258277
}
259278

260-
if (Settings->bFixGimbalLock) { Segment.FixGimbalLock(); }
279+
if (UpGetter) { Segment.UpVector = UpGetter->Read(Index); }
280+
else if (Settings->SplineMeshUpMode == EPCGExSplineMeshUpMode::Constant) { Segment.UpVector = Settings->SplineMeshUpVector; }
281+
else { Segment.FixGimbalLock(); }
261282
}
262283

263284
void FProcessor::CompleteWork()

Plugins/PCGExtendedToolkit/Source/PCGExtendedToolkit/Public/Paths/PCGExPathSplineMesh.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class /*PCGEXTENDEDTOOLKIT_API*/ UPCGExPathSplineMeshSettings : public UPCGExPat
3939
GENERATED_BODY()
4040

4141
public:
42+
UPCGExPathSplineMeshSettings(const FObjectInitializer& ObjectInitializer);
43+
4244
//~Begin UPCGSettings
4345
#if WITH_EDITOR
4446
PCGEX_NODE_INFOS(PathSplineMesh, "Path : Spline Mesh", "Create spline mesh components from paths.");
@@ -85,7 +87,7 @@ class /*PCGEXTENDEDTOOLKIT_API*/ UPCGExPathSplineMeshSettings : public UPCGExPat
8587
FName LeaveTangentAttribute = "LeaveTangent";
8688

8789
/** */
88-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable))
90+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Spline Axis Align"))
8991
EPCGExMinimalAxis SplineMeshAxisConstant = EPCGExMinimalAxis::X;
9092

9193
/** If enabled, will break scaling interpolation across the spline. */
@@ -111,9 +113,17 @@ class /*PCGEXTENDEDTOOLKIT_API*/ UPCGExPathSplineMeshSettings : public UPCGExPat
111113
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Additional Outputs", meta=(PCG_Overridable, EditCondition="WeightToAttribute!=EPCGExWeightOutputMode::NoOutput && WeightToAttribute!=EPCGExWeightOutputMode::NormalizedToDensity && WeightToAttribute!=EPCGExWeightOutputMode::NormalizedInvertedToDensity"))
112114
FName WeightAttributeName = "AssetWeight";
113115

114-
/** Fix gimbal lock, a.k.a weirdly twisted mesh */
115-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Fix Gimbal Lock"))
116-
bool bFixGimbalLock = false;
116+
/** */
117+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_NotOverridable))
118+
EPCGExSplineMeshUpMode SplineMeshUpMode = EPCGExSplineMeshUpMode::Constant;
119+
120+
/** */
121+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Spline Mesh Up Vector (Attr)", EditCondition="SplineMeshUpMode==EPCGExSplineMeshUpMode::Attribute", EditConditionHides))
122+
FPCGAttributePropertyInputSelector SplineMeshUpVectorAttribute;
123+
124+
/** */
125+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Spline Mesh Up Vector", EditCondition="SplineMeshUpMode==EPCGExSplineMeshUpMode::Constant", EditConditionHides))
126+
FVector SplineMeshUpVector = FVector::UpVector;
117127

118128
/** Default static mesh config applied to spline mesh components. */
119129
UPROPERTY(EditAnywhere, Category = Settings)
@@ -186,8 +196,9 @@ namespace PCGExPathSplineMesh
186196
TUniquePtr<PCGExAssetCollection::TDistributionHelper<UPCGExMeshCollection, FPCGExMeshCollectionEntry>> Helper;
187197
FPCGExJustificationDetails Justification;
188198

189-
TSharedPtr<PCGExData::TBuffer<FVector>> ArriveReader;
190-
TSharedPtr<PCGExData::TBuffer<FVector>> LeaveReader;
199+
TSharedPtr<PCGExData::TBuffer<FVector>> UpGetter;
200+
TSharedPtr<PCGExData::TBuffer<FVector>> ArriveGetter;
201+
TSharedPtr<PCGExData::TBuffer<FVector>> LeaveGetter;
191202

192203
TSharedPtr<PCGExData::TBuffer<int32>> WeightWriter;
193204
TSharedPtr<PCGExData::TBuffer<double>> NormalizedWeightWriter;

Plugins/PCGExtendedToolkit/Source/PCGExtendedToolkit/Public/Paths/PCGExPathSplineMeshSimple.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,35 +68,43 @@ class /*PCGEXTENDEDTOOLKIT_API*/ UPCGExPathSplineMeshSimpleSettings : public UPC
6868
FName LeaveTangentAttribute = "LeaveTangent";
6969

7070
/** Type of Start Offset */
71-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_NotOverridable))
71+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Offsets", meta=(PCG_NotOverridable))
7272
EPCGExInputValueType StartOffsetInput = EPCGExInputValueType::Constant;
7373

7474
/** Start Offset Attribute (Vector 2 expected)*/
75-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Start Offset (Attr)", EditCondition="StartOffsetInput!=EPCGExInputValueType::Constant", EditConditionHides))
75+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Offsets", meta=(PCG_Overridable, DisplayName="Start Offset (Attr)", EditCondition="StartOffsetInput!=EPCGExInputValueType::Constant", EditConditionHides))
7676
FName StartOffsetAttribute = FName("StartOffset");
7777

7878
/** Start Offset Constant */
79-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Start Offset", EditCondition="StartOffsetInput==EPCGExInputValueType::Constant", EditConditionHides))
79+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Offsets", meta=(PCG_Overridable, DisplayName="Start Offset", EditCondition="StartOffsetInput==EPCGExInputValueType::Constant", EditConditionHides))
8080
FVector2D StartOffset = FVector2D::ZeroVector;
8181

8282
/** Type of End Offset */
83-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_NotOverridable))
83+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Offsets", meta=(PCG_NotOverridable))
8484
EPCGExInputValueType EndOffsetInput = EPCGExInputValueType::Constant;
8585

8686
/** End Offset Attribute (Vector 2 expected)*/
87-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="End Offset (Attr)", EditCondition="EndOffsetInput!=EPCGExInputValueType::Constant", EditConditionHides))
87+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Offsets", meta=(PCG_Overridable, DisplayName="End Offset (Attr)", EditCondition="EndOffsetInput!=EPCGExInputValueType::Constant", EditConditionHides))
8888
FName EndOffsetAttribute = FName("EndOffset");
8989

9090
/** End Offset Constant */
91-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="End Offset", EditCondition="EndOffsetInput==EPCGExInputValueType::Constant", EditConditionHides))
91+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings|Offsets", meta=(PCG_Overridable, DisplayName="End Offset", EditCondition="EndOffsetInput==EPCGExInputValueType::Constant", EditConditionHides))
9292
FVector2D EndOffset = FVector2D::ZeroVector;
9393

94-
/** Fix gimbal lock, a.k.a weirdly twisted mesh */
95-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Fix Gimbal Lock"))
96-
bool bFixGimbalLock = false;
94+
/** */
95+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_NotOverridable))
96+
EPCGExSplineMeshUpMode SplineMeshUpMode = EPCGExSplineMeshUpMode::Constant;
97+
98+
/** */
99+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Spline Mesh Up Vector (Attr)", EditCondition="SplineMeshUpMode==EPCGExSplineMeshUpMode::Attribute", EditConditionHides))
100+
FPCGAttributePropertyInputSelector SplineMeshUpVectorAttribute;
101+
102+
/** */
103+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Spline Mesh Up Vector", EditCondition="SplineMeshUpMode==EPCGExSplineMeshUpMode::Constant", EditConditionHides))
104+
FVector SplineMeshUpVector = FVector::UpVector;
97105

98106
/** */
99-
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable))
107+
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta=(PCG_Overridable, DisplayName="Spline Axis Align"))
100108
EPCGExMinimalAxis SplineMeshAxisConstant = EPCGExMinimalAxis::X;
101109

102110
/** Tagging details */
@@ -152,6 +160,7 @@ namespace PCGExPathSplineMeshSimple
152160
int32 C1 = 1;
153161
int32 C2 = 2;
154162

163+
TSharedPtr<PCGExData::TBuffer<FVector>> UpGetter;
155164
TSharedPtr<PCGExData::TBuffer<FVector2D>> StartOffsetGetter;
156165
TSharedPtr<PCGExData::TBuffer<FVector2D>> EndOffsetGetter;
157166

Plugins/PCGExtendedToolkit/Source/PCGExtendedToolkit/Public/Paths/PCGExPaths.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ enum class EPCGExPathNormalDirection : uint8
4545
AverageNormal = 2 UMETA(DisplayName = "Average Normal", ToolTip="..."),
4646
};
4747

48+
UENUM()
49+
enum class EPCGExSplineMeshUpMode : uint8
50+
{
51+
Constant = 0 UMETA(DisplayName = "Constant", Tooltip="Constant up vector"),
52+
Attribute = 1 UMETA(DisplayName = "Attribute", Tooltip="Per-point attribute value"),
53+
GimbalFix = 2 UMETA(DisplayName = "Auto (Gimbal fix)", Tooltip="Automatically computed up vector to enforce gimbal fix")
54+
};
55+
4856
USTRUCT(BlueprintType)
4957
struct /*PCGEXTENDEDTOOLKIT_API*/ FPCGExPathClosedLoopDetails
5058
{
@@ -304,10 +312,10 @@ namespace PCGExPaths
304312
{
305313
// Thanks Drakynfly @ https://www.reddit.com/r/unrealengine/comments/kqo6ez/usplinecomponent_twists_in_on_itself/
306314

307-
const FVector NormalA = Params.StartTangent.GetSafeNormal(0.001);
308-
const FVector NormalB = Params.EndTangent.GetSafeNormal(0.001);
309-
if (const float Dot = NormalA | NormalB; Dot > 0.99 || Dot <= -0.99) { UpVector = NormalA; }
310-
else { UpVector = NormalA ^ NormalB; }
315+
const FVector A = Params.StartTangent.GetSafeNormal(0.001);
316+
const FVector B = Params.EndTangent.GetSafeNormal(0.001);
317+
if (const float Dot = A | B; Dot > 0.99 || Dot <= -0.99) { UpVector = A; }
318+
else { UpVector = A ^ B; }
311319
}
312320

313321
void ApplySettings(USplineMeshComponent* Component) const

0 commit comments

Comments
 (0)