mirror of
https://github.com/sinbad/StevesUEHelpers.git
synced 2025-02-23 17:45:23 +00:00
Add Halton Sequence based balanced random distribution
This commit is contained in:
parent
f7c6bc20dc
commit
c7886c555c
@ -15,3 +15,8 @@ void UStevesBPL::InsertChildWidgetAt(UPanelWidget* Parent, UWidget* Child, int A
|
|||||||
{
|
{
|
||||||
StevesUiHelpers::InsertChildWidgetAt(Parent, Child, AtIndex);
|
StevesUiHelpers::InsertChildWidgetAt(Parent, Child, AtIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FStevesBalancedRandomStream UStevesBPL::MakeBalancedRandomStream(int64 Seed)
|
||||||
|
{
|
||||||
|
return FStevesBalancedRandomStream(Seed);
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
|
#include "StevesBalancedRandomStream.h"
|
||||||
|
|
||||||
#include "StevesMathHelpers.h"
|
#include "StevesMathHelpers.h"
|
||||||
#include "StevesBPL.generated.h"
|
#include "StevesBPL.generated.h"
|
||||||
@ -53,5 +54,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|UI")
|
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|UI")
|
||||||
static void InsertChildWidgetAt(UPanelWidget* Parent, UWidget* Child, int AtIndex = 0);
|
static void InsertChildWidgetAt(UPanelWidget* Parent, UWidget* Child, int AtIndex = 0);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintPure, Category="StevesUEHelpers|Random", meta=(NativeMakeFunc))
|
||||||
|
static FStevesBalancedRandomStream MakeBalancedRandomStream(int64 Seed);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|Random")
|
||||||
|
static float BalancedRandom(const FStevesBalancedRandomStream& Stream) { return Stream.Rand(); }
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|Random")
|
||||||
|
static FVector2D BalancedRandom2D(const FStevesBalancedRandomStream& Stream) { return Stream.Rand2D(); }
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|Random")
|
||||||
|
static FVector BalancedRandom3D(const FStevesBalancedRandomStream& Stream) { return Stream.Rand3D(); }
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|Random")
|
||||||
|
static FVector BalancedRandomVector(const FStevesBalancedRandomStream& Stream) { return Stream.RandUnitVector(); }
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="StevesUEHelpers|Random")
|
||||||
|
static FVector BalancedRandomPointInBox(const FStevesBalancedRandomStream& Stream, const FVector& Min, const FVector& Max) { return Stream.RandPointInBox(FBox(Min, Max)); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
165
Source/StevesUEHelpers/Public/StevesBalancedRandomStream.h
Normal file
165
Source/StevesUEHelpers/Public/StevesBalancedRandomStream.h
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||||
|
#include "Math/Halton.h"
|
||||||
|
#include "StevesBalancedRandomStream.generated.h"
|
||||||
|
|
||||||
|
/// "Balanced" random stream, using the Halton Sequence
|
||||||
|
/// This is deterministic and more uniform in appearance than a general random stream (although not perfectly uniform)
|
||||||
|
USTRUCT(BlueprintType, meta=(HasNativeMake="StevesUEHelpers.StevesBPL.MakeBalancedRandomStream"))
|
||||||
|
struct STEVESUEHELPERS_API FStevesBalancedRandomStream
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32 InitialSeed = 0;
|
||||||
|
mutable uint32 Seed = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FStevesBalancedRandomStream()
|
||||||
|
: InitialSeed(0)
|
||||||
|
, Seed(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and initializes a new random stream from the specified seed value.
|
||||||
|
*
|
||||||
|
* @param InSeed The seed value.
|
||||||
|
*/
|
||||||
|
FStevesBalancedRandomStream( int32 InSeed )
|
||||||
|
{
|
||||||
|
Initialize(InSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and initializes a new random stream from the specified name.
|
||||||
|
*
|
||||||
|
* @note If NAME_None is provided, the stream will be seeded using the current time.
|
||||||
|
* @param InName The name value from which the stream will be initialized.
|
||||||
|
*/
|
||||||
|
FStevesBalancedRandomStream( FName InName )
|
||||||
|
{
|
||||||
|
Initialize(InName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this random stream with the specified seed value.
|
||||||
|
*
|
||||||
|
* @param InSeed The seed value.
|
||||||
|
*/
|
||||||
|
void Initialize( int32 InSeed )
|
||||||
|
{
|
||||||
|
InitialSeed = InSeed;
|
||||||
|
Seed = uint32(InSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this random stream using the specified name.
|
||||||
|
*
|
||||||
|
* @note If NAME_None is provided, the stream will be seeded using the current time.
|
||||||
|
* @param InName The name value from which the stream will be initialized.
|
||||||
|
*/
|
||||||
|
void Initialize( FName InName )
|
||||||
|
{
|
||||||
|
if (InName != NAME_None)
|
||||||
|
{
|
||||||
|
InitialSeed = GetTypeHash(InName.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InitialSeed = FPlatformTime::Cycles();
|
||||||
|
}
|
||||||
|
|
||||||
|
Seed = uint32(InitialSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets this random stream to the initial seed value.
|
||||||
|
*/
|
||||||
|
void Reset() const
|
||||||
|
{
|
||||||
|
Seed = uint32(InitialSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 GetInitialSeed() const
|
||||||
|
{
|
||||||
|
return InitialSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new random seed.
|
||||||
|
*/
|
||||||
|
void GenerateNewSeed()
|
||||||
|
{
|
||||||
|
Initialize(FMath::Rand());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Return a value between 0..1, inclusive
|
||||||
|
float Rand() const
|
||||||
|
{
|
||||||
|
return Halton(Seed++, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a 2D value with each element between 0..1, inclusive
|
||||||
|
/// Use this rather than calling Rand() twice to ensure balanced distribution
|
||||||
|
FVector2D Rand2D() const
|
||||||
|
{
|
||||||
|
const FVector2D Result(
|
||||||
|
Halton(Seed, 2),
|
||||||
|
Halton(Seed, 3));
|
||||||
|
++Seed;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a 3D value with each element between 0..1, inclusive
|
||||||
|
/// Use this rather than calling Rand() twice to ensure balanced distribution
|
||||||
|
FVector Rand3D() const
|
||||||
|
{
|
||||||
|
const FVector Result(
|
||||||
|
Halton(Seed, 2),
|
||||||
|
Halton(Seed, 3),
|
||||||
|
Halton(Seed, 5));
|
||||||
|
++Seed;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random vector of unit size.
|
||||||
|
*
|
||||||
|
* @return Random unit vector.
|
||||||
|
*/
|
||||||
|
FVector RandUnitVector() const
|
||||||
|
{
|
||||||
|
const FVector2D PitchYaw = Rand2D();
|
||||||
|
return FRotator(PitchYaw.X, PitchYaw.Y, 0).RotateVector(FVector::UpVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE FVector RandPointInBox(const FBox& Box) const
|
||||||
|
{
|
||||||
|
const FVector R3 = Rand3D();
|
||||||
|
return FVector(FMath::Lerp(Box.Min.X, Box.Max.X, R3.X),
|
||||||
|
FMath::Lerp(Box.Min.Y, Box.Max.Y, R3.Y),
|
||||||
|
FMath::Lerp(Box.Min.Z, Box.Max.Z, R3.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current seed.
|
||||||
|
*
|
||||||
|
* @return Current seed.
|
||||||
|
*/
|
||||||
|
int32 GetCurrentSeed() const
|
||||||
|
{
|
||||||
|
return int32(InitialSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FString ToString() const
|
||||||
|
{
|
||||||
|
return FString::Printf(TEXT("FStevesBalancedRandomStream(InitialSeed=%i, Seed=%u)"), InitialSeed, InitialSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user