keywords: [UE4]Linear Algebra & Plane Geometry API

keywords:UE4、Linear Algebra、Plane Geometry、线性代数、解析几何

范围判定

检测一个点是否在一个多边形(或矩形)的内部(2D和3D)
FBox2D::IsInside(const FVector2D& TestPoint)
FBox::IsInside(const FVector& TestPoint)
FIntRect::Contains( FIntPoint P )

角度计算

计算两个向量的夹角(Get an angle between 2 Vectors),范围:(0, 180)
float AimAtAngle = FMath::RadiansToDegrees(acosf(FVector::DotProduct(PlayerDirection, MouseDirection)));

参考:How to get an angle between 2 Vectors?
https://answers.unrealengine.com/questions/31058/how-to-get-an-angle-between-2-vectors.html

计算方向向量与空间坐标轴(X、Y、Z)的夹角,范围:(-180, 180)
FRotator Rot = UKismetMathLibrary::MakeRotFromX(TestVector);
float Angle = Rot.Yaw;  //(-180, 180)
判断角色A在角色B的左边还是右边(或者角色A相对角色B的四个方向)

参考自引擎代码:UAnimInstance::CalculateDirection()

//-180到0表示 ActorA 在 ActorB 左边,0到180表示 ActorA 在 ActorB 右边
float CalculateDirecton(const AActor* ActorA, const AActor* ActorB)
{
    FVector TestDire = ActorA->GetActorLocation() - ActorB->GetActorLocation();

    FMatrix RotMatrix = FRotationMatrix(ActorB->GetActorRotation());
    FVector ForwardVector = RotMatrix.GetScaledAxis(EAxis::X);
    FVector RightVector = RotMatrix.GetScaledAxis(EAxis::Y);
    FVector NormalizedVel = TestDire.GetSafeNormal2D();

    // get a cos(alpha) of forward vector vs velocity
    float ForwardCosAngle = FVector::DotProduct(ForwardVector, NormalizedVel);
    // now get the alpha and convert to degree
    float ForwardDeltaDegree = FMath::RadiansToDegrees(FMath::Acos(ForwardCosAngle));

    // depending on where right vector is, flip it
    float RightCosAngle = FVector::DotProduct(RightVector, NormalizedVel);
    if (RightCosAngle < 0)
    {
        ForwardDeltaDegree *= -1;
    }
    
    return ForwardDeltaDegree;
}
计算方向向量 InDirection 相对 ReferenceFrame 的方位俯仰角(Azimuth-Elevation)
void UKismetMathLibrary::GetAzimuthAndElevation(FVector InDirection, const FTransform& ReferenceFrame, float& Azimuth, float& Elevation);
根据入射向量和法线向量计算反射向量
FVector FMath::GetReflectionVector(const FVector& Direction, const FVector& SurfaceNormal);
根据地面的法线向量、Right方向向量、Up向量向量,计算出斜坡的 Roll 和 Pitch 方向的角度
void UKismetMathLibrary::GetSlopeDegreeAngles(const FVector& MyRightYAxis, const FVector& FloorNormal, const FVector& UpVector, 
    float& OutSlopePitchDegreeAngle, float& OutSlopeRollDegreeAngle);

点坐标计算

计算直线外一点到该直线的最近的点(垂足的坐标)
FVector UKismetMathLibrary::FindClosestPointOnLine(FVector Point, FVector LineOrigin, FVector LineDirection);
计算直线与平面交叉点的坐标
bool UKismetMathLibrary::LinePlaneIntersection(const FVector& LineStart, const FVector& LineEnd, 
    const FPlane& APlane, float& T, FVector& Intersection);
计算平面外一点投射到平面的坐标点
FVector UKismetMathLibrary::ProjectPointOnToPlane(FVector Point, FVector PlaneBase, FVector PlaneNormal);
计算线段上到某点的最近的点坐标
//Returns closest point on a segment to a given point.
FVector FMath::ClosestPointOnSegment(const FVector &Point, const FVector &StartPoint, const FVector &EndPoint);
计算线某点到线段的最短距离
//Returns square of the distance from a point to the closest point on a segment.
float FMath::PointDistToSegmentSquared(const FVector &Point, const FVector &StartPoint, const FVector &EndPoint);

向量(矢量)计算

向量A投射到以Z轴为法线的平面的投射向量
/**
 * Projects 2D components of vector based on Z.
 *
 * @return Projected version of vector based on Z.
 */
FVector Projection() const;
计算平面外矢量投射到平面后的矢量
FVector UKismetMathLibrary::ProjectVectorOnToPlane(FVector V, FVector PlaneNormal);

FVector FVector::VectorPlaneProject(const FVector& V, const FVector& PlaneNormal);
计算一组向量的平均向量
FVector GetVectorArrayAverage(const TArray<FVector>& Vectors);
获取反向方向 / 获取A向量相对B向量的镜像向量
/** 
 * Given a direction vector and a surface normal, returns the vector reflected across the surface normal.
 * Produces a result like shining a laser at a mirror!
 *
 * @param Direction Direction vector the ray is coming from.
 * @param SurfaceNormal A normal of the surface the ray should be reflected on.
 *
 * @returns Reflected vector.
 */
static CORE_API FVector GetReflectionVector(const FVector& Direction, const FVector& SurfaceNormal);
获取世界Rotator对应世界坐标系的3个轴向向量

另一种等价表述:以Rotator自身朝向为X轴,获取对应的X、Y、Z轴方向的世界坐标系方向

接口1:

FMatrix RotMatrix = FRotationMatrix(ActorB->GetActorRotation());
FVector ForwardVector = RotMatrix.GetScaledAxis(EAxis::X);
FVector RightVector = RotMatrix.GetScaledAxis(EAxis::Y);
FVector TopVector = RotMatrix.GetScaledAxis(EAxis::Z);

如果是想获取对应的方向向量使用:

FVector FMatrix::GetUnitAxis( EAxis::Type InAxis ) const

接口2:

FRotator TestRot(450.f, 45.f, 0.f);
FVector OutX;
FVector OutY;
FVector OutZ;
UKismetMathLibrary::GetAxes(TestRot, OutX, OutY, OutZ);

接口3:

FVector VecFwd = UKismetMathLibrary::GetForwardVector(TestRot);
FVector VecRight = UKismetMathLibrary::GetRightVector(TestRot);
FVector VecUp = UKismetMathLibrary::GetUpVector(TestRot);
以Rotator自身朝向为X轴,计算指定向量映射在这个局部坐标系X、Y、Z轴方向的局部空间向量
FRotator Rot(45.f, 45.f, 0);
FVector Velocity(90.f, 90.f, 0);
FVector VeclocityInNewDire = Rot.UnrotateVector(Velocity);
float ForwardSpeed = VeclocityInNewDire.X;
float RightSpeed = VeclocityInNewDire.Y;

蓝图示例

UnrotateVector的另一个应用,计算A向量相对B向量的Offset。
示例:

FVector Direction(1.f, 1.f, 0.f);
FVector BaseDire(0, -1.f, 0.f);
FVector OffsetDire = BaseDire.Rotation().UnrotateVector(Direction);
计算向量的相反方向向量
FVector UKismetMathLibrary::NegateVector(FVector A)

或者

FVector Direction;
FVector InverseDire = -Direction;

插值相关

Interpolate

使用简单弹簧模型(Spring)来 interpolate 浮点数值(范围从 Current 到 Target)

float UKismetMathLibrary::FloatSpringInterp(float Current, float Target, UPARAM(ref) FFloatSpringState& SpringState, 
    float Stiffness, float CriticalDampingFactor, float DeltaTime, float Mass = 1.f);

同上,数值类型为 Vector:

FVector UKismetMathLibrary::VectorSpringInterp(FVector Current, FVector Target, UPARAM(ref) FVectorSpringState& SpringState, float Stiffness, float CriticalDampingFactor, float DeltaTime, float Mass = 1.f);

Transform 插值计算:

FTransform UKismetMathLibrary::TInterpTo(const FTransform& Current, const FTransform& Target, float DeltaTime, float InterpSpeed);
Rotation Transform

Transform rotation from World Space to Local Space:

FORCEINLINE FQuat FTransform::InverseTransformRotation(const FQuat& Q) const;

example:

FRotator DestWorldRot(100.f, 100.f, 0.f);
FQuat QuatWorld = DestWorldRot.Quaternion();
FQuat QuatLocal = MyActor->GetComponentTransform().InverseTransformRotation(QuatWorld);
FRotator RotOffset = QuatLocal.Rotator();

Transform rotation from Local Space to World Space:

FORCEINLINE FQuat FTransform::TransformRotation(const FQuat& Q) const;

example:

FRotator DestRotOffset(100.f, 100.f, 0.f);
FRotator DestRotInWorld = FTransform(CameraRotInWorld).TransformRotation(DestRotOffset.Quaternion()).Rotator();
Location Transform

World Space To Local Space:

FORCEINLINE FVector FTransform::InverseTransformPositionNoScale(const FVector &V) const;

Blueprint Node:

InverseTransformLocation

Local Space To World Space:

FORCEINLINE FVector FTransform::TransformPositionNoScale(const FVector& V) const;

If you want only to calculate the Position Offset between two points, Rotation and Scale must be set to Zero. Otherwise the offset Vector would take account of direction. e.g. use FTransform(Comp1->GetComponentLocation()).InverseTransformPosition(Loc2); rather than Comp1->GetComponentTransform().InverseTransformPosition(Loc2);

Direction Transform

World To Local:

FORCEINLINE FVector FTransform::InverseTransformVectorNoScale(const FVector &V) const

example:

//return the offset from Camera's World Rotation to Character's World Rotation.
FRotator ASBaseCharacter::GetAimOffsets() const
{
    const FVector AimDirWS = GetBaseAimRotation().Vector();
    const FVector AimDirLS = ActorToWorld().InverseTransformVectorNoScale(AimDirWS);
    const FRotator AimRotLS = AimDirLS.Rotation();

    return AimRotLS;
}

Origin:
SBaseCharacter in EpicSurvivalGameSeries

Local To World:

FORCEINLINE FVector FTransform::TransformVectorNoScale(const FVector& V) const

If you want to calculate the Offset only between two Rotation (take no account of Location and Scale), the simplest way is to minus:FRotator Offset = R2 - R1;, but the result need to be corrected, because degrees may less than -180 or larger than 180.

Local Space (Position, Direction or Rotation) to World Space

Transform a position:

/** 
 *    Transform a position by the supplied transform.
 *    For example, if T was an object's transform, this would transform a position from local space to world space.
 */
UFUNCTION(BlueprintPure, Category="Math|Transform", meta=(Keywords="location"))
static FVector UKismetMathLibrary::TransformLocation(const FTransform& T, FVector Location);

equals:

FVector FTransform::TransformPosition(const FVector& V) const;

Transform a direction vector:

/** 
 *    Transform a direction vector by the supplied transform - will not change its length. 
 *    For example, if T was an object's transform, this would transform a direction from local space to world space.
 */
UFUNCTION(BlueprintPure, Category="Math|Transform")
static FVector UKismetMathLibrary::TransformDirection(const FTransform& T, FVector Direction);

equals:

FVector FTransform::TransformVectorNoScale(const FVector& V) const;

Transform a rotator:

/** 
 *    Transform a rotator by the supplied transform. 
 *    For example, if T was an object's transform, this would transform a rotation from local space to world space.
 */
UFUNCTION(BlueprintPure, Category="Math|Transform")
static FRotator UKismetMathLibrary::TransformRotation(const FTransform& T, FRotator Rotation);

equals:

FQuat FTransform::TransformRotation(const FQuat& Q) const;
T.TransformRotation(Rotation.Quaternion()).Rotator();
World Space (Position, Direction or Rotation) to Local Space
/** 
 *    Transform a position by the inverse of the supplied transform.
 *    For example, if T was an object's transform, this would transform a position from world space to local space.
 */
UFUNCTION(BlueprintPure, Category="Math|Transform", meta=(Keywords="location"))
static FVector UKismetMathLibrary::InverseTransformLocation(const FTransform& T, FVector Location);

FVector FTransform::InverseTransformPosition(const FVector &V) const;

/** 
 *    Transform a direction vector by the inverse of the supplied transform - will not change its length.
 *    For example, if T was an object's transform, this would transform a direction from world space to local space.
 */
UFUNCTION(BlueprintPure, Category="Math|Transform")
static FVector UKismetMathLibrary::InverseTransformDirection(const FTransform& T, FVector Direction);

/** 
 *    Transform a direction vector by the inverse of this matrix - will not take into account translation part.
 *    If you want to transform a surface normal (or plane) and correctly account for non-uniform scaling you should use TransformByUsingAdjointT with adjoint of matrix inverse.
 */
FVector FTransform::InverseTransformVector(const FVector &V) const;
FVector FTransform::InverseTransformVectorNoScale(const FVector &V) const;

/** 
 *    Transform a rotator by the inverse of the supplied transform. 
 *    For example, if T was an object's transform, this would transform a rotation from world space to local space.
 */
UFUNCTION(BlueprintPure, Category="Math|Transform")
static FRotator UKismetMathLibrary::InverseTransformRotation(const FTransform& T, FRotator Rotation);

FQuat FTransform::InverseTransformRotation(const FQuat& Q) const;
T.InverseTransformRotation(Rotation.Quaternion()).Rotator();

Inner of InverseTransformXXX is using UnrotateVector.

Bezier Cruve

API:

/**
 * Generates a list of sample points on a Bezier curve defined by 2 points.
 *
 * @param ControlPoints    Array of 4 FVectors (vert1, controlpoint1, controlpoint2, vert2).
 * @param NumPoints Number of samples.
 * @param OutPoints Receives the output samples.
 * @return The path length.
 */
static CORE_API float FVector::EvaluateBezier(const FVector* ControlPoints, int32 NumPoints, TArray<FVector>& OutPoints);

Example:

FVector MyControlPoints[4]; 

// Fill out your control points.

TArray<FVector> OutPoints;
FVector::EvaluateBezier(MyControlPoints, 2, OutPoints);

Tutorials

Video Tutorials

Math for Artists | Live from HQ | Inside Unreal
https://www.youtube.com/watch?v=KrghZBIIsXc

无欲则刚,关心则乱。----《论语》