Implement hydrostatic forces

Implement hydrostatic forces
This commit is contained in:
Kevin Poretti 2021-04-20 13:29:20 -04:00
parent 607a29aa16
commit f6ecbc44e5
34 changed files with 130 additions and 130 deletions

BIN
Content/Maps/ShipTest.umap (Stored with Git LFS)

Binary file not shown.

BIN
Content/Maps/ShipTest_BuiltData.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Ships/BP_Ship.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Ships/BP_TestCube.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Ships/BP_TestShip.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Ships/Ship_Dark/_defaultMat.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Ships/Ship_Dark/iron.uasset (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Ships/Ship_Dark/window.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Ships/Ship_Dark/wood.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Ships/Ship_Dark/woodDark.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Test/TestBoat.uasset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -22,16 +22,16 @@ UBuoyancyComponent::UBuoyancyComponent()
// ... // ...
} }
// Called when the game starts // Called when the game starts
void UBuoyancyComponent::BeginPlay() void UBuoyancyComponent::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
// ...
UStaticMeshComponent* MeshComp = Cast<UStaticMeshComponent>(GetOwner()->GetRootComponent()); UStaticMeshComponent* MeshComp = Cast<UStaticMeshComponent>(GetOwner()->GetRootComponent());
VolumeMesh = MeshComp->GetStaticMesh(); VolumeMesh = MeshComp->GetStaticMesh();
VolumeAsPrimComp = Cast<UPrimitiveComponent>(MeshComp);
SubmergedTriangles = TArray<FTriangleData>(); SubmergedTriangles = TArray<FTriangleData>();
SubmergedTriangles.SetNum(GetNumTriangles(), false); SubmergedTriangles.SetNum(GetNumTriangles(), false);
} }
@ -46,7 +46,7 @@ void UBuoyancyComponent::TickComponent(float DeltaTime, ELevelTick TickType, FAc
// determine height of vertices above or below surface of water // determine height of vertices above or below surface of water
ASOCGameState* State = Cast<ASOCGameState>(GetWorld()->GetGameState()); ASOCGameState* State = Cast<ASOCGameState>(GetWorld()->GetGameState());
AOcean* Ocean = nullptr; Ocean = nullptr;
if(State) if(State)
{ {
Ocean = State->GetOcean(); Ocean = State->GetOcean();
@ -70,11 +70,10 @@ void UBuoyancyComponent::TickComponent(float DeltaTime, ELevelTick TickType, FAc
if(V1.Depth < 0.0f || V2.Depth < 0.0f || V3.Depth < 0.0f) if(V1.Depth < 0.0f || V2.Depth < 0.0f || V3.Depth < 0.0f)
{ {
FTriangleData temp(V1, V2, V3); FTriangleData temp(V1, V2, V3, Ocean->GetOceanHeight());
Triangles.Add(temp); Triangles.Add(temp);
FVector Center = (V1.Position + V2.Position + V3.Position) / 3.0f;
if(DebugBuoyancy) if(DebugBuoyancy)
DrawDebugSphere(GetWorld(), Center, 5.0f, 12, FColor::Yellow, false, 0.0f, 0, 1.0f); DrawDebugSphere(GetWorld(), temp.Center, 5.0f, 12, FColor::Yellow, false, 0.0f, 0, 1.0f);
} }
} }
@ -84,18 +83,33 @@ void UBuoyancyComponent::TickComponent(float DeltaTime, ELevelTick TickType, FAc
{ {
FString DebugMsg = FString::Printf(TEXT("Num Submerged Triangles: %d\nNum Generated Triangles: %d"), FString DebugMsg = FString::Printf(TEXT("Num Submerged Triangles: %d\nNum Generated Triangles: %d"),
Triangles.Num(), SubmergedTriangles.Num()); Triangles.Num(), SubmergedTriangles.Num());
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Cyan, DebugMsg); GEngine->AddOnScreenDebugMessage(-1, -1.0f, FColor::Cyan, DebugMsg);
for (auto Triangle : SubmergedTriangles) for (auto Triangle : SubmergedTriangles)
{ {
DrawDebugSphere(GetWorld(), Triangle.Highest.Position, 2.0f, 12, FColor::Red, DrawDebugSphere(GetWorld(), Triangle.V3.GlobalPosition, 2.0f, 12, FColor::Red,
false, 0.0f, 0, 1.0f); false, 0.0f, 0, 1.0f);
DrawDebugSphere(GetWorld(), Triangle.Middle.Position, 2.0f, 12, FColor::Red, DrawDebugSphere(GetWorld(), Triangle.V2.GlobalPosition, 2.0f, 12, FColor::Red,
false, 0.0f, 0, 1.0f); false, 0.0f, 0, 1.0f);
DrawDebugSphere(GetWorld(), Triangle.Lowest.Position, 2.0f, 12, FColor::Red, DrawDebugSphere(GetWorld(), Triangle.V1.GlobalPosition, 2.0f, 12, FColor::Red,
false, 0.0f, 0, 1.0f); false, 0.0f, 0, 1.0f);
} }
} }
if(VolumeAsPrimComp)
{
for (auto Triangle : SubmergedTriangles)
{
float rhoInKgCm3 = 0.001025f;
// F = -p*g*Hcenter*normal
FVector Force = -rhoInKgCm3 * GetWorld()->GetGravityZ() * Triangle.DistanceToSurface * Triangle.Area * Triangle.Normal;
FVector VerticalForce(0.0f, 0.0f, Force.Z);
VolumeAsPrimComp->AddForceAtLocation(VerticalForce, Triangle.Center);
}
}
FString DebugMsg = FString::Printf(TEXT("Velocity.Z: %s"), *FString::SanitizeFloat(VolumeAsPrimComp->GetPhysicsLinearVelocity().Z));
GEngine->AddOnScreenDebugMessage(-1, -1.0f, FColor::Magenta, DebugMsg);
} }
} }
@ -133,7 +147,7 @@ TArray<FVertexData> UBuoyancyComponent::GetVertexPositions()
// convert asset space vertex position to world space // convert asset space vertex position to world space
FVector WorldSpaceVertexPos = GetOwner()->GetActorLocation() + GetOwner()->GetTransform().TransformVector(VertexBuffer->VertexPosition(idx)); FVector WorldSpaceVertexPos = GetOwner()->GetActorLocation() + GetOwner()->GetTransform().TransformVector(VertexBuffer->VertexPosition(idx));
FVertexData temp; FVertexData temp;
temp.Position = WorldSpaceVertexPos; temp.GlobalPosition = WorldSpaceVertexPos;
VertexPositions.Add(temp); VertexPositions.Add(temp);
} }
} }
@ -175,12 +189,21 @@ void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
} }
else if (NumSubmergedVertices == 2) else if (NumSubmergedVertices == 2)
{ {
FVector H = Triangle.Highest.Position; FVertexData V1 = Triangle.V1;
FVector M = Triangle.Middle.Position; FVertexData V2 = Triangle.V2;
FVector L = Triangle.Lowest.Position; FVertexData V3 = Triangle.V3;
float hH = Triangle.Highest.Depth; TArray<FVertexData> Vertices = {V1, V2, V3};
float hM = Triangle.Middle.Depth; Vertices.Sort();
float hL = Triangle.Lowest.Depth; V1 = Vertices[0];
V2 = Vertices[1];
V3 = Vertices[2];
FVector H = V3.GlobalPosition;
FVector M = V2.GlobalPosition;
FVector L = V1.GlobalPosition;
float hH = V3.Depth;
float hM = V2.Depth;
float hL = V1.Depth;
FVector MH = H - M; FVector MH = H - M;
float tM = -hL/(hH - hL); float tM = -hL/(hH - hL);
@ -192,17 +215,26 @@ void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
FVector LIL = tL * LH; FVector LIL = tL * LH;
FVector IL = LIL + L; FVector IL = LIL + L;
SubmergedTriangles.Add(FTriangleData(IM, IL, L)); SubmergedTriangles.Add(FTriangleData(L, IL, IM, Ocean->GetOceanHeight()));
SubmergedTriangles.Add(FTriangleData(M, IM, L)); SubmergedTriangles.Add(FTriangleData(M, L, IM, Ocean->GetOceanHeight()));
} }
else if (NumSubmergedVertices == 1) else if (NumSubmergedVertices == 1)
{ {
FVector H = Triangle.Highest.Position; FVertexData V1 = Triangle.V1;
FVector M = Triangle.Middle.Position; FVertexData V2 = Triangle.V2;
FVector L = Triangle.Lowest.Position; FVertexData V3 = Triangle.V3;
float hH = Triangle.Highest.Depth; TArray<FVertexData> Vertices = {V1, V2, V3};
float hM = Triangle.Middle.Depth; Vertices.Sort();
float hL = Triangle.Lowest.Depth; V1 = Vertices[0];
V2 = Vertices[1];
V3 = Vertices[2];
FVector H = V3.GlobalPosition;
FVector M = V2.GlobalPosition;
FVector L = V1.GlobalPosition;
float hH = V3.Depth;
float hM = V2.Depth;
float hL = V1.Depth;
FVector LM = M - L; FVector LM = M - L;
float tM = -hL/(hM - hL); float tM = -hL/(hM - hL);
@ -214,7 +246,7 @@ void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
FVector LJH = tH * LH; FVector LJH = tH * LH;
FVector JH = LJH + L; FVector JH = LJH + L;
SubmergedTriangles.Add(FTriangleData(JH, JM, L)); SubmergedTriangles.Add(FTriangleData(L, JH, JM, Ocean->GetOceanHeight()));
} }
} }
} }

View File

@ -11,6 +11,13 @@ AShipBase::AShipBase()
ShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ShipMesh")); ShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ShipMesh"));
ShipMesh->SetupAttachment(RootComponent); ShipMesh->SetupAttachment(RootComponent);
UPrimitiveComponent* ShipMeshAsPrim = Cast<UPrimitiveComponent>(ShipMesh);
if(ShipMeshAsPrim)
{
ShipMeshAsPrim->SetSimulatePhysics(true);
ShipMeshAsPrim->SetMassOverrideInKg(NAME_None, 800.0f, true);
ShipMeshAsPrim->SetLinearDamping(0.05f);
}
BuoyancyComp = CreateDefaultSubobject<UBuoyancyComponent>(TEXT("BuoyancyComponent")); BuoyancyComp = CreateDefaultSubobject<UBuoyancyComponent>(TEXT("BuoyancyComponent"));
} }

View File

@ -4,14 +4,17 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "Game/SOCGameState.h"
#include "BuoyancyComponent.generated.h" #include "BuoyancyComponent.generated.h"
USTRUCT() USTRUCT(BlueprintType)
struct FVertexData struct FVertexData
{ {
GENERATED_BODY() GENERATED_BODY()
FVector Position; FVector GlobalPosition;
// depth of the vertex above the surface of the water // depth of the vertex above the surface of the water
// negative value means the vertex is submerged // negative value means the vertex is submerged
float Depth; float Depth;
@ -22,19 +25,19 @@ struct FVertexData
FVertexData(FVector Position) FVertexData(FVector Position)
{ {
this->Position = Position; this->GlobalPosition = Position;
Depth = 0.0f; Depth = 0.0f;
} }
FVertexData(FVector Position, float Depth) FVertexData(FVector Position, float Depth)
{ {
this->Position = Position; this->GlobalPosition = Position;
this->Depth = Depth; this->Depth = Depth;
} }
void CalculateDepth(float SurfaceHeight) void CalculateDepth(float SurfaceHeight)
{ {
Depth = Position.Z - SurfaceHeight; Depth = GlobalPosition.Z - SurfaceHeight;
} }
bool operator< (const FVertexData& rhs) const bool operator< (const FVertexData& rhs) const
@ -43,38 +46,61 @@ struct FVertexData
} }
}; };
USTRUCT() USTRUCT(BlueprintType)
struct FTriangleData struct FTriangleData
{ {
GENERATED_BODY() GENERATED_BODY()
FVertexData V1; // lowest
FVertexData V2; // middle
FVertexData V3; // highest
FVertexData Highest; FVector Center;
FVertexData Middle;
FVertexData Lowest; float DistanceToSurface;
FVector Normal;
float Area;
FTriangleData() {} FTriangleData() {}
FTriangleData(FVertexData V1, FVertexData V2, FVertexData V3) FTriangleData(const FVertexData V1, const FVertexData V2, const FVertexData V3, float OceanHeight)
{ {
TArray<FVertexData> Vertices = {V1, V2, V3}; this->V1 = V1;
Vertices.Sort(); this->V2 = V2;
Lowest = Vertices[0]; this->V3 = V3;
Middle = Vertices[1];
Highest = Vertices[2];
}
int32 GetNumSubmergedVertices() Center = (V1.GlobalPosition + V2.GlobalPosition + V3.GlobalPosition) / 3.0f;
DistanceToSurface = FMath::Abs(OceanHeight - Center.Z);
Normal = FVector::CrossProduct(V2.GlobalPosition - V1.GlobalPosition, V3.GlobalPosition - V1.GlobalPosition);
Normal.Normalize();
// Heron's formula
float V12 = FVector::Distance(V1.GlobalPosition, V2.GlobalPosition);
float V23 = FVector::Distance(V2.GlobalPosition, V3.GlobalPosition);
float V13 = FVector::Distance(V1.GlobalPosition, V3.GlobalPosition);
// Half Triangle Perimeter
float S = (V12 + V23 + V13) / 2.0f;
Area = FMath::Sqrt(S * (S - V12) * (S - V23) * (S - V13));
}
int32 GetNumSubmergedVertices() const
{ {
int32 result = 0; int32 result = 0;
if(Highest.Depth < 0.0f) if(V3.Depth < 0.0f)
{ {
result++; result++;
} }
if(Middle.Depth < 0.0f) if(V2.Depth < 0.0f)
{ {
result++; result++;
} }
if(Lowest.Depth < 0.0f) if(V1.Depth < 0.0f)
{ {
result++; result++;
} }
@ -90,13 +116,15 @@ class SEAOFCROOKS_API UBuoyancyComponent : public UActorComponent
public: public:
// Sets default values for this component's properties // Sets default values for this component's properties
UBuoyancyComponent(); UBuoyancyComponent();
protected: protected:
UPROPERTY(BlueprintReadOnly) UPROPERTY(BlueprintReadOnly)
UStaticMesh* VolumeMesh; UStaticMesh* VolumeMesh;
UPROPERTY() UPROPERTY(BlueprintReadOnly)
TArray<FTriangleData> SubmergedTriangles; TArray<FTriangleData> SubmergedTriangles;
AOcean* Ocean;
// Called when the game starts // Called when the game starts
virtual void BeginPlay() override; virtual void BeginPlay() override;
@ -106,6 +134,8 @@ public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private: private:
UPrimitiveComponent* VolumeAsPrimComp;
int32 GetNumTriangles(); int32 GetNumTriangles();
TArray<FVertexData> GetVertexPositions(); TArray<FVertexData> GetVertexPositions();

View File

@ -8,7 +8,7 @@ public class SeaOfCrooks : ModuleRules
{ {
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "RenderCore", "RHI" }); PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent", "RenderCore", "RHI" });
PrivateDependencyModuleNames.AddRange(new string[] { }); PrivateDependencyModuleNames.AddRange(new string[] { });