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
void UBuoyancyComponent::BeginPlay()
{
Super::BeginPlay();
// ...
UStaticMeshComponent* MeshComp = Cast<UStaticMeshComponent>(GetOwner()->GetRootComponent());
VolumeMesh = MeshComp->GetStaticMesh();
VolumeAsPrimComp = Cast<UPrimitiveComponent>(MeshComp);
SubmergedTriangles = TArray<FTriangleData>();
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
ASOCGameState* State = Cast<ASOCGameState>(GetWorld()->GetGameState());
AOcean* Ocean = nullptr;
Ocean = nullptr;
if(State)
{
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)
{
FTriangleData temp(V1, V2, V3);
FTriangleData temp(V1, V2, V3, Ocean->GetOceanHeight());
Triangles.Add(temp);
FVector Center = (V1.Position + V2.Position + V3.Position) / 3.0f;
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"),
Triangles.Num(), SubmergedTriangles.Num());
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Cyan, DebugMsg);
GEngine->AddOnScreenDebugMessage(-1, -1.0f, FColor::Cyan, DebugMsg);
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);
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);
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);
}
}
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
FVector WorldSpaceVertexPos = GetOwner()->GetActorLocation() + GetOwner()->GetTransform().TransformVector(VertexBuffer->VertexPosition(idx));
FVertexData temp;
temp.Position = WorldSpaceVertexPos;
temp.GlobalPosition = WorldSpaceVertexPos;
VertexPositions.Add(temp);
}
}
@ -175,12 +189,21 @@ void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
}
else if (NumSubmergedVertices == 2)
{
FVector H = Triangle.Highest.Position;
FVector M = Triangle.Middle.Position;
FVector L = Triangle.Lowest.Position;
float hH = Triangle.Highest.Depth;
float hM = Triangle.Middle.Depth;
float hL = Triangle.Lowest.Depth;
FVertexData V1 = Triangle.V1;
FVertexData V2 = Triangle.V2;
FVertexData V3 = Triangle.V3;
TArray<FVertexData> Vertices = {V1, V2, V3};
Vertices.Sort();
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;
float tM = -hL/(hH - hL);
@ -192,17 +215,26 @@ void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
FVector LIL = tL * LH;
FVector IL = LIL + L;
SubmergedTriangles.Add(FTriangleData(IM, IL, L));
SubmergedTriangles.Add(FTriangleData(M, IM, L));
SubmergedTriangles.Add(FTriangleData(L, IL, IM, Ocean->GetOceanHeight()));
SubmergedTriangles.Add(FTriangleData(M, L, IM, Ocean->GetOceanHeight()));
}
else if (NumSubmergedVertices == 1)
{
FVector H = Triangle.Highest.Position;
FVector M = Triangle.Middle.Position;
FVector L = Triangle.Lowest.Position;
float hH = Triangle.Highest.Depth;
float hM = Triangle.Middle.Depth;
float hL = Triangle.Lowest.Depth;
FVertexData V1 = Triangle.V1;
FVertexData V2 = Triangle.V2;
FVertexData V3 = Triangle.V3;
TArray<FVertexData> Vertices = {V1, V2, V3};
Vertices.Sort();
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;
float tM = -hL/(hM - hL);
@ -214,7 +246,7 @@ void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
FVector LJH = tH * LH;
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->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"));
}

View File

@ -4,14 +4,17 @@
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Game/SOCGameState.h"
#include "BuoyancyComponent.generated.h"
USTRUCT()
USTRUCT(BlueprintType)
struct FVertexData
{
GENERATED_BODY()
FVector Position;
FVector GlobalPosition;
// depth of the vertex above the surface of the water
// negative value means the vertex is submerged
float Depth;
@ -22,19 +25,19 @@ struct FVertexData
FVertexData(FVector Position)
{
this->Position = Position;
this->GlobalPosition = Position;
Depth = 0.0f;
}
FVertexData(FVector Position, float Depth)
{
this->Position = Position;
this->GlobalPosition = Position;
this->Depth = Depth;
}
void CalculateDepth(float SurfaceHeight)
{
Depth = Position.Z - SurfaceHeight;
Depth = GlobalPosition.Z - SurfaceHeight;
}
bool operator< (const FVertexData& rhs) const
@ -43,38 +46,61 @@ struct FVertexData
}
};
USTRUCT()
USTRUCT(BlueprintType)
struct FTriangleData
{
GENERATED_BODY()
FVertexData Highest;
FVertexData Middle;
FVertexData Lowest;
FVertexData V1; // lowest
FVertexData V2; // middle
FVertexData V3; // highest
FVector Center;
float DistanceToSurface;
FVector Normal;
float Area;
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};
Vertices.Sort();
Lowest = Vertices[0];
Middle = Vertices[1];
Highest = Vertices[2];
this->V1 = V1;
this->V2 = V2;
this->V3 = V3;
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()
int32 GetNumSubmergedVertices() const
{
int32 result = 0;
if(Highest.Depth < 0.0f)
if(V3.Depth < 0.0f)
{
result++;
}
if(Middle.Depth < 0.0f)
if(V2.Depth < 0.0f)
{
result++;
}
if(Lowest.Depth < 0.0f)
if(V1.Depth < 0.0f)
{
result++;
}
@ -95,9 +121,11 @@ protected:
UPROPERTY(BlueprintReadOnly)
UStaticMesh* VolumeMesh;
UPROPERTY()
UPROPERTY(BlueprintReadOnly)
TArray<FTriangleData> SubmergedTriangles;
AOcean* Ocean;
// Called when the game starts
virtual void BeginPlay() override;
@ -106,6 +134,8 @@ public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
UPrimitiveComponent* VolumeAsPrimComp;
int32 GetNumTriangles();
TArray<FVertexData> GetVertexPositions();

View File

@ -8,7 +8,7 @@ public class SeaOfCrooks : ModuleRules
{
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[] { });