Files
UnrealEngineUWP/Engine/Source/Runtime/InteractiveToolsFramework/Private/BaseGizmos/GizmoElementBase.cpp
Christina TempelaarL 9ac82fb6dd Add IGizmoClickMultiTarget, IGizmoRenderTarget and IGizmoRenderMultiTarget interfaces to facilitate hitting parts within a gizmo element hierarchy. Add HitObject member to FInputRayHit struct to hold UObect-derived owners of hits.
#jira UETOOL-4781
#rb ryan.schmidt, brooke.hubert, jimmy.andrews
#preflight 6272b741e95a8b960ebfba9c

[CL 20050122 by Christina TempelaarL in ue5-main branch]
2022-05-04 17:25:53 -04:00

409 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BaseGizmos/GizmoElementBase.h"
#include "BaseGizmos/GizmoInterfaces.h"
#include "BaseGizmos/GizmoRenderingUtil.h"
#include "Materials/MaterialInterface.h"
DEFINE_LOG_CATEGORY_STATIC(LogGizmoElements, Log, All);
bool UGizmoElementBase::GetViewDependentVisibility(const FSceneView* View, const FTransform& InLocalToWorldTransform, const FVector& InLocalCenter) const
{
if (ViewDependentType == EGizmoElementViewDependentType::None || ViewAlignType == EGizmoElementViewAlignType::PointOnly || ViewAlignType == EGizmoElementViewAlignType::PointEye)
{
return true;
}
FVector ViewDir;
if (View->IsPerspectiveProjection())
{
FVector WorldCenter = InLocalToWorldTransform.TransformPosition(InLocalCenter);
ViewDir = WorldCenter - View->ViewLocation;
ViewDir.Normalize();
}
else
{
ViewDir = View->GetViewDirection();
}
bool bVisibleViewDependent;
if (ViewDependentType == EGizmoElementViewDependentType::Axis)
{
bVisibleViewDependent = FMath::Abs(FVector::DotProduct(ViewDependentAxis, ViewDir)) < DefaultViewAlignAxialMaxCosAngleTol;
}
else // (ViewDependentType == EGizmoElementViewDependentType::Plane)
{
bVisibleViewDependent = FMath::Abs(FVector::DotProduct(ViewDependentAxis, ViewDir)) > DefaultViewAlignPlanarMinCosAngleTol;
}
return bVisibleViewDependent;
}
bool UGizmoElementBase::GetViewAlignRot(const FSceneView* View, const FTransform& InLocalToWorldTransform, const FVector& InLocalCenter, FQuat& OutAlignRot) const
{
if (ViewAlignType == EGizmoElementViewAlignType::None)
{
return false;
}
FVector Scale = InLocalToWorldTransform.GetScale3D();
if (!FMath::IsNearlyEqual(Scale.X, Scale.Y, KINDA_SMALL_NUMBER) || !FMath::IsNearlyEqual(Scale.X, Scale.Z, KINDA_SMALL_NUMBER))
{
// Warn that non-uniform scale is not currently supported
bool bNonUniformScaleWarning = true;
if (bNonUniformScaleWarning)
{
UE_LOG(LogGizmoElements, Warning, TEXT("Gizmo element library view-dependent alignment does not currently support non-uniform scale (%f %f %f)."),
Scale.X, Scale.Y, Scale.Z);
bNonUniformScaleWarning = false;
}
return false;
}
FVector LocalViewDir;
FTransform WorldToLocalTransform = InLocalToWorldTransform.Inverse();
if (View->IsPerspectiveProjection())
{
FVector LocalViewLocation = WorldToLocalTransform.TransformPosition(View->ViewLocation);
LocalViewDir = InLocalCenter - LocalViewLocation;
LocalViewDir.Normalize();
}
else
{
FVector WorldViewDir = View->GetViewDirection();
LocalViewDir = WorldToLocalTransform.GetRotation().RotateVector(WorldViewDir);
LocalViewDir.Normalize();
}
if (ViewAlignType == EGizmoElementViewAlignType::PointOnly)
{
OutAlignRot = FQuat::FindBetweenNormals(ViewAlignNormal, -LocalViewDir);
}
else if (ViewAlignType == EGizmoElementViewAlignType::PointEye)
{
FVector Right = ViewAlignAxis ^ ViewAlignNormal;
Right.Normalize();
FVector Up = ViewAlignNormal ^ Right;
FMatrix LocalToCanonicalBasis(
FPlane(ViewAlignNormal.X, Right.X, Up.X, 0.0),
FPlane(ViewAlignNormal.Y, Right.Y, Up.Y, 0.0),
FPlane(ViewAlignNormal.Z, Right.Z, Up.Z, 0.0),
FPlane::ZeroVector);
FVector LocalViewUp = WorldToLocalTransform.TransformVector(View->GetViewUp());
FVector TargetFwd = -LocalViewDir;
FVector TargetRight = LocalViewUp ^ TargetFwd;
TargetRight.Normalize();
FVector TargetUp = TargetFwd ^ TargetRight;
FMatrix CanonicalToAlignRotBasis(
FPlane(TargetFwd.X, TargetFwd.Y, TargetFwd.Z, 0.0),
FPlane(TargetRight.X, TargetRight.Y, TargetRight.Z, 0.0),
FPlane(TargetUp.X, TargetUp.Y, TargetUp.Z, 0.0),
FPlane::ZeroVector);
FMatrix LocalToAligned = LocalToCanonicalBasis * CanonicalToAlignRotBasis;
OutAlignRot = LocalToAligned.ToQuat();
OutAlignRot.Normalize();
}
else if (ViewAlignType == EGizmoElementViewAlignType::Axial)
{
// if Axis and Dir are almost coincident, do not adjust the rotation
if ((FMath::Abs(FVector::DotProduct(ViewAlignAxis, -LocalViewDir))) >= DefaultViewAlignAxialMaxCosAngleTol)
{
return false;
}
FVector TargetRight = -LocalViewDir ^ ViewAlignAxis;
TargetRight.Normalize();
FVector TargetNormal = ViewAlignAxis ^ TargetRight;
TargetNormal.Normalize();
OutAlignRot = FQuat::FindBetweenNormals(ViewAlignNormal, TargetNormal);
}
return true;
}
const UMaterialInterface* UGizmoElementBase::GetCurrentMaterial(const FRenderTraversalState& RenderState) const
{
EGizmoElementInteractionState CurrentState;
if (RenderState.InteractionState == EGizmoElementInteractionState::None)
{
CurrentState = ElementInteractionState;
}
else
{
CurrentState = RenderState.InteractionState;
}
if (CurrentState == EGizmoElementInteractionState::Hovering)
{
if (RenderState.HoverMaterial.IsValid())
{
return RenderState.HoverMaterial.Get();
}
return HoverMaterial;
}
if (CurrentState == EGizmoElementInteractionState::Interacting)
{
if (RenderState.InteractMaterial.IsValid())
{
return RenderState.InteractMaterial.Get();
}
return InteractMaterial;
}
// CurrentState is None, so just return the regular material
if (RenderState.Material.IsValid())
{
return RenderState.Material.Get();
}
return Material;
}
void UGizmoElementBase::CacheRenderState(const FTransform& InLocalToWorldState, bool InVisibleViewDependent)
{
CachedLocalToWorldTransform = InLocalToWorldState;
bHasCachedLocalToWorldTransform = true;
bCachedVisibleViewDependent = InVisibleViewDependent;
}
void UGizmoElementBase::ResetCachedRenderState()
{
bHasCachedLocalToWorldTransform = false;
bCachedVisibleViewDependent = true;
}
void UGizmoElementBase::UpdateRenderTraversalState(FRenderTraversalState& InRenderTraversalState)
{
if (InRenderTraversalState.InteractionState == EGizmoElementInteractionState::None)
{
InRenderTraversalState.InteractionState = ElementInteractionState;
}
if (!InRenderTraversalState.HoverMaterial.IsValid())
{
InRenderTraversalState.HoverMaterial = HoverMaterial;
}
if (!InRenderTraversalState.InteractMaterial.IsValid())
{
InRenderTraversalState.InteractMaterial = InteractMaterial;
}
if (!InRenderTraversalState.Material.IsValid())
{
InRenderTraversalState.Material = Material;
}
}
bool UGizmoElementBase::IsVisible() const
{
bool bVisible = static_cast<uint8>(ElementState) & static_cast<uint8>(EGizmoElementState::Visible);
return (bEnabled && bVisible);
}
bool UGizmoElementBase::IsHittable() const
{
bool bHittable = static_cast<uint8>(ElementState) & static_cast<uint8>(EGizmoElementState::Hittable);
return (bEnabled && bHittable);
}
bool UGizmoElementBase::IsHittableInView() const
{
return (IsHittable() && bHasCachedLocalToWorldTransform && (!IsVisible() || bCachedVisibleViewDependent));
}
void UGizmoElementBase::SetEnabled(bool InEnabled)
{
bEnabled = InEnabled;
}
bool UGizmoElementBase::GetEnabled() const
{
return bEnabled;
}
void UGizmoElementBase::SetPartIdentifier(uint32 InPartIdentifier)
{
PartIdentifier = InPartIdentifier;
}
uint32 UGizmoElementBase::GetPartIdentifier()
{
return PartIdentifier;
}
void UGizmoElementBase::SetElementState(EGizmoElementState InElementState)
{
ElementState = InElementState;
}
EGizmoElementState UGizmoElementBase::GetElementState() const
{
return ElementState;
}
void UGizmoElementBase::SetElementInteractionState(EGizmoElementInteractionState InElementInteractionState)
{
ElementInteractionState = InElementInteractionState;
}
EGizmoElementInteractionState UGizmoElementBase::GetElementInteractionState() const
{
return ElementInteractionState;
}
void UGizmoElementBase::UpdatePartHittableState(bool bHittable, uint32 InPartIdentifier)
{
if (InPartIdentifier == PartIdentifier)
{
uint8 State = static_cast<uint8>(ElementState);
uint8 HittableMask = static_cast<uint8>(EGizmoElementState::Hittable);
uint8 NewState = (bHittable ? State | HittableMask : State & (~HittableMask));
ElementState = static_cast<EGizmoElementState>(NewState);
}
}
void UGizmoElementBase::UpdatePartVisibleState(bool bVisible, uint32 InPartIdentifier)
{
if (InPartIdentifier == PartIdentifier)
{
uint8 State = static_cast<uint8>(ElementState);
uint8 VisibleMask = static_cast<uint8>(EGizmoElementState::Visible);
uint8 NewState = (bVisible ? State | VisibleMask : State & (~VisibleMask));
ElementState = static_cast<EGizmoElementState>(NewState);
}
}
void UGizmoElementBase::UpdatePartInteractionState(EGizmoElementInteractionState InInteractionState, uint32 InPartIdentifier)
{
if (InPartIdentifier == PartIdentifier)
{
ElementInteractionState = InInteractionState;
}
}
void UGizmoElementBase::SetViewDependentType(EGizmoElementViewDependentType InViewDependentType)
{
ViewDependentType = InViewDependentType;
}
EGizmoElementViewDependentType UGizmoElementBase::GetViewDependentType() const
{
return ViewDependentType;
}
void UGizmoElementBase::SetViewDependentAngleTol(float InAngleTol)
{
ViewDependentAngleTol = InAngleTol;
ViewDependentAxialMaxCosAngleTol = FMath::Abs(FMath::Cos(ViewDependentAngleTol));
ViewDependentPlanarMinCosAngleTol = FMath::Abs(FMath::Cos(HALF_PI + ViewDependentAngleTol));
}
float UGizmoElementBase::GetViewDependentAngleTol() const
{
return ViewDependentAngleTol;
}
void UGizmoElementBase::SetViewDependentAxis(FVector InViewDependentAxis)
{
ViewDependentAxis = InViewDependentAxis;
ViewDependentAxis.Normalize();
}
FVector UGizmoElementBase::GetViewDependentAxis() const
{
return ViewDependentAxis;
}
void UGizmoElementBase::SetViewAlignType(EGizmoElementViewAlignType InViewAlignType)
{
ViewAlignType = InViewAlignType;
}
EGizmoElementViewAlignType UGizmoElementBase::GetViewAlignType() const
{
return ViewAlignType;
}
void UGizmoElementBase::SetViewAlignAxis(FVector InViewAlignAxis)
{
ViewAlignAxis = InViewAlignAxis;
ViewAlignAxis.Normalize();
}
FVector UGizmoElementBase::GetViewAlignAxis() const
{
return ViewAlignAxis;
}
void UGizmoElementBase::SetViewAlignNormal(FVector InViewAlignNormal)
{
ViewAlignNormal = InViewAlignNormal;
ViewAlignNormal.Normalize();
}
FVector UGizmoElementBase::GetViewAlignNormal() const
{
return ViewAlignNormal;
}
void UGizmoElementBase::SetViewAlignAxialAngleTol(float InAngleTol)
{
ViewAlignAxialAngleTol = InAngleTol;
ViewAlignAxialMaxCosAngleTol = FMath::Abs(FMath::Cos(ViewAlignAxialAngleTol));
}
float UGizmoElementBase::GetViewAlignAxialAngleTol() const
{
return ViewAlignAxialAngleTol;
}
void UGizmoElementBase::SetMaterial(UMaterialInterface* InMaterial)
{
Material = InMaterial;
}
UMaterialInterface* UGizmoElementBase::GetMaterial() const
{
return Material;
}
void UGizmoElementBase::SetHoverMaterial(UMaterialInterface* InHoverMaterial)
{
HoverMaterial = InHoverMaterial;
}
UMaterialInterface* UGizmoElementBase::GetHoverMaterial() const
{
return HoverMaterial;
}
void UGizmoElementBase::SetInteractMaterial(UMaterialInterface* InInteractMaterial)
{
InteractMaterial = InInteractMaterial;
}
UMaterialInterface* UGizmoElementBase::GetInteractMaterial() const
{
return InteractMaterial;
}
void UGizmoElementBase::SetVertexColor(const FColor& InVertexColor)
{
VertexColor = InVertexColor;
}
FColor UGizmoElementBase::GetVertexColor() const
{
return VertexColor;
}