Files
UnrealEngine/Engine/Source/Editor/ViewportInteraction/Private/ViewportInteractionDragOperations.cpp
2025-05-18 13:04:45 +08:00

167 lines
7.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ViewportInteractionDragOperations.h"
#include "ViewportInteractionTypes.h"
#include "VIGizmoHandle.h"
#include "ViewportInteractor.h"
#include "ViewportWorldInteraction.h"
#include "SnappingUtils.h"
#include "ViewportInteractor.h"
#include "UnrealWidgetFwd.h"
namespace VI
{
static FAutoConsoleVariable ScaleSensitivity(TEXT("VI.ScaleSensitivity"), 0.005f, TEXT("Sensitivity for scaling"));
}
void UTranslationDragOperation::ExecuteDrag(FDraggingTransformableData& DraggingData)
{
// Translate the gizmo!
DraggingData.OutGizmoUnsnappedTargetTransform.SetLocation(DraggingData.PassDraggedTo);
DraggingData.bOutMovedTransformGizmo = true;
DraggingData.bOutShouldApplyVelocitiesFromDrag = true;
DraggingData.bOutTranslated = true;
}
UPlaneTranslationDragOperation::UPlaneTranslationDragOperation()
{
bPlaneConstraint = true;
}
void UPlaneTranslationDragOperation::ExecuteDrag(struct FDraggingTransformableData& DraggingData)
{
// Translate the gizmo!
DraggingData.OutGizmoUnsnappedTargetTransform.SetLocation(DraggingData.PassDraggedTo);
DraggingData.bOutMovedTransformGizmo = true;
DraggingData.bOutShouldApplyVelocitiesFromDrag = true;
DraggingData.bOutTranslated = true;
}
URotateOnAngleDragOperation::URotateOnAngleDragOperation():
Super(),
StartDragAngleOnRotation(),
DraggingRotationHandleDirection()
{
}
void URotateOnAngleDragOperation::ExecuteDrag(FDraggingTransformableData& DraggingData)
{
const FTransformGizmoHandlePlacement& HandlePlacement = DraggingData.OptionalHandlePlacement.GetValue();
const FTransform& GizmoStartTransform = DraggingData.GizmoStartTransform;
int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex;
HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex);
FVector GizmoSpaceFacingAxisVector = UGizmoHandleGroup::GetAxisVector(FacingAxisIndex, HandlePlacement.Axes[FacingAxisIndex]);
USceneComponent* DraggingTransformGizmoComponent = DraggingData.Interactor->GetInteractorData().DraggingTransformGizmoComponent.Get();
if (DraggingTransformGizmoComponent)
{
const FTransform WorldToGizmo = GizmoStartTransform.Inverse();
FTransform NewGizmoToWorld;
{
if (!DraggingRotationHandleDirection.IsSet())
{
DraggingRotationHandleDirection = DraggingTransformGizmoComponent->GetComponentTransform().GetRotation().Vector();
DraggingRotationHandleDirection->Normalize();
}
//@todo ViewportInteraction: Use UViewportWorldInteraction::ComputeConstrainedDragDeltaFromStart instead of calculating where the laser hit on the plane with this intersect.
// Get the laser pointer intersection on the plane of the handle
const FPlane RotationPlane = FPlane(GizmoStartTransform.GetLocation(), DraggingRotationHandleDirection.GetValue());
const ECoordSystem CoordSystem = DraggingData.WorldInteraction->GetTransformGizmoCoordinateSpace();
const FVector LaserImpactOnRotationPlane = FMath::LinePlaneIntersection(DraggingData.LaserPointerStart, DraggingData.LaserPointerStart + DraggingData.LaserPointerDirection, RotationPlane);
{
FTransform GizmoTransformNoRotation = FTransform(FRotator::ZeroRotator, GizmoStartTransform.GetLocation());
if (CoordSystem == COORD_Local)
{
GizmoTransformNoRotation.SetRotation(GizmoStartTransform.GetRotation());
}
LocalIntersectPointOnRotationGizmo = GizmoTransformNoRotation.InverseTransformPositionNoScale(LaserImpactOnRotationPlane);
}
// Set output for hover point
DraggingData.OutUnsnappedDraggedTo = LaserImpactOnRotationPlane;
// Relative offset of the intersection on the plane
const FVector GizmoSpaceLaserImpactOnRotationPlane = WorldToGizmo.TransformPosition(LaserImpactOnRotationPlane);
FVector RotatedIntersectLocationOnPlane;
if (CoordSystem == COORD_Local)
{
RotatedIntersectLocationOnPlane = GizmoSpaceFacingAxisVector.Rotation().UnrotateVector(GizmoSpaceLaserImpactOnRotationPlane);
}
else
{
RotatedIntersectLocationOnPlane = GizmoStartTransform.TransformVector(GizmoSpaceFacingAxisVector).Rotation().UnrotateVector(GizmoSpaceLaserImpactOnRotationPlane);
}
// Get the angle between the center and the intersected point
float AngleToIntersectedLocation = (float)FMath::Atan2(RotatedIntersectLocationOnPlane.Y, RotatedIntersectLocationOnPlane.Z);
if (!StartDragAngleOnRotation.IsSet())
{
StartDragAngleOnRotation = AngleToIntersectedLocation;
}
// Delta rotation in gizmo space between the starting and the intersection rotation
const float AngleDeltaRotationFromStart = FMath::FindDeltaAngleRadians(AngleToIntersectedLocation, StartDragAngleOnRotation.GetValue());
const FQuat GizmoSpaceDeltaRotation = FQuat(GizmoSpaceFacingAxisVector, AngleDeltaRotationFromStart);
const FTransform GizmoSpaceRotatedTransform(GizmoSpaceDeltaRotation);
NewGizmoToWorld = GizmoSpaceRotatedTransform * GizmoStartTransform;
}
// Rotate the gizmo!
DraggingData.OutGizmoUnsnappedTargetTransform = NewGizmoToWorld;
DraggingData.bOutMovedTransformGizmo = true;
DraggingData.bOutShouldApplyVelocitiesFromDrag = true;
DraggingData.bOutRotated = true;
}
}
FVector URotateOnAngleDragOperation::GetLocalIntersectPointOnRotationGizmo() const
{
return LocalIntersectPointOnRotationGizmo;
}
void UScaleDragOperation::ExecuteDrag(struct FDraggingTransformableData& DraggingData)
{
const FTransformGizmoHandlePlacement& HandlePlacement = DraggingData.OptionalHandlePlacement.GetValue();
int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex;
HandlePlacement.GetCenterHandleCountAndFacingAxisIndex(/* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex);
const FVector PassGizmoSpaceDraggedTo = DraggingData.GizmoStartTransform.InverseTransformPositionNoScale(DraggingData.PassDraggedTo);
double AddedScaleOnAxis = PassGizmoSpaceDraggedTo[FacingAxisIndex] * VI::ScaleSensitivity->GetFloat();
// Invert if we we are scaling on the negative side of the gizmo
USceneComponent* DraggingTransformGizmoComponent = DraggingData.Interactor->GetInteractorData().DraggingTransformGizmoComponent.Get();
if (DraggingTransformGizmoComponent && DraggingTransformGizmoComponent->GetRelativeTransform().GetLocation()[FacingAxisIndex] < 0)
{
AddedScaleOnAxis *= -1;
}
FVector NewScale = DraggingData.GizmoStartTransform.GetScale3D();
NewScale[FacingAxisIndex] += AddedScaleOnAxis;
DraggingData.OutGizmoUnsnappedTargetTransform.SetScale3D(NewScale);
DraggingData.bOutMovedTransformGizmo = true;
DraggingData.bOutShouldApplyVelocitiesFromDrag = true;
DraggingData.bOutScaled = true;
}
void UUniformScaleDragOperation::ExecuteDrag(struct FDraggingTransformableData& DraggingData)
{
//Always use Z for uniform scale
const FVector RelativeDraggedTo = DraggingData.PassDraggedTo - DraggingData.GizmoStartTransform.GetLocation();
const FVector AddedScaleOnAxis(RelativeDraggedTo.Z * VI::ScaleSensitivity->GetFloat());
const FVector NewScale = DraggingData.GizmoStartTransform.GetScale3D() + AddedScaleOnAxis;
DraggingData.OutGizmoUnsnappedTargetTransform.SetScale3D(NewScale);
DraggingData.bOutMovedTransformGizmo = true;
DraggingData.bOutShouldApplyVelocitiesFromDrag = true;
DraggingData.bOutScaled = true;
}