struct FVector { public: /** Vector's X component. */ float X; /** Vector's Y component. */ float Y; /** Vector's Z component. */ float Z; }
最基本也是最重要的向量类了,包含了大量的变换和操作,涉及到很多的数学内容。
一些基本的常量向量:
/** A zero vector (0,0,0) */ static CORE_API const FVector ZeroVector; /** One vector (1,1,1) */ static CORE_API const FVector OneVector; /** Unreal up vector (0,0,1) */ static CORE_API const FVector UpVector; /** Unreal down vector (0,0,-1) */ static CORE_API const FVector DownVector; /** Unreal forward vector (1,0,0) */ static CORE_API const FVector ForwardVector; /** Unreal backward vector (-1,0,0) */ static CORE_API const FVector BackwardVector; /** Unreal right vector (0,1,0) */ static CORE_API const FVector RightVector; /** Unreal left vector (0,-1,0) */ static CORE_API const FVector LeftVector;
基本操作
/** * Calculate the cross product of two vectors. * * @param A The first vector. * @param B The second vector. * @return The cross product. */ FORCEINLINE FVector FVector::operator^(const FVector& V) const { return FVector ( Y * V.Z - Z * V.Y, Z * V.X - X * V.Z, X * V.Y - Y * V.X ); }
向量叉乘,[latex]\begin{bmatrix} x1\\y1\\ z1 \end{bmatrix}\times \begin{bmatrix} x2 \\ y2 \\ z2 \end{bmatrix}= \begin{bmatrix} y1z2-z1y2 \\ z1x2-x1z2 \\ x1y2-y1x2 \end{bmatrix}[/latex]
基本的向量操作都有了,比如数乘,点乘,叉乘之类的。需要注意的是,向量点乘重写的运算符是|,叉乘重写的运算符是^,运算符*/是分量的/。不过为了避免失误,还是用DotProduct,CrossProduct最好。
FVector v1(2, 4, 6), v2(-1, -2, -3); float dotProduct = v1 | v2;//-28 FVector crossProduct = v1 ^ v2;// (0,0,0) FVector componentDivide = v1 / v2;//(-2,-2,-2) FVector componentProduct = v1 * v2;//(-2,-8,-18)
归一化
向量的归一化函数有两个,一个是Safe的,一个是UnSafe的,这种形式在其他的向量类里面也有。区别在于,UnSafe的是直接计算的,而Safe的会先计算向量的模(平方),然后把零向量和单位向量先处理了。
/** * Calculates normalized version of vector without checking for zero length. * * @return Normalized version of vector. * @see GetSafeNormal() */ FORCEINLINE FVector GetUnsafeNormal() const; /** * Gets a normalized copy of the vector, checking it is safe to do so based on the length. * Returns zero vector if vector length is too small to safely normalize. * * @param Tolerance Minimum squared vector length. * @return A normalized copy if safe, (0,0,0) otherwise. */ FVector GetSafeNormal(float Tolerance=SMALL_NUMBER) const;
另外,还有GetSafeNormal2D的函数,仅仅针对x,y分量操作。
void ToDirectionAndLength(FVector &OutDir, float &OutLength) const;
获取当前向量的长度及单位方向向量。
平面投影
将向量投影到z=1的平面,各分量除以z。
/** * Projects 2D components of vector based on Z. * * @return Projected version of vector based on Z. */ FVector Projection() const;
FVector GridSnap(const float& GridSz) const;
按Gridsz将空间划分网格,获取离网格最近的那个点。实现方式是逐个计算每一个分量最近的点。这个函数主要用于计算对齐到网格。
/** Snaps a value to the nearest grid multiple */ static FORCEINLINE float GridSnap( float Location, float Grid ) { if( Grid==0.f ) return Location; else { return FloorToFloat((Location + 0.5*Grid)/Grid)*Grid; } }
关键函数是FloorToFloat((Location + 0.5Grid)/Grid)*Grid;
考虑在数轴上的整数x,如果Location在x的(0.5,0.5)范围内,那么floor(x+0.5)操作会返回x,从而可以计算离Location最近的整数点。上述操作类似。
FVector BoundToBox(const FVector& Min, const FVector Max) const;
获取Vector限制在Box中的向量,如果Vector的某些分量越界,则限制为边界值,用过Clamp系列函数的人应该不会陌生。类似的函数还有一些。
/** * Get a copy of this vector, clamped inside of a cube. * * @param Radius Half size of the cube. * @return A copy of this vector, bound by cube. */ FVector BoundToCube(float Radius) const; /** Get a copy of this vector, clamped inside of a cube. */ FVector BoundToBox(const FVector& Min, const FVector Max) const; /** Create a copy of this vector, with its magnitude clamped between Min and Max. */ FVector GetClampedToSize(float Min, float Max) const; /** Create a copy of this vector, with the 2D magnitude clamped between Min and Max. Z is unchanged. */ FVector GetClampedToSize2D(float Min, float Max) const; /** Create a copy of this vector, with its maximum magnitude clamped to MaxSize. */ FVector GetClampedToMaxSize(float MaxSize) const; /** Create a copy of this vector, with the maximum 2D magnitude clamped to MaxSize. Z is unchanged. */ FVector GetClampedToMaxSize2D(float MaxSize) const; /** * Add a vector to this and clamp the result in a cube. * * @param V Vector to add. * @param Radius Half size of the cube. */ void AddBounded(const FVector& V, float Radius=MAX_int16);
FVector Reciprocal() const;
各分量求倒数
镜像和反射
FVector MirrorByVector(const FVector& MirrorNormal) const;
这个函数的名字起的很奇怪,一开始我以为是计算被单位向量映射后的向量,然后推算出来的结果和代码的结果方向相反,查阅代码后发现这个函数主要是用来计算碰撞后的速度,其实就是入射角=反射角,mirrorNormal为碰撞点的法向量。如果BO是入射速度,那么OC为反射后的速度。
推算过程:OB在单位向量mirror上的投影OD=mirror*|OB|*cosα = mirror*|OB|*OB●mirror/|OB|/|mirror|=mirror*(OB ● mirror),然后BD=OD-OB,BC=2BD,OC=OB+BC, 化简后为OC = -OB + 2mirror(OB ● mirror)
FORCEINLINE FVector FVector::MirrorByVector(const FVector& MirrorNormal) const { return *this - MirrorNormal * (2.f * (*this | MirrorNormal)); }
FVector MirrorByPlane(const FPlane& Plane) const;
和上一个类似,只不过在单位向量(平面单位法向量)上的投影为点到平面的距离,这个距离为PlaneDot。
inline FVector FVector::MirrorByPlane( const FPlane& Plane ) const { return *this - Plane * (2.f * Plane.PlaneDot(*this) ); }
旋转
/** * Rotates around Axis (assumes Axis.Size() == 1). * * @param Angle Angle to rotate (in degrees). * @param Axis Axis to rotate around. * @return Rotated Vector. */ FVector RotateAngleAxis(const float AngleDeg, const FVector& Axis) const;
将向量围绕向量Axis旋转一个角度后的向量,详细推算过程可见3D数学8.2.3(P91),UE的实现基本一致。
投影
/** * Gets a copy of this vector projected onto the input vector. * * @param A Vector to project onto, does not assume it is normalized. * @return Projected vector. */ FORCEINLINE FVector FVector::ProjectOnTo(const FVector& A) const { return (A * ((*this | A) / (A | A))); } /** * Gets a copy of this vector projected onto the input vector, which is assumed to be unit length. * * @param Normal Vector to project onto (assumed to be unit length). * @return Projected vector. */ FORCEINLINE FVector ProjectOnToNormal(const FVector& Normal) const;
计算一个向量在另外一个向量上面的投影。比如要将b投影到a,投影向量 c = a / |a| * |b| * cos α = a / |a| * |b| * (ab/|a||b|) = a * (ab) / (|a| * |a|)。如果是单位向量,则结果是 a * (ab)
相关文章
- 03-06JS求随机数 Math.floor(Math.random() * (max - min + 1)) + min 理解
- 03-06Unreal Math: 坐标系
- 03-06Unreal Math: FVector(1)
- 03-06Codeforces Round #272 (Div. 1) B 构造 math
- 03-06Math(1)---Eigen稀疏矩阵乘法
- 03-06[CISCN 2019 初赛]Love Math 1
- 03-06JS 1-10 Math 常用的对象
- 03-06Math.abs(~2020) 按位取反后的绝对值是多少 2021, 按位取反后,比正数多1
- 03-062015弱校联盟(1) -A. Easy Math
- 03-06BUUCTF WEB LOVE_MATH1