SeaOfCrooks/Source/SeaOfCrooks/Private/Components/BuoyancyComponent.cpp
Kevin f6ecbc44e5 Implement hydrostatic forces
Implement hydrostatic forces
2021-04-20 13:29:20 -04:00

256 lines
7.0 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "Components/BuoyancyComponent.h"
#include "DrawDebugHelpers.h"
#include "StaticMeshResources.h"
#include "Game/SOCGameState.h"
static int32 DebugBuoyancy = 0;
FAutoConsoleVariableRef CVARDebugProtagonistDrawing(TEXT("SOC.DebugBuoyancy"),
DebugBuoyancy,
TEXT("Print debug information about buoyancy component"),
ECVF_Cheat);
// Sets default values for this component's properties
UBuoyancyComponent::UBuoyancyComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
// ...
}
// 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);
}
// Called every frame
void UBuoyancyComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
SubmergedTriangles.Empty();
// determine height of vertices above or below surface of water
ASOCGameState* State = Cast<ASOCGameState>(GetWorld()->GetGameState());
Ocean = nullptr;
if(State)
{
Ocean = State->GetOcean();
}
if(Ocean)
{
TArray<FVertexData> Vertices = GetVertexPositions();
for(int idx = 0; idx < Vertices.Num(); idx++)
{
Vertices[idx].CalculateDepth(Ocean->GetOceanHeight());
}
TArray<int32> Indices = GetTriangleIndices();
TArray<FTriangleData> Triangles;
for(int idx = 0; idx < Indices.Num(); idx += 3)
{
FVertexData V1 = Vertices[Indices[idx]];
FVertexData V2 = Vertices[Indices[idx + 1]];
FVertexData V3 = Vertices[Indices[idx + 2]];
if(V1.Depth < 0.0f || V2.Depth < 0.0f || V3.Depth < 0.0f)
{
FTriangleData temp(V1, V2, V3, Ocean->GetOceanHeight());
Triangles.Add(temp);
if(DebugBuoyancy)
DrawDebugSphere(GetWorld(), temp.Center, 5.0f, 12, FColor::Yellow, false, 0.0f, 0, 1.0f);
}
}
ProcessTriangles(Triangles);
if(DebugBuoyancy)
{
FString DebugMsg = FString::Printf(TEXT("Num Submerged Triangles: %d\nNum Generated Triangles: %d"),
Triangles.Num(), SubmergedTriangles.Num());
GEngine->AddOnScreenDebugMessage(-1, -1.0f, FColor::Cyan, DebugMsg);
for (auto Triangle : SubmergedTriangles)
{
DrawDebugSphere(GetWorld(), Triangle.V3.GlobalPosition, 2.0f, 12, FColor::Red,
false, 0.0f, 0, 1.0f);
DrawDebugSphere(GetWorld(), Triangle.V2.GlobalPosition, 2.0f, 12, FColor::Red,
false, 0.0f, 0, 1.0f);
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);
}
}
int32 UBuoyancyComponent::GetNumTriangles()
{
int32 result = 0;
if(!VolumeMesh || !VolumeMesh->RenderData)
{
return result;
}
if(VolumeMesh->RenderData->LODResources.Num() > 0)
{
result = VolumeMesh->RenderData->LODResources[0].GetNumTriangles();
}
return result;
}
TArray<FVertexData> UBuoyancyComponent::GetVertexPositions()
{
TArray<FVertexData> VertexPositions = TArray<FVertexData>();
if(!VolumeMesh || !VolumeMesh->RenderData)
{
return VertexPositions;
}
if(VolumeMesh->RenderData->LODResources.Num() > 0)
{
FPositionVertexBuffer* VertexBuffer = &VolumeMesh->RenderData->LODResources[0].VertexBuffers.PositionVertexBuffer;
if(VertexBuffer)
{
for(uint32 idx = 0; idx < VertexBuffer->GetNumVertices(); idx++)
{
// convert asset space vertex position to world space
FVector WorldSpaceVertexPos = GetOwner()->GetActorLocation() + GetOwner()->GetTransform().TransformVector(VertexBuffer->VertexPosition(idx));
FVertexData temp;
temp.GlobalPosition = WorldSpaceVertexPos;
VertexPositions.Add(temp);
}
}
}
return VertexPositions;
}
TArray<int32> UBuoyancyComponent::GetTriangleIndices()
{
TArray<int32> Indices = TArray<int32>();
if(!VolumeMesh || !VolumeMesh->RenderData) // return empty array
{
return Indices;
}
if(VolumeMesh->RenderData->LODResources.Num() > 0)
{
FRawStaticIndexBuffer* IndexBuffer = &VolumeMesh->RenderData->LODResources[0].IndexBuffer;
if(IndexBuffer)
{
for(int idx = 0; idx < IndexBuffer->GetNumIndices(); idx++)
{
Indices.Add(IndexBuffer->GetIndex(idx));
}
}
}
return Indices;
}
void UBuoyancyComponent::ProcessTriangles(TArray<FTriangleData>& Triangles)
{
for (auto Triangle : Triangles)
{
int32 NumSubmergedVertices = Triangle.GetNumSubmergedVertices();
if(NumSubmergedVertices == 3) // completely submerged so add as is
{
SubmergedTriangles.Add(Triangle);
}
else if (NumSubmergedVertices == 2)
{
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);
FVector MIM = tM * MH;
FVector IM = MIM + M;
FVector LH = H - L;
float tL = -hL/(hH - hL);
FVector LIL = tL * LH;
FVector IL = LIL + L;
SubmergedTriangles.Add(FTriangleData(L, IL, IM, Ocean->GetOceanHeight()));
SubmergedTriangles.Add(FTriangleData(M, L, IM, Ocean->GetOceanHeight()));
}
else if (NumSubmergedVertices == 1)
{
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);
FVector LJM = tM * LM;
FVector JM = LJM + L;
FVector LH = H - L;
float tH = -hL/(hH - hL);
FVector LJH = tH * LH;
FVector JH = LJH + L;
SubmergedTriangles.Add(FTriangleData(L, JH, JM, Ocean->GetOceanHeight()));
}
}
}