• [UE]常见数学和插值


    参考

    Unreal Transformation
    游戏中的旋转变换——四元数和欧拉角
    UE4 三种旋转 (一)
    UE4_源码浅析篇_矩阵

    unreal中的Transform基础

    Unreal Transformation
    UE4 三种旋转 (一)

    父空间坐标转局部空间坐标。
    FTransform.InverseTransformLocation(FVector Location)
    
    局部空间坐标转父空间坐标。
    FTransform.TransformLocation(FVector Location)
    
    局部空间旋转转父空间旋转。
    FTransform.TransformRotation(FRotator Rotator)
    
    获取使当前坐标系X轴旋转到X_V向量的Rotator。
    MakeRotFromX(FVector X_V)
    template<typename T>
    TMatrix<T> TRotationMatrix<T>::MakeFromX(TVector<T> const& XAxis)
    {
    	TVector<T> const NewX = XAxis.GetSafeNormal();
    
    	// try to use up if possible
    	TVector<T> const UpVector = (FMath::Abs(NewX.Z) < (1.f - UE_KINDA_SMALL_NUMBER)) ? TVector<T>(0, 0, 1.f) : TVector<T>(1.f, 0, 0);
    
    	const TVector<T> NewY = (UpVector ^ NewX).GetSafeNormal();
    	const TVector<T> NewZ = NewX ^ NewY;
    
    	return TMatrix<T>(NewX, NewY, NewZ, TVector<T>::ZeroVector);
    }
    
    
    实际上就是MakeRotFromX(Target-Start)FindLookAtRotation(FVector Start,FVector Target)
    
    // RotationMatrix.h
    // 保证FRotationMatrix的X轴指向给定方向X时,也保证了FRotationMatrix的Y轴约束在给定的方向X和方向Y的平面上,而TRotationMatrix::MakeFromX只指定X轴指向给定方向X,但是Y的方向并没有约束
    FRotationMatrix::MakeFromXY
    
    template<typename T>
    TMatrix<T> TRotationMatrix<T>::MakeFromXY(TVector<T> const& XAxis, TVector<T> const& YAxis)
    {
        // 1. 计算单位向量
    	TVector<T> NewX = XAxis.GetSafeNormal();
    	TVector<T> Norm = YAxis.GetSafeNormal();
    
    	// if they're almost same, we need to find arbitrary vector
    	if (FMath::IsNearlyEqual(FMath::Abs(NewX | Norm), T(1.f)))
    	{
    		// make sure we don't ever pick the same as NewX
    		Norm = (FMath::Abs(NewX.Z) < (1.f - UE_KINDA_SMALL_NUMBER)) ? TVector<T>(0, 0, 1.f) : TVector<T>(1.f, 0, 0);
    	}
    
        // 2. NewZ = NewX 叉乘 Norm
        //    NewY = NewZ 叉乘 NewX 
    	const TVector<T> NewZ = (NewX ^ Norm).GetSafeNormal();
    	const TVector<T> NewY = NewZ ^ NewX;
    
    	return TMatrix<T>(NewX, NewY, NewZ, TVector<T>::ZeroVector);
    }
    
    FRotationMatrix::MakeFromXZ
    template<typename T>
    TMatrix<T> TRotationMatrix<T>::MakeFromXZ(TVector<T> const& XAxis, TVector<T> const& ZAxis)
    {
    	TVector<T> const NewX = XAxis.GetSafeNormal();
    	TVector<T> Norm = ZAxis.GetSafeNormal();
    
    	// if they're almost same, we need to find arbitrary vector
    	if (FMath::IsNearlyEqual(FMath::Abs(NewX | Norm), T(1.f)))
    	{
    		// make sure we don't ever pick the same as NewX
    		Norm = (FMath::Abs(NewX.Z) < (1.f - UE_KINDA_SMALL_NUMBER)) ? TVector<T>(0, 0, 1.f) : TVector<T>(1.f, 0, 0);
    	}
    
    	const TVector<T> NewY = (Norm ^ NewX).GetSafeNormal();
    	const TVector<T> NewZ = NewX ^ NewY;
    
    	return TMatrix<T>(NewX, NewY, NewZ, TVector<T>::ZeroVector);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    FMatrix、FMatrix44f、FMatrix44d

    // Matrix.h, Matrix.inl
    TMatrix<T>
    
    // MathFwd.h
    using FMatrix 		= UE::Math::TMatrix<double>;		// UE_DECLARE_LWC_TYPE(Matrix, 44);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    FMatrix是unreal中表示3D变换的一个4x4的浮点数矩阵,其中前三列代表旋转和缩放,第四列代表平移。
    FMatrix的元素排列方式为列主序(column-major order),即按列顺序依次填写。
    下面是一个示例,展示了如何填写一个包含平移、旋转和缩放的变换矩阵:

    float ScaleX = 1;
    float ScaleY = 2;
    float ScaleZ = 3;
    float RotationPitch = 4;
    float RotationYaw = 5;
    float RotationRoll = 6;
    float TranslationX = 7;
    float TranslationY = 8;
    float TranslationZ = 9;
    
    FMatrix/FMatrix44f/FMatrix44d TransformMatrix;
    TransformMatrix.M[0][0] = ScaleX * FMath::Cos(RotationYaw) * FMath::Cos(RotationRoll);
    TransformMatrix.M[0][1] = ScaleX * FMath::Sin(RotationYaw) * FMath::Cos(RotationRoll);
    TransformMatrix.M[0][2] = -ScaleX * FMath::Sin(RotationRoll);
    TransformMatrix.M[0][3] = 0.0f;
    TransformMatrix.M[1][0] = ScaleY * (FMath::Cos(RotationYaw) * FMath::Sin(RotationRoll) * FMath::Sin(RotationPitch) - FMath::Sin(RotationYaw) * FMath::Cos(RotationPitch));
    TransformMatrix.M[1][1] = ScaleY * (FMath::Sin(RotationYaw) * FMath::Sin(RotationRoll) * FMath::Sin(RotationPitch) + FMath::Cos(RotationYaw) * FMath::Cos(RotationPitch));
    TransformMatrix.M[1][2] = ScaleY * FMath::Cos(RotationRoll) * FMath::Sin(RotationPitch);
    TransformMatrix.M[1][3] = 0.0f;
    TransformMatrix.M[2][0] = ScaleZ * (FMath::Cos(RotationYaw) * FMath::Sin(RotationRoll) * FMath::Cos(RotationPitch) + FMath::Sin(RotationYaw) * FMath::Sin(RotationPitch));
    TransformMatrix.M[2][1] = ScaleZ * (FMath::Sin(RotationYaw) * FMath::Sin(RotationRoll) * FMath::Cos(RotationPitch) - FMath::Cos(RotationYaw) * FMath::Sin(RotationPitch));
    TransformMatrix.M[2][2] = ScaleZ * FMath::Cos(RotationRoll) * FMath::Cos(RotationPitch);
    TransformMatrix.M[2][3] = 0.0f;
    TransformMatrix.M[3][0] = TranslationX;
    TransformMatrix.M[3][1] = TranslationY;
    TransformMatrix.M[3][2] = TranslationZ;
    TransformMatrix.M[3][3] = 1.0f;
    其中,TransformMatrix.M[i][j]表示矩阵中第i列第j行的元素值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    FMatrix、FMatrix44f、FMatrix44d

    相同点

    三者都可以用于表示3D空间中的变换。
    都支持矩阵乘法、加法、减法、转置、求逆等操作。
    都可以相互转换。

    不同点:

    数据类型不同:FMatrix使用单精度浮点数,FMatrix44f使用单精度浮点数,FMatrix44d使用双精度浮点数。
    计算精度不同:FMatrix使用单精度浮点数,精度较低;FMatrix44f使用单精度浮点数,精度较高但是内存占用较大;FMatrix44d使用双精度浮点数,精度最高但是内存占用最大。
    相互转换时需要进行类型转换。
    可以使用强制类型转换来相互转换

    FTranslationMatrix

    平移矩阵,用于表示沿x、y、z轴的平移变换,一个只有平移变换的矩阵。
    构造函数接受一个FVector类型的参数,表示需要进行平移的向量

    FRotationMatrix

    一个只有旋转变换的矩阵

    // RotationMatrix.h
    TRotationMatrix<T>
    
    • 1
    • 2

    FRotationMatrix比较特殊,只能在纯C++中使用,不能用UFUNCTION等暴露给蓝图,见:Unable to find ‘class’, ‘delegate’, ‘enum’, or ‘struct’ with name ‘FRotationMatrix’

    // 编译报错
    UFUNCTION(BlueprintCallable)
    FRotationMatrix Convert(const FRotator& Rot);
    
    // 修改成FMatrix
    UFUNCTION(BlueprintCallable)
    FMatrix Convert(const FRotator& Rot);
    // 函数实现内部可以按照如下方式转换
    FMatrix myRotationMatrix=FRotationMatrix::Make(FRotator(0,0,0));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    FRotationMatrix与FRotator、FQuat的转换

    // 1.FRotator==>FRotationMatrix
    FRotator Rotation(roll, pitch, yaw); //其中roll、pitch和yaw分别表示绕x、y和z轴的旋转角度。
    FMatrix RotationMatrix = FRotationMatrix(Rotation);
    // 2.FRotationMatrix==>FRotator
    FRotationMatrix RotationMatrix = ...;
    FRotator Rotation = RotationMatrix.Rotator();
    
    // 3.FQuat==>FRotationMatrix
    FQuat QuatRotation = ...;
    FRotationMatrix RotationMatrix = FRotationMatrix(QuatRotation.Rotator());
    // 4.FRotationMatrix==>FQuat
    FRotationMatrix RotationMatrix = ...;
    FQuat RotationQuat = RotationMatrix.ToQuat();
    FQuat QuatRotation = FQuat(RotationMatrix);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    TRotator

    欧拉角,FRotator是一个包含三个浮点数Pitch、Yaw、Roll的结构体,用于表示3D旋转。

    TRotator<T>: Rotator.h
    // 注意FRotator的构造函数中参数顺序是 Pitch, Yaw, Roll
    // Pitch:俯仰角,即绕Y轴旋转;
    // Yaw:偏角,即绕Z轴旋转;
    // Roll:滚角,即绕X轴旋转。
    FORCEINLINE TRotator( T InPitch, T InYaw, T InRoll );
    // UKismetMathLibrary::MakeRotator中的顺序是Roll, Pitch, Yaw
    FRotator UKismetMathLibrary::MakeRotator(float Roll, float Pitch, float Yaw)
    {
    	return FRotator(Pitch,Yaw,Roll);
    }
    
    // MathFwd.h
    using FRotator 		= UE::Math::TRotator<double>;		// UE_DECLARE_LWC_TYPE(Rotator, 3);
    
    // 使用示例
    //绕`z`轴旋转10度
    FRotator rotator(0, 10, 0); 
    AActorT->SetActorRotation(rotator);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    FQuat

    四元数,x、y、z、w。用于表示3D旋转。四元数比欧拉角更加高效. FQuat通常用于表示游戏角色的旋转。避免万向锁,以及更方便做差值计算。

    FQuat(FVector Axis, float AngleRad)
    
    struct FQuat 
    {
    	public:
    		/** The quaternion's X-component. */
    		float X;
    		/** The quaternion's Y-component. */
    		float Y;
    		/** The quaternion's Z-component. */
    		float Z;
    		/** The quaternion's W-component. */
    		float W;
    }
    
    // 构造函数: 创建和初始化一个新的四元数(根据给定轴旋转 a 弧度)
    FQuat(FVector Axis, float AngleRad)
    
    //绕z轴旋转45度
    FQuat quat = FQuat(FVector(0, 0, 1), PI / 4.f); 
    GetOwner()->SetActorRotation(quat);
    
    FQuat axisRot(FVector::RightVector, FMath::DegreesToRadians(90));
    SetActorRotation((GetActorRotation().Quaternion() * axisRot).Rotator());
    
    FQuat axisRot(FVector::UpVector, FMath::DegreesToRadians(90);
    SetActorRotation((axisRot * GetActorRotation().Quaternion()).Rotator());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    FScaleMatrix

    缩放矩阵,用于表示沿x、y、z轴的缩放变换,一个只有缩放变换的矩阵。

    FTransform

    FTranslationMatrix、FRotationMatrix、FScaleMatrix来构建一个FTransform

    FVector ScaleVector = FVector(2.f, 3.f, 4.f);
    FScaleMatrix ScaleMatrix(ScaleVector);
    
    FRotator Rotation(0.f, 45.f, 0.f);
    FRotationMatrix RotationMatrix = FRotationMatrix(Rotation);
    
    FVector Translation(100.0f, 200.0f, 300.0f);
    FTranslationMatrix TranslationMatrix(Translation);
    
    FTransform Transform(RotationMatrix.ToQuat(), TranslationMatrix.GetOrigin(), ScaleMatrix.GetScaleVector());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    关于旋转的几个常见示例

    1. 将不限范围的角度转换到[0, 360)

    UKismetMathLibrary::ClampAxis

    // KismetMathLibrary.cpp
    float UKismetMathLibrary::ClampAxis(float Angle)
    {
    	return FRotator::ClampAxis(Angle);
    }
    // Rotator.h
    template<typename T>
    FORCEINLINE T TRotator<T>::ClampAxis( T Angle )
    {
    	// returns Angle in the range (-360,360)
    	Angle = FMath::Fmod(Angle, (T)360.0);
    
    	if (Angle < (T)0.0)
    	{
    		// shift to [0,360) range
    		Angle += (T)360.0;
    	}
    
    	return Angle;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.A位置的actor看向B位置

    A位置的actor看向B位置,实际就是将A位置的actor的forward vector转向A->B

    2.1KismetMathLibrary.FindLookAtRotation/UKismetMathLibrary::MakeRotFromX/KismetMathLibrary.MakeRotFromXY

    // 解释
    KismetMathLibrary.FindLookAtRotation 等价于 UKismetMathLibrary::MakeRotFromX 等价于
    TVector<T>::ToOrientationRotator() 等价于
    TVector<T>::Rotation()
    
    // 源码 Vector.h
    FORCEINLINE UE::Math::TRotator<T> Rotation() const
    {
    	return ToOrientationRotator();
    }
    // UnrealMath.cpp
    template<typename T>
    UE::Math::TRotator<T> UE::Math::TVector<T>::ToOrientationRotator() const
    {
    	UE::Math::TRotator<T> R;
    	// Find yaw.
    	R.Yaw = FMath::RadiansToDegrees(FMath::Atan2(Y, X));
    	// Find pitch.
    	R.Pitch = FMath::RadiansToDegrees(FMath::Atan2(Z, FMath::Sqrt(X*X + Y*Y)));
    	// Find roll.
    	R.Roll = 0;
    	...
    	return R;
    }
    
    
    // MakeRotFromXY相比MakeRotFromX,除了使forward vector指向X外,还约束了right vector在XY平面上,
    KismetMathLibrary.MakeRotFromXY
    KismetMathLibrary.MakeRotFromXZ
    
    // 示例
    FVector LookDirection = target->GetActorLocation() - GetOwner()->GetActorLocation(); 
    FMatrix LookRotationMatrix = FRotationMatrix::MakeFromXZ(LookDirection, GetOwner()->GetActorUpVector()); 
    GetOwner()->SetActorRotation(LookRotationMatrix.Rotator());
    
    
    // 源码KismetMathLibrary.inl
    FRotator UKismetMathLibrary::FindLookAtRotation(const FVector& Start, const FVector& Target)
    {
    	return MakeRotFromX(Target - Start);
    }
    FRotator UKismetMathLibrary::MakeRotFromX(const FVector& X)
    {
    	return FRotationMatrix::MakeFromX(X).Rotator();
    }
    
    FRotator UKismetMathLibrary::MakeRotFromXY(const FVector& X, const FVector& Y)
    {
    	return FRotationMatrix::MakeFromXY(X, Y).Rotator();
    }
    
    
    FRotator UKismetMathLibrary::MakeRotFromXZ(const FVector& X, const FVector& Z)
    {
    	return FRotationMatrix::MakeFromXZ(X, Z).Rotator();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    2.2 UKismetMathLibrary::Conv_VectorToRotator

    // 求出令forward vector和InVec同向的FRotator
    FRotator UKismetMathLibrary::Conv_VectorToRotator(FVector InVec)
    
    // KismetMathLibrary.inl
    KISMET_MATH_FORCEINLINE
    FRotator UKismetMathLibrary::Conv_VectorToRotator(FVector InVec)
    {
    	return InVec.ToOrientationRotator();
    }
    // UnrealMath.cpp
    template<typename T>
    UE::Math::TRotator<T> UE::Math::TVector<T>::ToOrientationRotator() const
    {
    	UE::Math::TRotator<T> R;
    	// Find yaw.
    	R.Yaw = FMath::RadiansToDegrees(FMath::Atan2(Y, X));
    	// Find pitch.
    	R.Pitch = FMath::RadiansToDegrees(FMath::Atan2(Z, FMath::Sqrt(X*X + Y*Y)));
    	// Find roll.
    	R.Roll = 0;
    #if ENABLE_NAN_DIAGNOSTIC || (DO_CHECK && !UE_BUILD_SHIPPING)
    	if (R.ContainsNaN())
    	{
    		logOrEnsureNanError(TEXT("TVector::Rotation(): Rotator result %s contains NaN! Input FVector = %s"), *R.ToString(), *this->ToString());
    		R = UE::Math::TRotator<T>::ZeroRotator;
    	}
    #endif
    
    	return R;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3.RotateVector和UnrotateVector

    旋转矩阵是正交矩阵,逆等于转置, 旋转矩阵(Rotate Matrix)的性质分析

    UnrotateVector: 将世界坐标系下的向量转换到旋转矩阵表示的局部坐标系下
    RotateVector: 将向量从旋转矩阵表示的局部坐标系下转换到世界坐标系下
    使用示例1:让A点绕B点旋转:UE4之A点绕B点旋转
    使用示例2:ALS中相机镜头控制部分的插值逻辑 AALSPlayerCameraManager::CalculateAxisIndependentLag

    // 关于RotateVector和UnrotateVector的作用,在ALS的相机镜头控制中使用示例如下
    // 先用UnrotateVector转换到相机旋转矩阵表示的局部坐标系下,然后在局部坐标系下的三个轴分别插值
    // 然后将插值结果用RotateVector局部坐标系下转换到世界坐标系下
    // 区别直接在世界坐标系下的三个轴插值分别插值,
    FVector AALSPlayerCameraManager::CalculateAxisIndependentLag(FVector CurrentLocation, FVector TargetLocation,
                                                                 FRotator CameraRotation, FVector LagSpeeds,
                                                                 float DeltaTime)
    {
    	CameraRotation.Roll = 0.0f;
    	CameraRotation.Pitch = 0.0f;
    	const FVector UnrotatedCurLoc = CameraRotation.UnrotateVector(CurrentLocation);
    	const FVector UnrotatedTargetLoc = CameraRotation.UnrotateVector(TargetLocation);
    
    	const FVector ResultVector(
    		FMath::FInterpTo(UnrotatedCurLoc.X, UnrotatedTargetLoc.X, DeltaTime, LagSpeeds.X),
    		FMath::FInterpTo(UnrotatedCurLoc.Y, UnrotatedTargetLoc.Y, DeltaTime, LagSpeeds.Y),
    		FMath::FInterpTo(UnrotatedCurLoc.Z, UnrotatedTargetLoc.Z, DeltaTime, LagSpeeds.Z));
    
    	return CameraRotation.RotateVector(ResultVector);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    dir_rot.RotateVector(ue.Vector(-150, 30, 20))
    // Rotator.h
    CORE_API TVector<T> RotateVector( const UE::Math::TVector<T>& V ) const;
    // UnrealMath.cpp
    template<typename T>
    UE::Math::TVector<T> UE::Math::TRotator<T>::UnrotateVector(const UE::Math::TVector<T>& V) const
    {
    	return UE::Math::TRotationMatrix<T>(*this).GetTransposed().TransformVector( V );
    }	
    
    template<typename T>
    UE::Math::TVector<T> UE::Math::TRotator<T>::RotateVector(const UE::Math::TVector<T>& V) const
    {
    	return UE::Math::TRotationMatrix<T>(*this).TransformVector( V );
    }	
    
    // Quat.h
    template<typename T>
    FORCEINLINE TVector<T> TQuat<T>::RotateVector(TVector<T> V) const
    {	
    	// http://people.csail.mit.edu/bkph/articles/Quaternions.pdf
    	// V' = V + 2w(Q x V) + (2Q x (Q x V))
    	// refactor:
    	// V' = V + w(2(Q x V)) + (Q x (2(Q x V)))
    	// T = 2(Q x V);
    	// V' = V + w*(T) + (Q x T)
    
    	const TVector<T> Q(X, Y, Z);
    	const TVector<T> TT = 2.f * TVector<T>::CrossProduct(Q, V);
    	const TVector<T> Result = V + (W * TT) + TVector<T>::CrossProduct(Q, TT);
    	return Result;
    }
    
    template<typename T>
    FORCEINLINE TVector<T> TQuat<T>::UnrotateVector(TVector<T> V) const
    {	
    	const TVector<T> Q(-X, -Y, -Z); // Inverse
    	const TVector<T> TT = 2.f * TVector<T>::CrossProduct(Q, V);
    	const TVector<T> Result = V + (W * TT) + TVector<T>::CrossProduct(Q, TT);
    	return Result;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    插值相关

    旋转插值Math.RInterpTo

    // UnrealMath.cpp
    // 注意,插值速度小于等于0时,直接返回的是Target
    在这里插入图片描述

    标量插值Math.FInterpTo

    // 注意,插值速度小于等于0时,直接返回的是Target

    // UnrealMathUtility.h
    
        /** Interpolate float from Current to Target. Scaled by distance to Target, so it has a strong start speed and ease out. */
    	template<typename T1, typename T2 = T1, typename T3 = T2, typename T4 = T3>
    	UE_NODISCARD static auto FInterpTo( T1  Current, T2 Target, T3 DeltaTime, T4 InterpSpeed )
    	{
    		using RetType = decltype(T1() * T2() * T3() * T4());
    	
    		// If no interp speed, jump to target value
    		if( InterpSpeed <= 0.f )
    		{
    			return static_cast<RetType>(Target);
    		}
    
    		// Distance to reach
    		const RetType Dist = Target - Current;
    
    		// If distance is too small, just set the desired location
    		if( FMath::Square(Dist) < UE_SMALL_NUMBER )
    		{
    			return static_cast<RetType>(Target);
    		}
    
    		// Delta Move, Clamp so we do not over shoot.
    		const RetType DeltaMove = Dist * FMath::Clamp<RetType>(DeltaTime * InterpSpeed, 0.f, 1.f);
    
    		return Current + DeltaMove;				
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    FMath::Lerp/FMath::FInterpConstantTo

    可以看看UE4 插值相关函数中的插值过程图示意

    TickComponent: 中
    	TargetYaw = 90
    	FRotator OpenDoor(0.f,TargetYaw,0.f);
    	OpenDoor.Yaw = FMath::Lerp(CurrentYaw, TargetYaw,0.02f);
    	// 插值的速度与帧率无关
        OpenDoor.Yaw = FMath::FInterpConstantTo(CurrentYaw, TargetYaw,DeltaTime,45);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    FMath::Lerp线性插值的问题。OpenDoor.Yaw会一直接近90度,但是不会到达90度。同时电脑帧率快慢会影响OpenDoor.Yaw插值的速度

    KismetMathLibrary::VLerp

    在两个向量之间进行比例插值

    UKismetMathLibrary::Ease

    UKismetMathLibrary::Ease
    提供了多种内置的缓动插值方式

    Debug相关

    Unreal engine 4 C 一些调试用的绘制函数

    // 头文件
    #include "DrawDebugHelpers.h"
    
    // 几个示例
    点:  DrawDebugPoint(GetWorld(), LocationOne, 200, FColor(52,220,239), true, 999);
    球体:DrawDebugSphere(GetWorld(), LocationTwo, 200, 26, FColor(181,0,0), true, 999, 0, 2);
    圆:  DrawDebugCircle(GetWorld(), CircleMatrix, 200, 50, FColor(0,104,167), true, 999, 0, 10);
    	  DrawDebugCircle(GetWorld(), LocationFour, 200, 50, FColor(0,0,0), true, 999, 0, 10);
    	  DrawDebugSolidBox(GetWorld(), MyBox, FColor(20, 100, 240), MyTransform, true, 999);
    盒:  DrawDebugBox(GetWorld(), LocationFive, FVector(100,100,100), FColor::Purple, true, 999, 0, 10);
    线:  DrawDebugLine(GetWorld(), LocationTwo, LocationThree, FColor::Emerald, true, 999, 0, 10);
    方向箭头:DrawDebugDirectionalArrow(GetWorld(), FVector(-300, 600, 600), FVector(-300, -600, 600), 120.f, FColor::Magenta, true, 999, 0, 5.f);
    交叉准星:DrawDebugCrosshairs(GetWorld(), FVector(0,0,1000), FRotator(0,0,0), 500.f, FColor::White, true, 999, 0);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    KismetMathLibrary

    KismetMathLibrary库为常用的数学使用库,包含了对向量、矩阵等数学变量的常规操作;

    // 头文件
    #include "Kismet/KismetMathLibrary.h"
    
    // 一些常用示例
    // Cur_Pitch: [0, 360), Min_Pitch:[-180, 0), Max_Pitch:[0, 180)
    // 将[0, 360)的输入角Cur_Pitch 限制到[-180, 180)之间,返回的是一个[-180, 180)之间的角度
    Ret_Pitch = KismetMathLibrary.ClampAngle(Cur_Pitch, Min_Pitch, Max_Pitch)
    // 将[-180, 180)之间的角度转换回[0, 360)之间
    UE::Math::TRotator<T>::ClampAxis
    // 将[0, 360)之间的角度转换回[-180, 180)之间
    UE::Math::TRotator<T>::NormalizeAxis
    
    
    // 求出从一个点看向另一个点时的Rotator
    KismetMathLibrary.FindLookAtRotation
    
    // 求出令forward vector和InVec同向的FRotator
    KismetMathLibrary.Conv_VectorToRotator
    
    KismetMathLibrary.MakeRotFromZX
    KismetMathLibrary.MakeRotFromZY
    KismetMathLibrary.MakeRotFromZX
    
    KismetMathLibrary.DegAcos
    KismetMathLibrary.DegreesToRadians
    KismetMathLibrary.FMod
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    GameplayStatics

    UGameplayStatics类实用分析

    GameplayStatics库为常用的Gameplay操作库,包含Gameplay操作的各类静态函数

    // 头文件
    #include "Kismet/GameplayStatics.h"
    
    
    
    • 1
    • 2
    • 3
    • 4

    Python的Math

    atan2和atan

    python中 math模块下 atan 和 atan2的区别
    在这里插入图片描述

    atan2(y, x) 返回射线从原点到点 (x, y) 与正 x 轴之间的角度 θ,限制为 (−π, π]。

    在这里插入图片描述

    在这里插入图片描述
    从 −π 到 +π 的切函数图,带有相应的 y/x 符号。绿色箭头指向 atan2(−1, −1) 和 atan2(1, 1) 的结果。

    如果 x > 0,则所需的角度测量值为 atan2(y, x)=arctan(y/x),但是,当 x < 0 时,角度与所需角度 arctan(y/x)截然相反,并且必须添加±π(半圈)才能将点放置在正确的象限中。 [1] 使用该 atan2 函数可以消除这种更正,简化代码和数学公式

  • 相关阅读:
    【瑞萨零基础入门】瑞萨MCU零基础入门系列教程(更新连载中)
    CIFAR-10 数据集简介
    Driud数据库连接池的使用
    绘制几何图形
    【P53】基于TPS61093的典型单电源转双电源电路
    用回调函数封装AJAX 和 jquery框架
    Android Framework如何从萌白到封神学习?
    Unity中国成立,以应对国内日益严格的数据处理法规
    JVM coredump
    内存函数的介绍和模拟实现
  • 原文地址:https://blog.csdn.net/qq_35987777/article/details/132196260