156 lines
4.8 KiB
C++
156 lines
4.8 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "BaseGizmos/GizmoElementCircle.h"
|
|
#include "BaseGizmos/GizmoRenderingUtil.h"
|
|
#include "BaseGizmos/GizmoMath.h"
|
|
#include "InputState.h"
|
|
#include "Intersection/IntersectionUtil.h"
|
|
#include "Materials/MaterialInterface.h"
|
|
#include "PrimitiveDrawingUtils.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(GizmoElementCircle)
|
|
|
|
void UGizmoElementCircle::Render(IToolsContextRenderAPI* RenderAPI, const FRenderTraversalState& RenderState)
|
|
{
|
|
FRenderTraversalState CurrentRenderState(RenderState);
|
|
bool bVisibleViewDependent = UpdateRenderState(RenderAPI, Center, CurrentRenderState);
|
|
|
|
if (bVisibleViewDependent)
|
|
{
|
|
const double WorldRadius = Radius * CurrentRenderState.LocalToWorldTransform.GetScale3D().X;
|
|
const FVector WorldCenter = CurrentRenderState.LocalToWorldTransform.TransformPosition(FVector::ZeroVector);
|
|
const FVector WorldAxis0 = CurrentRenderState.LocalToWorldTransform.TransformVectorNoScale(Axis0);
|
|
const FVector WorldAxis1 = CurrentRenderState.LocalToWorldTransform.TransformVectorNoScale(Axis1);
|
|
|
|
FPrimitiveDrawInterface* PDI = RenderAPI->GetPrimitiveDrawInterface();
|
|
|
|
if (bDrawMesh)
|
|
{
|
|
if (const UMaterialInterface* UseMaterial = CurrentRenderState.GetCurrentMaterial())
|
|
{
|
|
FColor VertexColor = CurrentRenderState.GetCurrentVertexColor().ToFColor(false);
|
|
DrawDisc(PDI, WorldCenter, WorldAxis0, WorldAxis1, VertexColor, WorldRadius, NumSegments, UseMaterial->GetRenderProxy(), SDPG_Foreground);
|
|
}
|
|
}
|
|
|
|
if (bDrawLine)
|
|
{
|
|
check(RenderAPI);
|
|
const FSceneView* View = RenderAPI->GetSceneView();
|
|
check(View);
|
|
float CurrentLineThickness = GetCurrentLineThickness(View->IsPerspectiveProjection(), View->FOV);
|
|
|
|
DrawCircle(PDI, WorldCenter, WorldAxis0, WorldAxis1, CurrentRenderState.GetCurrentLineColor(), WorldRadius, NumSegments, SDPG_Foreground, CurrentLineThickness, 0.0, bScreenSpaceLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
FInputRayHit UGizmoElementCircle::LineTrace(const UGizmoViewContext* ViewContext, const FLineTraceTraversalState& LineTraceState, const FVector& RayOrigin, const FVector& RayDirection)
|
|
{
|
|
FLineTraceTraversalState CurrentLineTraceState(LineTraceState);
|
|
bool bHittableViewDependent = UpdateLineTraceState(ViewContext, Center, CurrentLineTraceState);
|
|
|
|
if (bHittableViewDependent)
|
|
{
|
|
const FVector WorldCenter = CurrentLineTraceState.LocalToWorldTransform.GetLocation();
|
|
const FVector WorldAxis0 = CurrentLineTraceState.LocalToWorldTransform.TransformVectorNoScale(Axis0);
|
|
const FVector WorldAxis1 = CurrentLineTraceState.LocalToWorldTransform.TransformVectorNoScale(Axis1);
|
|
const FVector WorldNormal = WorldAxis0 ^ WorldAxis1;
|
|
const double PixelHitThresholdAdjust = CurrentLineTraceState.PixelToWorldScale * PixelHitDistanceThreshold;
|
|
double WorldRadius = CurrentLineTraceState.LocalToWorldTransform.GetScale3D().X * Radius;
|
|
|
|
// if ray is parallel to circle, no hit
|
|
if (FMath::IsNearlyZero(FVector::DotProduct(WorldNormal, RayDirection)))
|
|
{
|
|
return FInputRayHit();
|
|
}
|
|
|
|
if (bHitMesh)
|
|
{
|
|
WorldRadius += PixelHitThresholdAdjust;
|
|
|
|
UE::Geometry::FLinearIntersection Result;
|
|
IntersectionUtil::RayCircleIntersection(RayOrigin, RayDirection, WorldCenter, WorldRadius, WorldNormal, Result);
|
|
|
|
if (Result.intersects)
|
|
{
|
|
FInputRayHit RayHit(static_cast<float>(Result.parameter.Min));
|
|
RayHit.SetHitObject(this);
|
|
RayHit.HitIdentifier = PartIdentifier;
|
|
return RayHit;
|
|
}
|
|
}
|
|
else if (bHitLine)
|
|
{
|
|
FPlane Plane(WorldCenter, WorldNormal);
|
|
double HitDepth = FMath::RayPlaneIntersectionParam(RayOrigin, RayDirection, Plane);
|
|
if (HitDepth < 0)
|
|
{
|
|
return FInputRayHit();
|
|
}
|
|
|
|
FVector HitPoint = RayOrigin + RayDirection * HitDepth;
|
|
|
|
FVector NearestCirclePos;
|
|
GizmoMath::ClosetPointOnCircle(HitPoint, WorldCenter, WorldNormal, static_cast<float>(WorldRadius), NearestCirclePos);
|
|
|
|
FRay Ray(RayOrigin, RayDirection, true);
|
|
FVector NearestRayPos = Ray.ClosestPoint(NearestCirclePos);
|
|
|
|
const double HitBuffer = PixelHitThresholdAdjust + LineThickness;
|
|
double Distance = FVector::Distance(NearestCirclePos, NearestRayPos);
|
|
|
|
if (Distance <= HitBuffer)
|
|
{
|
|
FInputRayHit RayHit(static_cast<float>(HitDepth));
|
|
RayHit.SetHitObject(this);
|
|
RayHit.HitIdentifier = PartIdentifier;
|
|
return RayHit;
|
|
}
|
|
}
|
|
}
|
|
return FInputRayHit();
|
|
}
|
|
|
|
void UGizmoElementCircle::SetDrawMesh(bool InDrawMesh)
|
|
{
|
|
bDrawMesh = InDrawMesh;
|
|
}
|
|
|
|
bool UGizmoElementCircle::GetDrawMesh() const
|
|
{
|
|
return bDrawMesh;
|
|
}
|
|
|
|
void UGizmoElementCircle::SetDrawLine(bool InDrawLine)
|
|
{
|
|
bDrawLine = InDrawLine;
|
|
}
|
|
|
|
bool UGizmoElementCircle::GetDrawLine() const
|
|
{
|
|
return bDrawLine;
|
|
}
|
|
|
|
void UGizmoElementCircle::SetHitMesh(bool InHitMesh)
|
|
{
|
|
bHitMesh = InHitMesh;
|
|
}
|
|
|
|
bool UGizmoElementCircle::GetHitMesh() const
|
|
{
|
|
return bHitMesh;
|
|
}
|
|
|
|
void UGizmoElementCircle::SetHitLine(bool InHitLine)
|
|
{
|
|
bHitLine = InHitLine;
|
|
}
|
|
|
|
bool UGizmoElementCircle::GetHitLine() const
|
|
{
|
|
return bHitLine;
|
|
}
|
|
|
|
|