Hello, I’m attempting to retrieve the NumWaves value from the Gerstner Water Wave Generator Simple class ( C++). My goal is to bind this value to an editable text widget. However, I’m encountering an issue where I can retrieve the value, but it doesn’t display in the widget UI. I’ve included some screenshots from the blueprints to illustrate my problem.
I succeeded in displaying the value in an editable text, although the result is not depicted in the sea. What I mean is that I can change the value but the waves of WaterBodyOcean Actor are not changing. As I understand, I need to retrieve the void FGerstnerWave::Recompute() in the blueprint.
Do anyone know how to do this? I paste all the .cpp an .h code.
GerstnerWaterWaves.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
include “GerstnerWaterWaves.h” include “Engine/Engine.h” include “GerstnerWaterWaveSubsystem.h” include “Misc/LargeWorldRenderPosition.h” include “WaterModule.h”
include UE_INLINE_GENERATED_CPP_BY_NAME(GerstnerWaterWaves)
FVector SummedNormal(ForceInitToZero);
// Use the offset of the normalized tile as world position to match the shader behavior (see GerstnerWaveFunctions.ush).
FVector WorldPosition(FLargeWorldRenderPosition(InPosition).GetOffset());
for (const FGerstnerWave& Params : GetGerstnerWaves())
{
float FirstOffset1D;
FVector FirstNormal;
FVector FirstOffset = GetWaveOffsetAtPosition(Params, WorldPosition, InTime, FirstNormal, FirstOffset1D);
// Only non-zero steepness requires a second sample.
if (Params.Q != 0)
{
//Approximate wave height by taking two samples on each side of the current sample position and lerping.
//Keep one query point fixed since sampling is going to move the points - if on the left half of wavelength, only add a right offset query point and vice-versa.
//Choose q as the factor to offset by (max horizontal displacement).
//Lerp between the two sampled heights and normals.
const float TwoPi = 2 * PI;
const float WaveTime = Params.WaveSpeed * InTime;
float Position1D = FVector2D::DotProduct(FVector2D(WorldPosition.X, WorldPosition.Y), Params.WaveVector) - WaveTime;
float MappedPosition1D = Position1D >= 0.f ? FMath::Fmod(Position1D, TwoPi) : TwoPi - FMath::Abs(FMath::Fmod(Position1D, TwoPi)); //get positive modulos from negative numbers too
FVector SecondNormal;
float SecondOffset1D;
FVector GuessOffset;
if (MappedPosition1D < PI)
{
GuessOffset = Params.Direction * Params.Q;
}
else
{
GuessOffset = -Params.Direction * Params.Q;
}
const FVector GuessPosition = WorldPosition + GuessOffset;
FVector SecondOffset = GetWaveOffsetAtPosition(Params, GuessPosition, InTime, SecondNormal, SecondOffset1D);
SecondOffset1D += (MappedPosition1D < PI) ? Params.Q : -Params.Q;
if (!(MappedPosition1D < PI))
{
Swap<FVector>(FirstOffset, SecondOffset);
Swap<float>(FirstOffset1D, SecondOffset1D);
Swap<FVector>(FirstNormal, SecondNormal);
}
const float LerpDenominator = (SecondOffset1D - FirstOffset1D);
float LerpVal = (0 - FirstOffset1D) / (LerpDenominator > 0.f ? LerpDenominator : 1.f);
const float FinalHeight = FMath::Lerp(FirstOffset.Z, SecondOffset.Z, LerpVal);
const FVector WaveNormal = FMath::Lerp(FirstNormal, SecondNormal, LerpVal);
SummedNormal += WaveNormal;
WaveHeight += FinalHeight;
}
else
{
SummedNormal += FirstNormal;
WaveHeight += FirstOffset.Z;
}
}
SummedNormal.Z = 1.0f - SummedNormal.Z;
OutNormal = SummedNormal.GetSafeNormal();
return WaveHeight;
}
float UGerstnerWaterWaves::GetSimpleWaveHeightAtPosition(const FVector& InPosition, float InWaterDepth, float InTime) const
{
float WaveHeight = 0.f;
// Use the offset of the normalized tile as world position to match the shader behavior (see GerstnerWaveFunctions.ush).
FVector WorldPosition(FLargeWorldRenderPosition(InPosition).GetOffset());
// Generate new waves if there is a generator. Make sure that the wave list has been cleared before generating new ones.
if (GerstnerWaveGenerator)
{
if (bAllowBPScript)
{
GerstnerWaveGenerator->GenerateGerstnerWaves(GerstnerWaves);
}
else
{
GerstnerWaveGenerator->GenerateGerstnerWaves_Implementation(GerstnerWaves);
}
// Automatically recompute the waves internals after waves have been regenerated :
for (FGerstnerWave& Params : GerstnerWaves)
{
Params.Recompute();
MaxWaveHeight += Params.Amplitude;
}
}
if (UGerstnerWaterWaveSubsystem* GerstnerWaterWaveSubsystem = GEngine ? GEngine->GetEngineSubsystem<UGerstnerWaterWaveSubsystem>() : nullptr)
{
GerstnerWaterWaveSubsystem->RebuildGPUData();
}
/**
Base class for the gerstner water wave generation. This can be overridden by either C++ classes or Blueprint classes.
Simply implement GenerateGerstnerWaves (or GenerateGerstnerWaves_Implementation in C++) to return the set of waves to be used. Waves will automatically be sorted based on wave length.
*/
UCLASS(EditInlineNew, BlueprintType, MinimalAPI, Abstract, Blueprintable)
class UGerstnerWaterWaveGeneratorBase : public UObject
{
GENERATED_BODY()
/**
Default implementation of a gerstner wave generator using a simple custom range based set of parameters to generate waves.
*/
UCLASS(EditInlineNew, BlueprintType, MinimalAPI, Blueprintable)
class UGerstnerWaterWaveGeneratorSimple : public UGerstnerWaterWaveGeneratorBase
{
GENERATED_BODY()
/**
Default implementation of a gerstner wave generator using known wave spectra from oceanology.
Edited using octaves, where each octave is a set of waves with 2x longer wave length than the previous octave
*/
UCLASS(EditInlineNew, BlueprintType, MinimalAPI, HideDropdown, Blueprintable)
class UGerstnerWaterWaveGeneratorSpectrum : public UGerstnerWaterWaveGeneratorBase
{
GENERATED_BODY()
UCLASS(EditInlineNew, BlueprintType, MinimalAPI, Blueprintable)
class UGerstnerWaterWaves : public UWaterWaves
{
GENERATED_BODY()
friend class UGerstnerWaterWaveSubsystem;
public:
UGerstnerWaterWaves();
/** Returns the maximum wave height that can be reached by those waves */
virtual float GetMaxWaveHeight() const override { return MaxWaveHeight; }
/** Computes the raw wave perturbation of the water height/normal */
virtual float GetWaveHeightAtPosition(const FVector& InPosition, float InWaterDepth, float InTime, FVector& OutNormal) const override;
/** Computes the raw wave perturbation of the water height only (simple version : faster computation) */
virtual float GetSimpleWaveHeightAtPosition(const FVector& InPosition, float InWaterDepth, float InTime) const override;
/** Computes the attenuation factor to apply to the raw wave perturbation. Attenuates : normal/wave height/max wave height.
Should match the GPU version (ComputeWaveDepthAttenuationFactor) */
virtual float GetWaveAttenuationFactor(const FVector& InPosition, float InWaterDepth, float InTargetWaveMaskDepth) const override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced, Category = Waves)
TObjectPtr<UGerstnerWaterWaveGeneratorBase> GerstnerWaveGenerator;
UFUNCTION(BlueprintPure, Category = "Wave")
const TArray<FGerstnerWave>& GetGerstnerWaves() const { return GerstnerWaves; }
UFUNCTION(BlueprintCallable, Category = "Wave")
void RecomputeWaves(bool bAllowBPScript);
/** Call RecomputeWaves whenever wave data changes, so that all cached data can be recomputed (do not call OnPostLoad... can call BP script internally) */
WATER_API void RecomputeWaves(bool bAllowBPScript);