Procedural Rivers Generator - rought funtionality

This commit is contained in:
aollero 2022-03-04 14:15:44 +01:00 committed by bernat
parent 3b7675e021
commit 0edc8c3c1b
3 changed files with 253 additions and 0 deletions

View File

@ -0,0 +1,173 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see <https://opensource.org/licenses/MIT>.
#include "ProceduralWaterManager.h"
#include "Components/SplineComponent.h"
#include "FileHelpers.h"
#include "Misc/FileHelper.h"
#include "Misc/CString.h"
#include "Runtime/Engine/Public/DrawDebugHelpers.h"
#include "UnrealString.h"
#include "Actor.h"
#include "Engine/World.h"
#include "UObject/ConstructorHelpers.h"
// #define DEBUG_MSG(x, ...) if(GEngine){GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, FString::Printf(TEXT(x), __VA_ARGS__));}
// Sets default values
UProceduralWaterManager::UProceduralWaterManager()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
//PrimaryActorTick.bCanEverTick = true;
// static ConstructorHelpers::FObjectFinder<UBlueprint> DummyBlueprint(TEXT("Blueprint'/CarlaTools/ProceduralWaterManager/DummyActor.DummyActor'"));
// if (DummyBlueprint.Object){
// MyDummyBlueprint = (UClass*)DummyBlueprint.Object->GeneratedClass;
// }
static ConstructorHelpers::FObjectFinder<UBlueprint> RiverBlueprint(TEXT("Blueprint'/Game/racer-sim/Blueprints/Water/BP_River.BP_River'"));
if (RiverBlueprint.Object){
RiverBlueprintClass = (UClass*)RiverBlueprint.Object->GeneratedClass;
}
}
FString UProceduralWaterManager::StartWaterGeneration(const FProceduralRiversMetaInfo metaInfo)
{
FString errorMsg;
const FString WaterInfoPath = metaInfo.WaterInfoPath;
if(!FPlatformFileManager::Get().GetPlatformFile().FileExists(*WaterInfoPath))
{
errorMsg = "File Not Found!! :(";
DEBUG_MSG("File Not Found!! :(");
return errorMsg;
}
TArray<FString> file;
FFileHelper::LoadFileToStringArray(file, *WaterInfoPath);
TArray<FSplinePoint> riverPoints;
float inputKeyCount = 0.0f;
int iterationNumber = 0;
AActor* riverActor = nullptr;
FString x_str, y_str;
FVector previusPosition(NAN, NAN, NAN);
float scaleFactor = metaInfo.CustomScaleFactor;
FVector locationOffset(0,0,0);
for(FString line : file)
{
if(line == "# _")
{
// Important IF to add last point for every spline
// Uses data from previus iteration
if(iterationNumber != 0 && iterationNumber != -1)
{
// Add Last point to river spline
FSplinePoint location(inputKeyCount, previusPosition);
if(riverActor != nullptr)
AddRiverPointFromCode(riverActor, location); // Last Point
CheckAndReverseWaterFlow(riverActor);
}
riverActor = SpawnRiverBlueprintActor();
inputKeyCount = 0.0f;
iterationNumber = -1; // Wildcard value used for headers
}
else{
if(!line.Split(TEXT(" "), &y_str, &x_str))
{
return "Erroorrrrr";
}
float positionX = scaleFactor*FCString::Atof(*x_str);
float positionY = scaleFactor*FCString::Atof(*y_str);
float positionZ;
if(metaInfo.CustomHeight > -100000000.0f)
positionZ = metaInfo.CustomHeight;
else
positionZ = GetLandscapeSurfaceHeight(positionX, positionY, false);
FVector position(positionX, positionY, positionZ);
position += metaInfo.CustomLocationOffset;
if((iterationNumber % metaInfo.CustomSampling) == 0){
FSplinePoint newPoint(inputKeyCount, position);
newPoint.Scale = FVector(1.0f, 2.5f, 1.0f);
if(riverActor != nullptr)
AddRiverPointFromCode(riverActor, newPoint);
inputKeyCount += 1.0f;
}
previusPosition = position;
}
iterationNumber++;
}
return "Successfully processed";
}
AActor* UProceduralWaterManager::SpawnRiverBlueprintActor()
{
FVector location(0, 0, 0);
FRotator rotation(0,0,0);
FActorSpawnParameters spawnInfo;
UWorld* World = GetWorld();
AActor* riverActor = World->SpawnActor<AActor>(RiverBlueprintClass, location, rotation, spawnInfo);
return riverActor;
}
float UProceduralWaterManager::GetLandscapeSurfaceHeight(float x, float y, bool bDrawDebugLines)
{
UWorld* world = GetWorld();
if(world)
{
FVector RayStartingPoint(x, y, 999999);
FVector RayEndPoint(x, y, 0);
// Raytrace
FHitResult HitResult;
world->LineTraceSingleByObjectType(
OUT HitResult,
RayStartingPoint,
RayEndPoint,
FCollisionObjectQueryParams(ECollisionChannel::ECC_WorldStatic),
FCollisionQueryParams()
);
// Draw debug line.
if (bDrawDebugLines)
{
FColor LineColor;
if (HitResult.GetActor()) LineColor = FColor::Red;
else LineColor = FColor::Green;
DrawDebugLine(
world,
RayStartingPoint,
RayEndPoint,
LineColor,
true,
5.f,
0.f,
10.f
);
}
// Return Z location.
if (HitResult.GetActor()) return HitResult.ImpactPoint.Z;
}
return 0.0f;
}

View File

@ -0,0 +1,80 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CoreMinimal.h"
#include "Components/SplineComponent.h"
#include "EditorUtilityWidget.h"
#include "Math/Vector.h"
#include "ProceduralWaterManager.generated.h"
USTRUCT(BlueprintType)
struct CARLATOOLS_API FProceduralRiversMetaInfo
{
GENERATED_USTRUCT_BODY();
UPROPERTY(BlueprintReadWrite)
FString WaterInfoPath;
UPROPERTY(BlueprintReadWrite)
int CustomSampling;
UPROPERTY(BlueprintReadWrite)
float CustomScaleFactor;
UPROPERTY(BlueprintReadWrite)
FVector CustomLocationOffset;
UPROPERTY(BlueprintReadWrite)
float CustomHeight;
UPROPERTY(BlueprintReadWrite)
int SizeOfLandscape;
UPROPERTY(BlueprintReadWrite)
int SizeOfTexture;
};
UCLASS(BlueprintType)
class CARLATOOLS_API UProceduralWaterManager : public UEditorUtilityWidget
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
UProceduralWaterManager();
public:
/// Main function to be called from the widget to start all the generation process
/// @a metaInfo is the input data for this process
UFUNCTION(BlueprintCallable)
FString StartWaterGeneration(const FProceduralRiversMetaInfo metaInfo);
/// Add river @a riverActor spline point @a splinePoint to SplinePoint
/// collection to be added in later processes to the spline component.
/// This is implemented in blueprint code.
UFUNCTION(BlueprintImplementableEvent)
void AddRiverPointFromCode(AActor* riverActor, FSplinePoint splinePoint);
/// It checks which is the direction the flow of the river depending on the
/// altitude of the start and the end of the river @a riverActor
UFUNCTION(BlueprintImplementableEvent)
void CheckAndReverseWaterFlow(AActor* riverActor);
private:
TSubclassOf<class AActor> RiverBlueprintClass;
/// Instantiate a new actor of type RiverBlueprintClass
/// Returns the the actor created
UFUNCTION()
AActor* SpawnRiverBlueprintActor();
/// Calculates the height of the landscape in an specific 2D coordinate ( @a x, @a y)
/// throwing rays and detecting the hit point. @a bDrawDebugLines allows to visualize
/// the rays in the viewport, only for debug purposes.
/// Return the Z value
UFUNCTION()
float GetLandscapeSurfaceHeight(float x, float y, bool bDrawDebugLines = false);
};