Files
UnrealEngineUWP/Engine/Source/Developer/LogVisualizer/Private/VisualLoggerRenderingActorBase.cpp
fred kimberley 7fbfaf57c8 Require explicit constructors/casts when converting between FVector, FVector3d, and FVector3f.
#jira UE-122078
#rb Andrew.Davidson, Colin.McGinley
#preflight standard build

#ROBOMERGE-AUTHOR: fred.kimberley
#ROBOMERGE-SOURCE: CL 18817999 in //UE5/Release-5.0/... via CL 18818012 via CL 18822871
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v910-18824042)

[CL 18824721 by fred kimberley in ue5-main branch]
2022-02-02 07:59:31 -05:00

523 lines
19 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "VisualLoggerRenderingActorBase.h"
#include "LogVisualizerSettings.h"
#if WITH_EDITOR
#include "GeomTools.h"
#endif // WITH_EDITOR
#include "VisualLoggerRenderingComponent.h"
#include "VisualLogger/VisualLogger.h"
namespace FDebugDrawing
{
const FVector NavOffset(0, 0, 15);
}
class UVisualLoggerRenderingComponent;
class FVisualLoggerSceneProxy final : public FDebugRenderSceneProxy
{
public:
virtual SIZE_T GetTypeHash() const override
{
static size_t UniquePointer;
return reinterpret_cast<size_t>(&UniquePointer);
}
FVisualLoggerSceneProxy(const UVisualLoggerRenderingComponent* InComponent)
: FDebugRenderSceneProxy(InComponent)
{
DrawType = SolidAndWireMeshes;
ViewFlagName = TEXT("VisLog");
ViewFlagIndex = uint32(FEngineShowFlags::FindIndexByName(*ViewFlagName));
bWantsSelectionOutline = false;
}
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View);
Result.bDynamicRelevance = true;
// ideally the TranslucencyRelevance should be filled out by the material, here we do it conservative
Result.bSeparateTranslucency = Result.bNormalTranslucency = IsShown(View) && GIsEditor;
return Result;
}
virtual uint32 GetMemoryFootprint(void) const override { return sizeof(*this) + GetAllocatedSize(); }
};
UVisualLoggerRenderingComponent::UVisualLoggerRenderingComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
}
FDebugRenderSceneProxy* UVisualLoggerRenderingComponent::CreateDebugSceneProxy()
{
AVisualLoggerRenderingActorBase* RenderingActor = Cast<AVisualLoggerRenderingActorBase>(GetOuter());
if (RenderingActor == nullptr)
{
return nullptr;
}
ULogVisualizerSettings *Settings = ULogVisualizerSettings::StaticClass()->GetDefaultObject<ULogVisualizerSettings>();
FVisualLoggerSceneProxy *VLogSceneProxy = new FVisualLoggerSceneProxy(this);
VLogSceneProxy->SolidMeshMaterial = Settings->GetDebugMeshMaterial();
RenderingActor->IterateDebugShapes([VLogSceneProxy] (const AVisualLoggerRenderingActorBase::FTimelineDebugShapes& Shapes)
{
VLogSceneProxy->Spheres.Append(Shapes.Points);
VLogSceneProxy->Lines.Append(Shapes.Lines);
VLogSceneProxy->Boxes.Append(Shapes.Boxes);
VLogSceneProxy->Meshes.Append(Shapes.Meshes);
VLogSceneProxy->Cones.Append(Shapes.Cones);
VLogSceneProxy->Texts.Append(Shapes.Texts);
VLogSceneProxy->Cylinders.Append(Shapes.Cylinders);
VLogSceneProxy->ArrowLines.Append(Shapes.Arrows);
VLogSceneProxy->Capsules.Append(Shapes.Capsules);
});
return VLogSceneProxy;
}
FBoxSphereBounds UVisualLoggerRenderingComponent::CalcBounds(const FTransform& LocalToWorld) const
{
FBox MyBounds;
MyBounds.Init();
MyBounds = FBox(FVector(-HALF_WORLD_MAX, -HALF_WORLD_MAX, -HALF_WORLD_MAX), FVector(HALF_WORLD_MAX, HALF_WORLD_MAX, HALF_WORLD_MAX));
return MyBounds;
}
AVisualLoggerRenderingActorBase::AVisualLoggerRenderingActorBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
USceneComponent* SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp"));
RootComponent = SceneComponent;
RenderingComponent = CreateDefaultSubobject<UVisualLoggerRenderingComponent>(TEXT("RenderingComponent"));
}
AVisualLoggerRenderingActorBase::~AVisualLoggerRenderingActorBase()
{
}
namespace
{
static bool IsPolygonWindingCorrect(const TArray<FVector>& Verts)
{
// this will work only for convex polys, but we're assuming that all logged polygons are convex in the first place
if (Verts.Num() >= 3)
{
const FVector SurfaceNormal = FVector::CrossProduct(Verts[1] - Verts[0], Verts[2] - Verts[0]);
const float TestDot = FVector::DotProduct(SurfaceNormal, FVector(0, 0, 1));
return TestDot > 0;
}
return false;
}
static void GetPolygonMesh(const FVisualLogShapeElement* ElementToDraw, FDebugRenderSceneProxy::FMesh& TestMesh, const FVector3f& VertexOffset = FVector3f::ZeroVector)
{
TestMesh.Color = ElementToDraw->GetFColor();
FClipSMPolygon InPoly(ElementToDraw->Points.Num());
InPoly.FaceNormal = FVector(0, 0, 1);
const bool bHasCorrectWinding = IsPolygonWindingCorrect(ElementToDraw->Points);
if (bHasCorrectWinding)
{
for (int32 Index = 0; Index < ElementToDraw->Points.Num(); Index++)
{
FClipSMVertex v1;
v1.Pos = (FVector3f)ElementToDraw->Points[Index];
InPoly.Vertices.Add(v1);
}
}
else
{
for (int32 Index = ElementToDraw->Points.Num() - 1; Index >= 0; Index--)
{
FClipSMVertex v1;
v1.Pos = (FVector3f)ElementToDraw->Points[Index];
InPoly.Vertices.Add(v1);
}
}
TArray<FClipSMTriangle> OutTris;
const bool bTriangulated = FGeomTools::TriangulatePoly(OutTris, InPoly, false);
if (bTriangulated)
{
int32 LastIndex = 0;
FGeomTools::RemoveRedundantTriangles(OutTris);
for (const auto& CurrentTri : OutTris)
{
TestMesh.Vertices.Add(FDynamicMeshVertex(CurrentTri.Vertices[0].Pos + VertexOffset));
TestMesh.Vertices.Add(FDynamicMeshVertex(CurrentTri.Vertices[1].Pos + VertexOffset));
TestMesh.Vertices.Add(FDynamicMeshVertex(CurrentTri.Vertices[2].Pos + VertexOffset));
TestMesh.Indices.Add(LastIndex++);
TestMesh.Indices.Add(LastIndex++);
TestMesh.Indices.Add(LastIndex++);
}
}
}
}
void AVisualLoggerRenderingActorBase::GetDebugShapes(const FVisualLogEntry& InEntry, bool bAddEntryLocationPointer, AVisualLoggerRenderingActorBase::FTimelineDebugShapes& DebugShapes)
{
const FVisualLogEntry* Entry = &InEntry;
const FVisualLogShapeElement* ElementToDraw = Entry->ElementsToDraw.GetData();
const int32 ElementsCount = Entry->ElementsToDraw.Num();
if (bAddEntryLocationPointer)
{
constexpr float Length = 100;
const FVector DirectionNorm = FVector(0, 0, 1).GetSafeNormal();
FVector YAxis, ZAxis;
DirectionNorm.FindBestAxisVectors(YAxis, ZAxis);
DebugShapes.Cones.Add(FDebugRenderSceneProxy::FCone(FScaleMatrix(FVector(Length)) * FMatrix(DirectionNorm, YAxis, ZAxis, Entry->Location), 5, 5, FColor::Red));
}
if (DebugShapes.LogEntriesPath.Num())
{
FVector Location = DebugShapes.LogEntriesPath[0];
for (int32 Index = 1; Index < DebugShapes.LogEntriesPath.Num(); ++Index)
{
const FVector CurrentLocation = DebugShapes.LogEntriesPath[Index];
DebugShapes.Lines.Add(FDebugRenderSceneProxy::FDebugLine(Location, CurrentLocation, FColor(160, 160, 240), 2.0));
Location = CurrentLocation;
}
}
for (int32 ElementIndex = 0; ElementIndex < ElementsCount; ++ElementIndex, ++ElementToDraw)
{
if (!FVisualLoggerFilters::Get().MatchCategoryFilters(ElementToDraw->Category.ToString(), ElementToDraw->Verbosity))
{
continue;
}
const FVector3f CorridorOffset = (FVector3f)FDebugDrawing::NavOffset * 1.25f;
const FColor Color = ElementToDraw->GetFColor();
switch (ElementToDraw->GetType())
{
case EVisualLoggerShapeElement::SinglePoint:
{
const float Radius = float(ElementToDraw->Radius);
const bool bDrawLabel = (ElementToDraw->Description.IsEmpty() == false);
const int32 NumPoints = ElementToDraw->Points.Num();
for (int32 Index = 0; Index < NumPoints; ++Index)
{
const FVector& Point = ElementToDraw->Points[Index];
DebugShapes.Points.Add(FDebugRenderSceneProxy::FSphere(Radius, Point, Color));
if (bDrawLabel)
{
const FString PrintString = NumPoints == 1 ? ElementToDraw->Description : FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index);
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(PrintString, Point, Color));
}
}
}
break;
case EVisualLoggerShapeElement::Polygon:
{
FDebugRenderSceneProxy::FMesh TestMesh;
GetPolygonMesh(ElementToDraw, TestMesh, CorridorOffset);
DebugShapes.Meshes.Add(TestMesh);
for (int32 VIdx = 0; VIdx < ElementToDraw->Points.Num(); VIdx++)
{
DebugShapes.Lines.Add(FDebugRenderSceneProxy::FDebugLine(
ElementToDraw->Points[VIdx] + (FVector)CorridorOffset,
ElementToDraw->Points[(VIdx + 1) % ElementToDraw->Points.Num()] + (FVector)CorridorOffset,
FColor::Cyan,
2)
);
}
}
break;
case EVisualLoggerShapeElement::Mesh:
{
struct FHeaderData
{
float VerticesNum, FacesNum;
FHeaderData(const FVector& InVector) : VerticesNum(InVector.X), FacesNum(InVector.Y) {}
};
const FHeaderData HeaderData(ElementToDraw->Points[0]);
FDebugRenderSceneProxy::FMesh TestMesh;
TestMesh.Color = ElementToDraw->GetFColor();
int32 StartIndex = 1;
int32 EndIndex = StartIndex + HeaderData.VerticesNum;
for (int32 VIdx = StartIndex; VIdx < EndIndex; VIdx++)
{
TestMesh.Vertices.Add(FVector3f(ElementToDraw->Points[VIdx]));
}
StartIndex = EndIndex;
EndIndex = StartIndex + HeaderData.FacesNum;
for (int32 VIdx = StartIndex; VIdx < EndIndex; VIdx++)
{
const FVector &CurrentFace = ElementToDraw->Points[VIdx];
TestMesh.Indices.Add(CurrentFace.X);
TestMesh.Indices.Add(CurrentFace.Y);
TestMesh.Indices.Add(CurrentFace.Z);
}
DebugShapes.Meshes.Add(TestMesh);
}
break;
case EVisualLoggerShapeElement::Segment:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = (ElementToDraw->Description.IsEmpty() == false);
const FVector* Location = ElementToDraw->Points.GetData();
const int32 NumPoints = ElementToDraw->Points.Num();
for (int32 Index = 0; Index + 1 < NumPoints; Index += 2, Location += 2)
{
DebugShapes.Lines.Add(FDebugRenderSceneProxy::FDebugLine(*Location, *(Location + 1), Color, Thickness));
if (bDrawLabel)
{
const FString PrintString = NumPoints == 2 ? ElementToDraw->Description : FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index / 2);
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(PrintString, (*Location + (*(Location + 1) - *Location) / 2), Color));
}
}
}
break;
case EVisualLoggerShapeElement::Path:
{
const float Thickness = float(ElementToDraw->Thicknes);
FVector Location = ElementToDraw->Points[0];
for (int32 Index = 1; Index < ElementToDraw->Points.Num(); ++Index)
{
const FVector CurrentLocation = ElementToDraw->Points[Index];
DebugShapes.Lines.Add(FDebugRenderSceneProxy::FDebugLine(Location, CurrentLocation, Color, Thickness));
Location = CurrentLocation;
}
}
break;
case EVisualLoggerShapeElement::Box:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = (ElementToDraw->Description.IsEmpty() == false);
const FVector* BoxExtent = ElementToDraw->Points.GetData();
const int32 NumPoints = ElementToDraw->Points.Num();
for (int32 Index = 0; Index + 1 < NumPoints; Index += 2, BoxExtent += 2)
{
const FBox Box = FBox(*BoxExtent, *(BoxExtent + 1));
DebugShapes.Boxes.Add(FDebugRenderSceneProxy::FDebugBox(Box, Color, FTransform(ElementToDraw->TransformationMatrix)));
if (bDrawLabel)
{
const FString PrintString = NumPoints == 2 ? ElementToDraw->Description : FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index / 2);
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(PrintString, Box.GetCenter(), Color));
}
}
}
break;
case EVisualLoggerShapeElement::Cone:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = ElementToDraw->Description.IsEmpty() == false;
for (int32 Index = 0; Index + 2 < ElementToDraw->Points.Num(); Index += 3)
{
const FVector Origin = ElementToDraw->Points[Index];
const FVector Direction = ElementToDraw->Points[Index + 1].GetSafeNormal();
const FVector Angles = ElementToDraw->Points[Index + 2];
const float Length = Angles.X;
FVector YAxis, ZAxis;
Direction.FindBestAxisVectors(YAxis, ZAxis);
DebugShapes.Cones.Add(FDebugRenderSceneProxy::FCone(FScaleMatrix(FVector(Length)) * FMatrix(Direction, YAxis, ZAxis, Origin), Angles.Y, Angles.Z, Color));
if (bDrawLabel)
{
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(ElementToDraw->Description, Origin, Color));
}
}
}
break;
case EVisualLoggerShapeElement::Cylinder:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = ElementToDraw->Description.IsEmpty() == false;
for (int32 Index = 0; Index + 2 < ElementToDraw->Points.Num(); Index += 3)
{
const FVector Start = ElementToDraw->Points[Index];
const FVector End = ElementToDraw->Points[Index + 1];
const FVector OtherData = ElementToDraw->Points[Index + 2];
const float HalfHeight = 0.5f * (End - Start).Size();
const FVector Center = 0.5f * (Start + End);
DebugShapes.Cylinders.Add(FDebugRenderSceneProxy::FWireCylinder(Center, OtherData.X, HalfHeight, Color)); // Base parameter is the center of the cylinder
if (bDrawLabel)
{
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(ElementToDraw->Description, Center, Color));
}
}
}
break;
case EVisualLoggerShapeElement::Capsule:
{
const float Thickness = float(ElementToDraw->Thicknes);
const bool bDrawLabel = ElementToDraw->Description.IsEmpty() == false;
for (int32 Index = 0; Index + 2 < ElementToDraw->Points.Num(); Index += 3)
{
const FVector Base = ElementToDraw->Points[Index + 0];
const FVector FirstData = ElementToDraw->Points[Index + 1];
const FVector SecondData = ElementToDraw->Points[Index + 2];
const float HalfHeight = FirstData.X;
const float Radius = FirstData.Y;
const FQuat Rotation = FQuat(FirstData.Z, SecondData.X, SecondData.Y, SecondData.Z);
const FMatrix Axes = FQuatRotationTranslationMatrix(Rotation, FVector::ZeroVector);
const FVector XAxis = Axes.GetScaledAxis(EAxis::X);
const FVector YAxis = Axes.GetScaledAxis(EAxis::Y);
const FVector ZAxis = Axes.GetScaledAxis(EAxis::Z);
DebugShapes.Capsules.Add(FDebugRenderSceneProxy::FCapsule(Base, Radius, XAxis, YAxis, ZAxis, HalfHeight, Color));
if (bDrawLabel)
{
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(ElementToDraw->Description, Base + HalfHeight * FVector::UpVector, Color));
}
}
}
break;
case EVisualLoggerShapeElement::NavAreaMesh:
{
if (ElementToDraw->Points.Num() == 0)
{
continue;
}
struct FHeaderData
{
float MinZ, MaxZ;
FHeaderData(const FVector& InVector) : MinZ(InVector.X), MaxZ(InVector.Y) {}
};
const FHeaderData HeaderData(ElementToDraw->Points[0]);
TArray<FVector> AreaMeshPoints = ElementToDraw->Points;
AreaMeshPoints.RemoveAt(0, 1, false);
AreaMeshPoints.Add(ElementToDraw->Points[1]);
TArray<FVector> Vertices;
TNavStatArray<FVector> Faces;
int32 CurrentIndex = 0;
FDebugRenderSceneProxy::FMesh TestMesh;
TestMesh.Color = ElementToDraw->GetFColor();
for (int32 PointIndex = 0; PointIndex < AreaMeshPoints.Num() - 1; PointIndex++)
{
FVector Point = AreaMeshPoints[PointIndex];
FVector NextPoint = AreaMeshPoints[PointIndex + 1];
FVector3f P1(Point.X, Point.Y, HeaderData.MinZ);
FVector3f P2(Point.X, Point.Y, HeaderData.MaxZ);
FVector3f P3(NextPoint.X, NextPoint.Y, HeaderData.MinZ);
FVector3f P4(NextPoint.X, NextPoint.Y, HeaderData.MaxZ);
TestMesh.Vertices.Add(P1); TestMesh.Vertices.Add(P2); TestMesh.Vertices.Add(P3);
TestMesh.Indices.Add(CurrentIndex + 0);
TestMesh.Indices.Add(CurrentIndex + 1);
TestMesh.Indices.Add(CurrentIndex + 2);
CurrentIndex += 3;
TestMesh.Vertices.Add(P3); TestMesh.Vertices.Add(P2); TestMesh.Vertices.Add(P4);
TestMesh.Indices.Add(CurrentIndex + 0);
TestMesh.Indices.Add(CurrentIndex + 1);
TestMesh.Indices.Add(CurrentIndex + 2);
CurrentIndex += 3;
}
DebugShapes.Meshes.Add(TestMesh);
{
FDebugRenderSceneProxy::FMesh PolygonMesh;
FVisualLogShapeElement PolygonToDraw(EVisualLoggerShapeElement::Polygon);
PolygonToDraw.SetColor(ElementToDraw->GetFColor());
PolygonToDraw.Points.Reserve(AreaMeshPoints.Num());
PolygonToDraw.Points = AreaMeshPoints;
GetPolygonMesh(&PolygonToDraw, PolygonMesh, FVector3f(0, 0, HeaderData.MaxZ));
DebugShapes.Meshes.Add(PolygonMesh);
}
for (int32 VIdx = 0; VIdx < AreaMeshPoints.Num(); VIdx++)
{
DebugShapes.Lines.Add(FDebugRenderSceneProxy::FDebugLine(
AreaMeshPoints[VIdx] + FVector(0, 0, HeaderData.MaxZ),
AreaMeshPoints[(VIdx + 1) % AreaMeshPoints.Num()] + FVector(0, 0, HeaderData.MaxZ),
ElementToDraw->GetFColor(),
2)
);
}
}
break;
case EVisualLoggerShapeElement::Arrow:
{
const bool bDrawLabel = (ElementToDraw->Description.IsEmpty() == false);
const FVector* Location = ElementToDraw->Points.GetData();
const int32 NumPoints = ElementToDraw->Points.Num();
for (int32 Index = 0; Index + 1 < NumPoints; Index += 2, Location += 2)
{
DebugShapes.Arrows.Add(FDebugRenderSceneProxy::FArrowLine(*Location, *(Location + 1), Color));
if (bDrawLabel)
{
const FString PrintString = NumPoints == 2 ? ElementToDraw->Description : FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index / 2);
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(PrintString, (*Location + (*(Location + 1) - *Location) / 2), Color));
}
}
}
break;
case EVisualLoggerShapeElement::Circle:
{
const bool bDrawLabel = (ElementToDraw->Description.IsEmpty() == false);
const int32 NumPoints = ElementToDraw->Points.Num();
for (int32 Index = 0; Index + 2 < NumPoints; Index += 3)
{
const FVector Center = ElementToDraw->Points[Index + 0];
const FVector UpAxis = ElementToDraw->Points[Index + 1];
const float Radius = ElementToDraw->Points[Index + 2].X;
const float Thickness = float(ElementToDraw->Thicknes);
const FQuat Rotation = FQuat::FindBetweenNormals(FVector::UpVector, UpAxis);
const FVector XAxis = Rotation.RotateVector(FVector::XAxisVector);
const FVector YAxis = Rotation.RotateVector(FVector::YAxisVector);
static constexpr int32 CircleDivs = 12;
FVector PrevPosition = FVector::ZeroVector;
for (int32 Div = 0; Div <= CircleDivs; Div++)
{
const float Angle = (float)Div / (float)CircleDivs * PI * 2.0f;
const FVector Position = Center + (FMath::Cos(Angle) * XAxis + FMath::Sin(Angle) * YAxis) * Radius;
if (Div > 0)
{
DebugShapes.Lines.Add(FDebugRenderSceneProxy::FDebugLine(PrevPosition, Position, Color, Thickness));
}
PrevPosition = Position;
}
if (bDrawLabel)
{
const FString PrintString = NumPoints == 3 ? ElementToDraw->Description : FString::Printf(TEXT("%s_%d"), *ElementToDraw->Description, Index / 3);
DebugShapes.Texts.Add(FDebugRenderSceneProxy::FText3d(PrintString, Center, Color));
}
}
}
break;
case EVisualLoggerShapeElement::Invalid:
UE_LOG(LogVisual, Warning, TEXT("Invalid element type"));
break;
default:
UE_LOG(LogVisual, Warning, TEXT("Unhandled element type: %s"), ElementToDraw->GetType());
}
}
}