Files
UnrealEngine/Engine/Source/Runtime/InteractiveToolsFramework/Private/ToolDataVisualizer.cpp
2025-05-18 13:04:45 +08:00

264 lines
9.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ToolDataVisualizer.h"
#include "MaterialShared.h"
#include "ToolContextInterfaces.h"
#include "PrimitiveDrawingUtils.h" // DrawCircle
#include "BaseGizmos/GizmoMath.h"
const int BoxFaces[6][4] =
{
{ 0, 1, 2, 3 }, // back, -z
{ 5, 4, 7, 6 }, // front, +z
{ 4, 0, 3, 7 }, // left, -x
{ 1, 5, 6, 2 }, // right, +x,
{ 4, 5, 1, 0 }, // bottom, -y
{ 3, 2, 6, 7 } // top, +y
};
FToolDataVisualizer::FToolDataVisualizer()
{
LineColor = FLinearColor(0.95f, 0.05f, 0.05f);
PointColor = FLinearColor(0.95f, 0.05f, 0.05f);
PopAllTransforms();
}
FToolDataVisualizer::FToolDataVisualizer(const FToolDataVisualizer&) = default;
FToolDataVisualizer::~FToolDataVisualizer() = default;
void FToolDataVisualizer::BeginFrame(IToolsContextRenderAPI* RenderAPI, const FViewCameraState& CameraStateIn)
{
checkf(CurrentPDI == nullptr, TEXT("FToolDataVisualizer::BeginFrame: matching EndFrame was not called last frame!"));
CurrentPDI = RenderAPI->GetPrimitiveDrawInterface();
CameraState = CameraStateIn;
PDISizeScale = CameraState.GetPDIScalingFactor();
bHaveCameraState = true;
}
void FToolDataVisualizer::BeginFrame(IToolsContextRenderAPI* RenderAPI)
{
checkf(CurrentPDI == nullptr, TEXT("FToolDataVisualizer::BeginFrame: matching EndFrame was not called last frame!"));
CurrentPDI = RenderAPI->GetPrimitiveDrawInterface();
CameraState = RenderAPI->GetCameraState();
PDISizeScale = CameraState.GetPDIScalingFactor();
bHaveCameraState = true;
}
void FToolDataVisualizer::EndFrame()
{
// not safe to hold PDI
CurrentPDI = nullptr;
}
void FToolDataVisualizer::SetTransform(const FTransform& Transform)
{
TransformStack.Reset();
TransformStack.Add(Transform);
TotalTransform = Transform;
}
void FToolDataVisualizer::PushTransform(const FTransform& Transform)
{
TransformStack.Add(Transform);
TotalTransform *= Transform;
}
void FToolDataVisualizer::PopTransform()
{
TransformStack.Pop(EAllowShrinking::No);
TotalTransform = FTransform::Identity;
for (const FTransform& Transform : TransformStack)
{
TotalTransform *= Transform;
}
}
void FToolDataVisualizer::PopAllTransforms()
{
TransformStack.Reset();
TotalTransform = FTransform::Identity;
}
void FToolDataVisualizer::InternalDrawTransformedLine(const FVector& A, const FVector& B, const FLinearColor& ColorIn, float LineThicknessIn, bool bDepthTestedIn)
{
CurrentPDI->DrawLine(A, B, ColorIn,
uint8( (bDepthTestedIn) ? SDPG_World : SDPG_Foreground),
LineThicknessIn * PDISizeScale, DepthBias, true);
}
void FToolDataVisualizer::InternalDrawTransformedPoint(const FVector& Position, const FLinearColor& ColorIn, float PointSizeIn, bool bDepthTestedIn)
{
CurrentPDI->DrawPoint(Position, ColorIn, PointSizeIn * PDISizeScale,
uint8( (bDepthTestedIn) ? SDPG_World : SDPG_Foreground) );
}
void FToolDataVisualizer::InternalDrawCircle(const FVector& Position, const FVector& Normal, float Radius, int Steps, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
{
FVector Tan1, Tan2;
GizmoMath::MakeNormalPlaneBasis((FVector)TransformN(Normal), Tan1, Tan2);
Tan1.Normalize(); Tan2.Normalize();
// this function is from SceneManagement.h
::DrawCircle(CurrentPDI, TransformP(Position), (FVector)Tan1, (FVector)Tan2,
Color, Radius, Steps,
uint8( (bDepthTestedIn) ? SDPG_World : SDPG_Foreground),
LineThicknessIn * PDISizeScale, DepthBias, true);
}
void FToolDataVisualizer::InternalDrawArc(const FVector& InPosition, const FVector& InNormal, const float InRadius, const int InSteps, const float InMinAngle, const float InMaxAngle, const FLinearColor& Color, float LineThicknessIn, const bool bDepthTestedIn)
{
FVector Tan1, Tan2;
GizmoMath::MakeNormalPlaneBasis(TransformN(InNormal), Tan1, Tan2);
Tan1.Normalize(); Tan2.Normalize();
// this function is from SceneManagement.h
::DrawArc(CurrentPDI, TransformP(InPosition), Tan1, Tan2,
InMinAngle, InMaxAngle,
InRadius, InSteps, Color,
static_cast<uint8>(bDepthTestedIn ? SDPG_World : SDPG_Foreground));
}
void FToolDataVisualizer::InternalDrawWireBox(const FBox& Box, const FLinearColor& ColorIn, float LineThicknessIn, bool bDepthTestedIn)
{
// corners [ (-x,-y), (x,-y), (x,y), (-x,y) ], -z, then +z
FVector Corners[8] =
{
TransformP(Box.Min),
TransformP(FVector(Box.Max.X, Box.Min.Y, Box.Min.Z)),
TransformP(FVector(Box.Max.X, Box.Max.Y, Box.Min.Z)),
TransformP(FVector(Box.Min.X, Box.Max.Y, Box.Min.Z)),
TransformP(FVector(Box.Min.X, Box.Min.Y, Box.Max.Z)),
TransformP(FVector(Box.Max.X, Box.Min.Y, Box.Max.Z)),
TransformP(Box.Max),
TransformP(FVector(Box.Min.X, Box.Max.Y, Box.Max.Z))
};
for (int FaceIdx = 0; FaceIdx < 6; FaceIdx++)
{
for (int Last = 3, Cur = 0; Cur < 4; Last = Cur++)
{
InternalDrawTransformedLine(Corners[BoxFaces[FaceIdx][Last]], Corners[BoxFaces[FaceIdx][Cur]],
ColorIn, LineThicknessIn, bDepthTestedIn);
}
}
}
void FToolDataVisualizer::InternalDrawSquare(const FVector& Center, const FVector& SideA, const FVector& SideB, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
{
FVector CC = TransformP(Center);
FVector SA = TransformV(SideA);
FVector SB = TransformV(SideB);
FVector HalfDiag = (SA + SB) * .5f;
FVector C00 = CC - HalfDiag;
FVector C11 = CC + HalfDiag;
FVector C01 = C00 + SB;
FVector C10 = C00 + SA;
InternalDrawTransformedLine(C00, C01, Color, LineThicknessIn, bDepthTestedIn);
InternalDrawTransformedLine(C01, C11, Color, LineThicknessIn, bDepthTestedIn);
InternalDrawTransformedLine(C10, C11, Color, LineThicknessIn, bDepthTestedIn);
InternalDrawTransformedLine(C00, C10, Color, LineThicknessIn, bDepthTestedIn);
}
void FToolDataVisualizer::InternalDrawWireCylinder(const FVector& Position, const FVector& Normal, float Radius, float Height, int Steps, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
{
FVector Tan1, Tan2;
GizmoMath::MakeNormalPlaneBasis(Normal, Tan1, Tan2);
const float AngleDelta = 2.0f * PI / Steps;
FVector X(Tan1), Y(Tan2);
FVector LastVertex = TransformP(Position + X * Radius);
FVector LastVertexB = TransformP(Position + X * Radius + Normal * Height);
for (int32 Step = 0; Step < Steps; Step++)
{
float Angle = (Step + 1) * AngleDelta;
FVector A = Position + (X * FMath::Cos(Angle) + Y * FMath::Sin(Angle)) * Radius;
FVector B = A + Normal * Height;
FVector Vertex = TransformP(A);
FVector VertexB = TransformP(B);
InternalDrawTransformedLine(LastVertex, Vertex, Color, LineThicknessIn, bDepthTestedIn);
InternalDrawTransformedLine(Vertex, VertexB, Color, LineThicknessIn, bDepthTestedIn);
InternalDrawTransformedLine(LastVertexB, VertexB, Color, LineThicknessIn, bDepthTestedIn);
LastVertex = Vertex;
LastVertexB = VertexB;
}
}
void FToolDataVisualizer::InternalDrawViewFacingCircle(const FVector& Position, float Radius, int Steps, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
{
checkf(bHaveCameraState, TEXT("To call this function, you must first call the version of BeginFrame that takes the CameraState"));
FVector WorldPosition = TransformP(Position);
FVector WorldNormal = (CameraState.Position - WorldPosition);
WorldNormal.Normalize();
FVector Tan1, Tan2;
GizmoMath::MakeNormalPlaneBasis(WorldNormal, Tan1, Tan2);
// this function is from SceneManagement.h
::DrawCircle(CurrentPDI, WorldPosition, (FVector)Tan1, (FVector)Tan2,
Color, Radius, Steps,
uint8( (bDepthTestedIn) ? SDPG_World : SDPG_Foreground),
LineThicknessIn * PDISizeScale, DepthBias, true);
}
void FToolDataVisualizer::InternalDrawViewFacingArc(const FVector& InPosition, const float InRadius, const int InSteps, const float InMinAngle, const float InMaxAngle, const FLinearColor& Color, float LineThicknessIn, const bool bDepthTestedIn)
{
checkf(bHaveCameraState, TEXT("To call this function, you must first call the version of BeginFrame that takes the CameraState"));
const FVector WorldPosition = TransformP(InPosition);
FVector WorldNormal = (CameraState.Position - WorldPosition);
WorldNormal.Normalize();
FVector Tan1, Tan2;
GizmoMath::MakeNormalPlaneBasis(WorldNormal, Tan1, Tan2);
// this function is from SceneManagement.h
::DrawArc(CurrentPDI, WorldPosition, Tan1, Tan2,
InMinAngle, InMaxAngle,
InRadius, InSteps, Color,
static_cast<uint8>(bDepthTestedIn ? SDPG_World : SDPG_Foreground));
}
void FToolDataVisualizer::InternalDrawViewFacingX(const FVector& Position, float Width, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
{
checkf(bHaveCameraState, TEXT("To call this function, you must first call the version of BeginFrame that takes the CameraState"));
FVector WorldPosition = TransformP(Position);
FVector UpOffset = CameraState.Up() * Width / 2;
FVector RightOffset = CameraState.Right() * Width / 2;
InternalDrawTransformedLine(
WorldPosition - UpOffset - RightOffset,
WorldPosition + UpOffset + RightOffset,
Color, LineThicknessIn, bDepthTestedIn);
InternalDrawTransformedLine(
WorldPosition + UpOffset - RightOffset,
WorldPosition - UpOffset + RightOffset,
Color, LineThicknessIn, bDepthTestedIn);
}
void FToolDataVisualizer::InternalDrawDisc(const FVector& Position, const FVector& Normal, float Radius, int Steps, const FColor& Color, FMaterialRenderProxy* RenderProxy, bool bDepthTestedIn)
{
const FVector TransformNormal = TransformN(Normal);
FVector Tan1;
FVector Tan2;
GizmoMath::MakeNormalPlaneBasis(TransformNormal, Tan1, Tan2);
Tan1.Normalize();
Tan2.Normalize();
// this function is from SceneManagement.h
const uint8 DepthPriority = uint8( (bDepthTestedIn) ? SDPG_World : SDPG_Foreground );
const FVector TransformPosition = TransformP(Position);
::DrawDisc(CurrentPDI, TransformPosition, Tan1, Tan2, Color, Radius, Steps, RenderProxy,
DepthPriority);
}