Skip to content

Commit f0ce070

Browse files
Add spline generator and add module
- Spline generator can be useful for manual masks of things like rivers paths or playable areas to facilitate building placement. Has a known problem where splines are convex that's noted in comments - Add module is handy for adding a small amount of noise without compressing average height - Added falloff curve to both splines and blend. This can be handy for making cliffs. - Added some other code that was in cashgen but missing from here for 3Select module
1 parent 850df2b commit f0ce070

File tree

11 files changed

+326
-7
lines changed

11 files changed

+326
-7
lines changed

‎Plugins/UnrealFastNoisePlugin/Source/UnrealFastNoisePlugin/Private/UFN3SelectModule.cpp‎

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,25 @@ float UUFN3SelectModule::GetNoise3D(float aX, float aY, float aZ)
1616

1717
float control = (selectModule->GetNoise3D(aX, aY, aZ));
1818

19+
if (interpType != ESelectInterpType::None)
20+
{
21+
// Outside falloff bounds
22+
if (control >= upperThreshold + falloff) {
23+
return inputModule1->GetNoise3D(aX, aY, aZ);
24+
}
25+
else if (control >= lowerThreshold + falloff && control < upperThreshold - falloff) {
26+
return inputModule2->GetNoise3D(aX, aY, aZ);
27+
}
28+
else if (control < lowerThreshold - falloff) {
29+
return inputModule3->GetNoise3D(aX, aY, aZ);
30+
}
31+
else if (control < upperThreshold + falloff && control >= upperThreshold - falloff) {
32+
return GetInterp3D(aX, aY, aZ, inputModule2, inputModule1, interpType, (control - (upperThreshold - falloff) / 2.0f * falloff));
33+
}
34+
else if (control < lowerThreshold + falloff && control >= lowerThreshold - falloff) {
35+
return GetInterp3D(aX, aY, aZ, inputModule3, inputModule2, interpType, (control - (lowerThreshold - falloff) / 2.0f * falloff));
36+
}
37+
}
1938

2039
// If there's no interpolation, easy mode
2140
if (control >= upperThreshold) {
@@ -39,6 +58,26 @@ float UUFN3SelectModule::GetNoise2D(float aX, float aY)
3958

4059
float control = (selectModule->GetNoise2D(aX, aY));
4160

61+
if (interpType != ESelectInterpType::None)
62+
{
63+
// Outside falloff bounds
64+
if (control >= upperThreshold + falloff) {
65+
return inputModule1->GetNoise2D(aX, aY);
66+
}
67+
else if (control >= lowerThreshold + falloff && control < upperThreshold - falloff) {
68+
return inputModule2->GetNoise2D(aX, aY);
69+
}
70+
else if (control < lowerThreshold - falloff) {
71+
return inputModule3->GetNoise2D(aX, aY);
72+
}
73+
else if (control < upperThreshold + falloff && control >= upperThreshold - falloff) {
74+
return GetInterp2D(aX, aY, inputModule2, inputModule1, interpType, (control - ((upperThreshold) - falloff) / 2.0f * falloff));
75+
}
76+
else if (control < lowerThreshold + falloff && control >= lowerThreshold - falloff) {
77+
return GetInterp2D(aX, aY, inputModule3, inputModule2, interpType, (control - ((lowerThreshold) - falloff) / 2.0f * falloff));
78+
}
79+
}
80+
4281
// If there's no interpolation, easy mode
4382
if (control >= upperThreshold) {
4483
return inputModule1->GetNoise2D(aX, aY);
@@ -54,3 +93,59 @@ float UUFN3SelectModule::GetNoise2D(float aX, float aY)
5493

5594
}
5695

96+
float UUFN3SelectModule::GetInterp2D(float aX, float aY, UUFNNoiseGenerator* input1, UUFNNoiseGenerator* input2, ESelectInterpType interpType, float alpha)
97+
{
98+
switch (interpType)
99+
{
100+
case ESelectInterpType::CircularIn:
101+
return FMath::InterpCircularIn(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
102+
case ESelectInterpType::CircularInOut:
103+
return FMath::InterpCircularInOut(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
104+
case ESelectInterpType::CircularOut:
105+
return FMath::InterpCircularOut(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
106+
case ESelectInterpType::ExponentialIn:
107+
return FMath::InterpExpoIn(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
108+
case ESelectInterpType::ExponentialInOut:
109+
return FMath::InterpExpoInOut(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
110+
case ESelectInterpType::ExponentialOut:
111+
return FMath::InterpExpoOut(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
112+
case ESelectInterpType::SineIn:
113+
return FMath::InterpSinIn(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
114+
default:
115+
case ESelectInterpType::SineInOut:
116+
return FMath::InterpSinInOut(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
117+
case ESelectInterpType::SineOut:
118+
return FMath::InterpSinInOut(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha);
119+
case ESelectInterpType::Step:
120+
return FMath::InterpStep(input1->GetNoise2D(aX, aY), input2->GetNoise2D(aX, aY), alpha, numSteps);
121+
}
122+
}
123+
124+
float UUFN3SelectModule::GetInterp3D(float aX, float aY, float aZ, UUFNNoiseGenerator* input1, UUFNNoiseGenerator* input2, ESelectInterpType interpType, float alpha)
125+
{
126+
switch (interpType)
127+
{
128+
case ESelectInterpType::CircularIn:
129+
return FMath::InterpCircularIn(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
130+
case ESelectInterpType::CircularInOut:
131+
return FMath::InterpCircularInOut(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
132+
case ESelectInterpType::CircularOut:
133+
return FMath::InterpCircularOut(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
134+
case ESelectInterpType::ExponentialIn:
135+
return FMath::InterpExpoIn(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
136+
case ESelectInterpType::ExponentialInOut:
137+
return FMath::InterpExpoInOut(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
138+
case ESelectInterpType::ExponentialOut:
139+
return FMath::InterpExpoOut(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
140+
case ESelectInterpType::SineIn:
141+
return FMath::InterpSinIn(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
142+
default:
143+
case ESelectInterpType::SineInOut:
144+
return FMath::InterpSinInOut(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
145+
case ESelectInterpType::SineOut:
146+
return FMath::InterpSinInOut(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha);
147+
case ESelectInterpType::Step:
148+
return FMath::InterpStep(input1->GetNoise3D(aX, aY, aZ), input2->GetNoise3D(aX, aY, aZ), alpha, numSteps);
149+
}
150+
}
151+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
#include "UnrealFastNoisePlugin.h"
3+
#include "UFNNoiseGenerator.h"
4+
#include "UFNAddModule.h"
5+
6+
UUFNAddModule::UUFNAddModule(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
7+
{
8+
threshold = 0.0f;
9+
}
10+
11+
float UUFNAddModule::GetNoise3D(float aX, float aY, float aZ)
12+
{
13+
14+
if (!(inputModule1 || inputModule2)) {
15+
return 0.0f;
16+
}
17+
18+
float modifier = 1.0f;
19+
if (maskModule)
20+
{
21+
float mask = maskModule->GetNoise3D(aX, aY, aZ);
22+
if (mask >= threshold)
23+
{
24+
modifier = mask;
25+
}
26+
else {
27+
return inputModule1->GetNoise3D(aX, aY, aZ);
28+
}
29+
}
30+
31+
32+
return modifier * (inputModule1->GetNoise3D(aX, aY, aZ) + inputModule2->GetNoise3D(aX, aY, aZ));
33+
34+
35+
}
36+
37+
float UUFNAddModule::GetNoise2D(float aX, float aY)
38+
{
39+
return GetNoise3D(aX, aY, 0.0f);
40+
}
41+

‎Plugins/UnrealFastNoisePlugin/Source/UnrealFastNoisePlugin/Private/UFNBlendModule.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ float UUFNBlendModule::GetNoise3D(float aX, float aY, float aZ)
1717

1818
float control = (selectModule->GetNoise3D(aX, aY, aZ) + 1.0f) / 2.0f;
1919

20+
if (blendCurve)
21+
{
22+
control = blendCurve->GetFloatValue(control);
23+
}
24+
2025
return FMath::Lerp(inputModule1->GetNoise3D(aX, aY, aZ), inputModule2->GetNoise3D(aX, aY, aZ), control);
2126
}
2227

@@ -28,6 +33,11 @@ float UUFNBlendModule::GetNoise2D(float aX, float aY)
2833

2934
float control = (selectModule->GetNoise2D(aX, aY) + 1.0f) / 2.0f;
3035

36+
if (blendCurve)
37+
{
38+
control = blendCurve->GetFloatValue(control);
39+
}
40+
3141
return FMath::Lerp(inputModule1->GetNoise2D(aX, aY), inputModule2->GetNoise2D(aX, aY), control);
3242
}
3343

‎Plugins/UnrealFastNoisePlugin/Source/UnrealFastNoisePlugin/Private/UFNBlueprintFunctionLibrary.cpp‎

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
#include "UFN3SelectModule.h"
55
#include "UFNBlendModule.h"
66
#include "UFNScaleBiasModule.h"
7+
#include "UFNAddModule.h"
78
#include "UFNConstantModule.h"
9+
#include "UFNSplineGenerator.h"
10+
#include "Classes/Components/SplineComponent.h"
811
#include "UFNBlueprintFunctionLibrary.h"
912

1013
UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateNoiseGenerator(UObject* outer, ENoiseType noiseType, ECellularDistanceFunction cellularDistanceFunction, ECellularReturnType cellularReturnType , EFractalType fractalType, EInterp interpolation, int32 seed, int32 octaves, float frequency, float lacunarity, EPositionWarpType positionWarpType, float positionWarpAmplitude)
1114
{
12-
UFastNoise* noiseGen = NewObject<UFastNoise>(outer, FName("NoiseGen"));
15+
UFastNoise* noiseGen = NewObject<UFastNoise>(outer);
1316

1417
noiseGen->SetNoiseType(noiseType);
1518
noiseGen->SetSeed(seed);
@@ -34,7 +37,7 @@ UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateSelectModule(UObject* ou
3437
return nullptr;
3538
}
3639

37-
UUFNSelectModule* newSelectModule = NewObject<UUFNSelectModule>(outer, FName("Select"));
40+
UUFNSelectModule* newSelectModule = NewObject<UUFNSelectModule>(outer);
3841

3942
newSelectModule->inputModule1 = inputModule1;
4043
newSelectModule->inputModule2 = inputModule2;
@@ -47,17 +50,18 @@ UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateSelectModule(UObject* ou
4750
return newSelectModule;
4851
}
4952

50-
UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateBlendModule(UObject* outer, UUFNNoiseGenerator* inputModule1, UUFNNoiseGenerator* inputModule2, UUFNNoiseGenerator* selectModule)
53+
UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateBlendModule(UObject* outer, UUFNNoiseGenerator* inputModule1, UUFNNoiseGenerator* inputModule2, UUFNNoiseGenerator* selectModule, UCurveFloat* blendCurve)
5154
{
5255
if (!(inputModule1 && inputModule2 && selectModule && outer)) {
5356
return nullptr;
5457
}
5558

56-
UUFNBlendModule* blendModule = NewObject<UUFNBlendModule>(outer, FName("Blend"));
59+
UUFNBlendModule* blendModule = NewObject<UUFNBlendModule>(outer);
5760

5861
blendModule->inputModule1 = inputModule1;
5962
blendModule->inputModule2 = inputModule2;
6063
blendModule->selectModule = selectModule;
64+
blendModule->blendCurve = blendCurve;
6165

6266
return blendModule;
6367
}
@@ -77,6 +81,23 @@ UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateScaleBiasModule(UObject*
7781
return scaleBiasModule;
7882
}
7983

84+
UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateAddModule(UObject* outer, UUFNNoiseGenerator* inputModule1, UUFNNoiseGenerator* inputModule2, UUFNNoiseGenerator* maskModule, float threshold)
85+
{
86+
if (!(outer && inputModule1 && inputModule2))
87+
{
88+
return nullptr;
89+
}
90+
91+
UUFNAddModule* noiseGen = NewObject<UUFNAddModule>(outer);
92+
93+
noiseGen->inputModule1 = inputModule1;
94+
noiseGen->inputModule2 = inputModule2;
95+
noiseGen->maskModule = maskModule;
96+
noiseGen->threshold = threshold;
97+
98+
return noiseGen;
99+
}
100+
80101
UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateConstantModule(UObject* outer, float constantValue)
81102
{
82103
UUFNConstantModule* noiseGen = NewObject<UUFNConstantModule>(outer);
@@ -165,7 +186,7 @@ UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::Create3SelectModule(UObject* o
165186
return nullptr;
166187
}
167188

168-
UUFN3SelectModule* newSelectModule = NewObject<UUFN3SelectModule>(outer, FName("Select"));
189+
UUFN3SelectModule* newSelectModule = NewObject<UUFN3SelectModule>(outer);
169190

170191
newSelectModule->inputModule1 = inputModule1;
171192
newSelectModule->inputModule2 = inputModule2;
@@ -180,6 +201,17 @@ UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::Create3SelectModule(UObject* o
180201
return newSelectModule;
181202
}
182203

204+
UUFNNoiseGenerator* UUFNBlueprintFunctionLibrary::CreateSplineGenerator(UObject* outer, float MaxDistance, float MinDistance, TArray<USplineComponent*> Splines, UCurveFloat* falloffCurve)
205+
{
206+
UUFNSplineGenerator* newSplineGenerator = NewObject<UUFNSplineGenerator>(outer);
207+
newSplineGenerator->MaximumDistance = MaxDistance;
208+
newSplineGenerator->MinimumDistance = MinDistance;
209+
newSplineGenerator->Splines = Splines;
210+
newSplineGenerator->FalloffCurve = falloffCurve;
211+
212+
return newSplineGenerator;
213+
}
214+
183215
UUFNBlueprintFunctionLibrary::UUFNBlueprintFunctionLibrary(const class FObjectInitializer& obj)
184216
: Super(obj)
185217
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "UnrealFastNoisePlugin.h"
2+
#include "UFNNoiseGenerator.h"
3+
#include "Classes/Components/SplineComponent.h"
4+
#include "UFNSplineGenerator.h"
5+
6+
UUFNSplineGenerator::UUFNSplineGenerator(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
7+
{
8+
}
9+
10+
float UUFNSplineGenerator::GetNoise3D(float aX, float aY, float aZ)
11+
{
12+
float LocalMinDistance = MaximumDistance;
13+
FVector WorldPoint = FVector(aX, aY, aZ);
14+
for (auto Spline : Splines)
15+
{
16+
// May need the InputKey later, so instead of finding location, find input key to prevent multiple searches
17+
float InputKey = Spline->FindInputKeyClosestToWorldLocation(WorldPoint);
18+
FVector PointOnSpline = Spline->GetLocationAtSplineInputKey(InputKey, ESplineCoordinateSpace::World);
19+
20+
float Distance = FVector::Dist(FVector(aX, aY, 0.0f), PointOnSpline);
21+
22+
// If we are inside a spline's width, distance from other splines is irrelevant so we can return early
23+
if (Distance < MinimumDistance)
24+
{
25+
return 0.0f;
26+
}
27+
else {
28+
LocalMinDistance = Distance < LocalMinDistance ? Distance : LocalMinDistance;
29+
/*
30+
This is not implemented
31+
32+
Inside convex curves we have the problem that a point may be closer to the sides than to the points
33+
near the apex. This means there will be a seam down the centre rather than a soft gradient. We could
34+
alleviate this by ensuring we use a point on the curve that has a (roughly) orthogonal tangent to
35+
the vector between our world space point and the point on the tangent, but this doesn't seem to work.
36+
37+
FVector TangentOnSpline = Spline->GetTangentAtSplineInputKey(InputKey, ESplineCoordinateSpace::World);
38+
TangentOnSpline.Normalize();
39+
FVector WorldPointToSplinePoint = PointOnSpline - WorldPoint;
40+
WorldPointToSplinePoint.Normalize();
41+
if (FVector::DotProduct(TangentOnSpline, WorldPointToSplinePoint) <= TangentApproximation)
42+
{
43+
LocalMinDistance = Distance < LocalMinDistance ? Distance : LocalMinDistance;
44+
}
45+
else {
46+
// Find a point on the curve with orthogonal tangent, and use distance to that instead.
47+
return 0.0f;
48+
}
49+
*/
50+
51+
}
52+
}
53+
54+
if (FalloffCurve)
55+
{
56+
return FalloffCurve->GetFloatValue((LocalMinDistance - MinimumDistance) / (MaximumDistance - MinimumDistance));
57+
}
58+
else {
59+
return (LocalMinDistance - MinimumDistance) / (MaximumDistance - MinimumDistance);
60+
}
61+
}
62+
float UUFNSplineGenerator::GetNoise2D(float aX, float aY)
63+
{
64+
return GetNoise3D(aX, aY, 0.0f);
65+
}
66+
67+
void UUFNSplineGenerator::AddSpline(USplineComponent* Spline)
68+
{
69+
Splines.Add(Spline);
70+
//GLog->Log(FString::Printf(TEXT("Number of Splines: %d, ID %d"), Splines.Num(), GetUniqueID()));
71+
}

‎Plugins/UnrealFastNoisePlugin/Source/UnrealFastNoisePlugin/Public/UFN3SelectModule.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ class UUFN3SelectModule : public UUFNNoiseGenerator
2828
ESelectInterpType interpType;
2929
int32 numSteps;
3030

31+
private:
32+
float GetInterp2D(float aX, float aY, UUFNNoiseGenerator* input1, UUFNNoiseGenerator* input2, ESelectInterpType interpType, float alpha);
33+
float GetInterp3D(float aX, float aY, float aZ, UUFNNoiseGenerator* input1, UUFNNoiseGenerator* input2, ESelectInterpType interpType, float alpha);
3134
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include "UFNNoiseGenerator.h"
4+
#include "UFNAddModule.generated.h"
5+
6+
UCLASS()
7+
class UUFNAddModule : public UUFNNoiseGenerator
8+
{
9+
GENERATED_UCLASS_BODY()
10+
public:
11+
12+
virtual float GetNoise3D(float aX, float aY, float aZ) override;
13+
virtual float GetNoise2D(float aX, float aY) override;
14+
UPROPERTY()
15+
UUFNNoiseGenerator* inputModule1;
16+
UPROPERTY()
17+
UUFNNoiseGenerator* inputModule2;
18+
UPROPERTY()
19+
UUFNNoiseGenerator* maskModule;
20+
21+
float threshold;
22+
};

‎Plugins/UnrealFastNoisePlugin/Source/UnrealFastNoisePlugin/Public/UFNBlendModule.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ class UUFNBlendModule : public UUFNNoiseGenerator
1919
UUFNNoiseGenerator* selectModule;
2020

2121
float falloff;
22+
UPROPERTY()
23+
UCurveFloat* blendCurve;
2224

2325
};

0 commit comments

Comments
 (0)