Files
2025-05-18 13:04:45 +08:00

406 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BaseGizmos/ParameterToTransformAdapters.h"
#include "BaseGizmos/GizmoMath.h"
void UGizmoAxisTranslationParameterSource::SetParameter(float NewValue)
{
Parameter = NewValue;
LastChange.CurrentValue = NewValue;
double UseDelta = LastChange.GetChangeDelta();
// check for any constraints on the delta value
double SnappedDelta = 0;
if (AxisDeltaConstraintFunction(UseDelta, SnappedDelta))
{
UseDelta = SnappedDelta;
}
// construct translation as delta from initial position
FVector Translation = UseDelta * CurTranslationAxis;
// translate the initial transform
FTransform NewTransform = InitialTransform;
NewTransform.AddToTranslation(Translation);
// apply position constraint
FVector SnappedPos;
if (PositionConstraintFunction(NewTransform.GetTranslation(), SnappedPos))
{
FVector SnappedLinePos = GizmoMath::ProjectPointOntoLine(SnappedPos, CurTranslationOrigin, CurTranslationAxis);
NewTransform.SetTranslation(SnappedLinePos);
}
TransformSource->SetTransform(NewTransform);
OnParameterChanged.Broadcast(this, LastChange);
}
void UGizmoAxisTranslationParameterSource::BeginModify()
{
check(AxisSource);
LastChange = FGizmoFloatParameterChange(Parameter);
InitialTransform = TransformSource->GetTransform();
CurTranslationAxis = AxisSource->GetDirection();
CurTranslationOrigin = AxisSource->GetOrigin();
}
void UGizmoAxisTranslationParameterSource::EndModify()
{
}
void UGizmoPlaneTranslationParameterSource::SetParameter(const FVector2D& NewValue)
{
Parameter = NewValue;
LastChange.CurrentValue = NewValue;
// construct translation as delta from initial position
FVector2D Delta = LastChange.GetChangeDelta();
double UseDeltaX = Delta.X;
double UseDeltaY = Delta.Y;
// check for any constraints on the delta value
double SnappedDeltaX = 0, SnappedDeltaY = 0;
if (AxisXDeltaConstraintFunction(UseDeltaX, SnappedDeltaX))
{
UseDeltaX = SnappedDeltaX;
}
if (AxisYDeltaConstraintFunction(UseDeltaY, SnappedDeltaY))
{
UseDeltaY = SnappedDeltaY;
}
FVector Translation = UseDeltaX*CurTranslationAxisX + UseDeltaY*CurTranslationAxisY;
// apply translation to initial transform
FTransform NewTransform = InitialTransform;
NewTransform.AddToTranslation(Translation);
// apply position constraint
FVector SnappedPos;
if (PositionConstraintFunction(NewTransform.GetTranslation(), SnappedPos))
{
FVector PlanePos = GizmoMath::ProjectPointOntoPlane(SnappedPos, CurTranslationOrigin, CurTranslationNormal);
NewTransform.SetTranslation(PlanePos);
}
TransformSource->SetTransform(NewTransform);
OnParameterChanged.Broadcast(this, LastChange);
}
void UGizmoPlaneTranslationParameterSource::BeginModify()
{
check(AxisSource);
LastChange = FGizmoVec2ParameterChange(Parameter);
// save initial transformation and axis information
InitialTransform = TransformSource->GetTransform();
CurTranslationOrigin = AxisSource->GetOrigin();
AxisSource->GetAxisFrame(CurTranslationNormal, CurTranslationAxisX, CurTranslationAxisY);
}
void UGizmoPlaneTranslationParameterSource::EndModify()
{
}
void UGizmoAxisRotationParameterSource::SetParameter(float NewValue)
{
Angle = NewValue;
LastChange.CurrentValue = NewValue;
double AngleDelta = LastChange.GetChangeDelta();
double SnappedDelta;
if (AngleDeltaConstraintFunction(AngleDelta, SnappedDelta))
{
AngleDelta = SnappedDelta;
}
// construct rotation as delta from initial position
FQuat DeltaRotation(CurRotationAxis, AngleDelta);
DeltaRotation = RotationConstraintFunction(DeltaRotation);
// rotate the vector from the rotation origin to the transform origin,
// to get the translation of the origin produced by the rotation
FVector DeltaPosition = InitialTransform.GetLocation() - CurRotationOrigin;
DeltaPosition = DeltaRotation * DeltaPosition;
FVector NewLocation = CurRotationOrigin + DeltaPosition;
// rotate the initial transform by the rotation
FQuat NewRotation = DeltaRotation * InitialTransform.GetRotation();
// construct new transform
FTransform NewTransform = InitialTransform;
NewTransform.SetLocation(NewLocation);
NewTransform.SetRotation(NewRotation);
TransformSource->SetTransform(NewTransform);
OnParameterChanged.Broadcast(this, LastChange);
}
void UGizmoAxisRotationParameterSource::BeginModify()
{
check(AxisSource != nullptr);
LastChange = FGizmoFloatParameterChange(Angle);
// save initial transformation and axis information
InitialTransform = TransformSource->GetTransform();
CurRotationAxis = AxisSource->GetDirection();
CurRotationOrigin = AxisSource->GetOrigin();
}
void UGizmoAxisRotationParameterSource::EndModify()
{
}
void UGizmoUniformScaleParameterSource::SetParameter(const FVector2D& NewValue)
{
Parameter = NewValue;
LastChange.CurrentValue = NewValue;
// Convert 2D parameter delta to a 1D uniform scale change
// This possibly be exposed as a TFunction to allow customization?
double SignedDelta = LastChange.GetChangeDelta().X + LastChange.GetChangeDelta().Y;
SignedDelta *= ScaleMultiplier;
FTransform NewTransform = InitialTransform;
const FVector StartScale = InitialTransform.GetScale3D();
double SnappedDelta;
bool bIsSnapped = false;
// if using snapping while scaling
if (ScaleAxisDeltaConstraintFunction(SignedDelta, SnappedDelta))
{
SignedDelta = SnappedDelta;
bIsSnapped = true;
}
FVector NewScale;
// if the initial scale is uniform and snapping is on, we can use an additive method to scale up or down
if (StartScale.IsUniform() && bIsSnapped)
{
NewScale = FVector(SignedDelta) + StartScale;
}
// otherwise, we need to use multiplication to scale
// ex: initial scale is (1,2,4) and scale delta is .5 -> next incremented scale should be (1.5, 3, 6)
// to preserve proportions. Addition would result in (1.5, 2.5, 4.5) which does not keep original proportions.
// Additionally, using multiplication when scale is uniform would result in an ex where InitScale=(2,2,2) and
// ScaleDelta = .5 where next scale would be (3,3,3), where the intermediate scale of (2.5,2.5,2.5) is unreachable
else
{
NewScale = SignedDelta * StartScale + StartScale;
}
// currently calling ScaleConstraintFunction has no effect (no changes made to SignedDelta) because this constraint function
// is intended to relate to WorldGridSnapping. Currently WorldGridSnapping has no effect on scaling, with or without normal snapping
// because the viewport scale mode fixes the transform space to local
SignedDelta = ScaleConstraintFunction(SignedDelta);
NewTransform.SetScale3D(NewScale);
TransformSource->SetTransform(NewTransform);
OnParameterChanged.Broadcast(this, LastChange);
}
void UGizmoUniformScaleParameterSource::BeginModify()
{
check(AxisSource);
LastChange = FGizmoVec2ParameterChange(Parameter);
// save initial transformation and axis information
InitialTransform = TransformSource->GetTransform();
CurScaleOrigin = AxisSource->GetOrigin();
// note: currently not used!
AxisSource->GetAxisFrame(CurScaleNormal, CurScaleAxisX, CurScaleAxisY);
}
void UGizmoUniformScaleParameterSource::EndModify()
{
}
void UGizmoAxisScaleParameterSource::SetParameter(float NewValue)
{
Parameter = NewValue;
LastChange.CurrentValue = NewValue;
double ScaleDelta = LastChange.GetChangeDelta();
ScaleDelta *= ScaleMultiplier;
FTransform NewTransform = InitialTransform;
const FVector StartScale = InitialTransform.GetScale3D();
FVector NewScale;
double SnappedDelta;
// check for any constraints on the delta value
if (ScaleAxisDeltaConstraintFunction(ScaleDelta, SnappedDelta))
{
ScaleDelta = SnappedDelta;
// use additive scaling when snap is on
NewScale = StartScale + ScaleDelta * CurScaleAxis;
}
else
{
// use multiplicative scaling when snap is off
NewScale = StartScale * (FVector3d{1} + (ScaleDelta * CurScaleAxis));
}
// currently calling ScaleConstraintFunction has no effect (no changes made to ScaleDelta) because this constraint function
// is intended to relate to WorldGridSnapping. Currently WorldGridSnapping has no effect on scaling, with or without normal snapping
// because the viewport scale mode fixes the transform space to local
ScaleDelta = ScaleConstraintFunction(ScaleDelta);
if (bClampToZero)
{
NewScale = FVector::Max(FVector::ZeroVector, NewScale);
}
NewTransform.SetScale3D(NewScale);
TransformSource->SetTransform(NewTransform);
OnParameterChanged.Broadcast(this, LastChange);
}
void UGizmoAxisScaleParameterSource::BeginModify()
{
check(AxisSource);
LastChange = FGizmoFloatParameterChange(Parameter);
InitialTransform = TransformSource->GetTransform();
CurScaleAxis = AxisSource->GetDirection();
CurScaleOrigin = AxisSource->GetOrigin();
}
void UGizmoAxisScaleParameterSource::EndModify()
{
}
void UGizmoPlaneScaleParameterSource::SetParameter(const FVector2D& NewValue)
{
Parameter = NewValue;
LastChange.CurrentValue = NewValue;
// construct Scale as delta from initial position
FVector2D ScaleDelta = LastChange.GetChangeDelta() * ScaleMultiplier;
if (bUseEqualScaling)
{
ScaleDelta = FVector2D(ScaleDelta.X + ScaleDelta.Y);
}
FTransform NewTransform = InitialTransform;
const FVector StartScale = InitialTransform.GetScale3D();
double UseScaleDeltaX = ScaleDelta.X;
double UseScaleDeltaY = ScaleDelta.Y;
FVector NewScale;
if (bUseEqualScaling)
{
double SnappedDeltaX = 0.0, SnappedDeltaY = 0.0;
bool bIsSnapped = true;
// if using snapping while scaling on X and Y axis
if (ScaleAxisXDeltaConstraintFunction(UseScaleDeltaX, SnappedDeltaX))
{
UseScaleDeltaX = SnappedDeltaX;
}
else
{
bIsSnapped = false;
}
if (ScaleAxisYDeltaConstraintFunction(UseScaleDeltaY, SnappedDeltaY))
{
UseScaleDeltaY = SnappedDeltaY;
}
else
{
bIsSnapped = false;
}
// determines if the initial scales of the 2 affected axes are equivalent, and if we can therefore use uniform scaling (additive function)
const FVector AffectedValuesVector = StartScale*CurScaleAxisX + StartScale*CurScaleAxisY;
const bool bIsUniformAcrossScaleAxes = (AffectedValuesVector.X == AffectedValuesVector.Y) || (AffectedValuesVector.X == AffectedValuesVector.Z) || (AffectedValuesVector.Y == AffectedValuesVector.Z);
// will use additive if scale is uniform across 2 axes of the plane AND snapping is on
if (bIsUniformAcrossScaleAxes && bIsSnapped)
{
// uses an additive function to scale when both initial values are equal
// ex: allows for a case where InitScale= (2,2,1) scaling by 1 across Z axis, next increment will be (3,3,1) instead of (4,4,1)
NewScale = StartScale + UseScaleDeltaX*CurScaleAxisX + UseScaleDeltaY*CurScaleAxisY;
}
else
{
NewScale = StartScale + (UseScaleDeltaX * StartScale * CurScaleAxisX) + (UseScaleDeltaY * StartScale * CurScaleAxisY);
}
}
else
{
NewScale = StartScale + (UseScaleDeltaX * StartScale * CurScaleAxisX) + (UseScaleDeltaY * StartScale * CurScaleAxisY);
}
// currently calling ScaleConstraintFunction has no effect (no changes made to SignedDelta) because this constraint function
// is intended to relate to WorldGridSnapping. Currently WorldGridSnapping has no effect on scaling, with or without normal snapping
// because the viewport scale mode fixes the transform space to local
ScaleDelta = ScaleConstraintFunction(ScaleDelta);
if (bClampToZero)
{
NewScale = FVector::Max(NewScale, FVector::ZeroVector);
}
NewTransform.SetScale3D(NewScale);
TransformSource->SetTransform(NewTransform);
OnParameterChanged.Broadcast(this, LastChange);
}
void UGizmoPlaneScaleParameterSource::BeginModify()
{
check(AxisSource);
LastChange = FGizmoVec2ParameterChange(Parameter);
// save initial transformation and axis information
InitialTransform = TransformSource->GetTransform();
CurScaleOrigin = AxisSource->GetOrigin();
AxisSource->GetAxisFrame(CurScaleNormal, CurScaleAxisX, CurScaleAxisY);
}
void UGizmoPlaneScaleParameterSource::EndModify()
{
}