UE4 - 基础篇:矩阵是什么?
想看为什么不问我要密码呢?想看为什么不问我要密码呢?想看为什么不问我要密码呢?想看为什么不问我要密码呢?
在哪些辅助项目中,所谓的矩阵就是视图投影矩阵(有些人喜欢叫他相口)。在UE4源码中,这个矩阵通常被命名为:
ULocalPlayer::ViewProjectionMatrixFSceneView::ViewProjectionMatrix
这个矩阵包含了相机的变换信息,用于将世界坐标转换为屏幕坐标。一般ESP绘制方框的基本步骤是:
获取实体的世界坐标(World Position),又叫做WorldLocation。
获取玩家相机的ViewProjectionMatrix
使用矩阵乘法:
世界坐标 × ViewProjectionMatrix = 屏幕坐标使用转换后的屏幕坐标绘制2D方框
如果您想找到这个矩阵的具体内存位置, 建议一般是:
在游戏进程中搜索类似矩阵的特征值
通过UE4的GEngine等全局对象来定位
查找引擎渲染相关的函数调用链
在虚幻引擎中有保存好了的视图投影矩阵,我们可以直接从内存中去读取,当然你也可以口算这个矩阵....
不是白痴可以跳过这节
欧拉角
我这里有个小工具可以实现四元数和欧拉角的转换,还能复刻万向死锁呢 >> 伏秋洛的小玩具
哦,你说我这个小玩具不直观?其实我还有一个https://compsci290-s2016.github.io/CoursePage/Materials/EulerAnglesViz/
Euler angles,莱昂哈德·欧拉用欧拉角来描述刚体在三维欧几里得空间的取向。对于任何参考系,一个刚体的取向,是依照顺序,从这参考系,做三个欧拉角的旋转而设定的。所以,刚体的取向可以用三个基本旋转矩阵来决定。换句话说,任何关于刚体旋转的旋转矩阵是由三个基本旋转矩阵复合而成的。

其实我也不能说什么,我数学一坨狗屎吧,这里有一个文档说的比较清晰
这里说一下Pitch/Yaw/Roll的区别

机体坐标系:固定在飞行器上的坐标系,一般沿机身方向为X轴,沿机翼方向为Y轴,垂直机身方向为Z轴,如上图所示。下面说的旋转都是指沿机体坐标系。
这里有一个著名的弱智知识《万向死锁》
其实就是欧拉角的定义出现了问题,无法修复,是一个软件问题,没什么好讨论的,好吧,我说一下就是:欧拉角是一个按指定顺序的变换。
视图矩阵
UE的视图矩阵(View Matrix)是一个4x4的矩阵,用于将物体从世界空间转换到摄像机空间(也叫观察空间)。这个东西的作用就是将世界空间中的点转换到摄像机空间,其定义了摄像机的位置(Eye)和方向(Forward, Right, Up),是渲染管线中的关键变换矩阵之一。
在ue中可以通过一些调用获取视图矩阵
// 从PlayerController获取
FMatrix ViewMatrix = PlayerController->PlayerCameraManager->GetCameraViewMatrix();
// 从Camera组件获取
FMatrix ViewMatrix = CameraComponent->GetComponentToWorld().ToMatrixNoScale().Inverse();视图矩阵的变换顺序:
先平移:将场景原点移动到摄像机位置
再旋转:将场景按摄像机的方向进行旋转
最终结果:物体从世界空间变换到以摄像机为原点的观察空间
// 最终屏幕上的点 = 投影矩阵 * 视图矩阵 * 世界矩阵 * 物体本地坐标
FVector4 ScreenPosition = ProjectionMatrix * ViewMatrix * WorldMatrix * LocalPosition;这里有一些课程视频:
需要注意的是,ue中视图矩阵的格式是:
{ M[0][0] = InX.X; M[0][1] = InX.Y; M[0][2] = InX.Z; M[0][3] = 0.0f; M[1][0] = InY.X; M[1][1] = InY.Y; M[1][2] = InY.Z; M[1][3] = 0.0f; M[2][0] = InZ.X; M[2][1] = InZ.Y; M[2][2] = InZ.Z; M[2][3] = 0.0f; M[3][0] = InW.X; M[3][1] = InW.Y; M[3][2] = InW.Z; M[3][3] = 1.0f; }
口算视图投影矩阵
首先我们要获取到当前人物的Rotation和Location构建ViewMatrix。
哦,这个东西有个缺点,因为在UE外挂开发里面,我们一般是不知道相机的Rota和Loc的,所以说用人物的绘制,可能因为别的视野按钮的移动导致绘制偏移,这是我们不愿意看到的,但是还是和你说一下口算吧...
首先需要将欧拉角转换为方向向量(要转换是因为你可以获取到的Rotation使用的是FRotator保存的):
// pitch(X), yaw(Y), roll(Z)
FVector GetForwardVector(FRotator rotation) {
float cp = cos(rotation.pitch * PI / 180); // c++三角函数用的是弧度,而ue里面的rota是度(degree)
float sp = sin(rotation.pitch * PI / 180);
float cy = cos(rotation.yaw * PI / 180);
float sy = sin(rotation.yaw * PI / 180);
return FVector(cp * cy, cp * sy, sp);
}
FVector GetRightVector(FRotator rotation) {
float cy = cos(rotation.yaw * PI / 180);
float sy = sin(rotation.yaw * PI / 180);
return FVector(sy, -cy, 0);
}
FVector GetUpVector(FRotator rotation) {
float cp = cos(rotation.pitch * PI / 180);
float sp = sin(rotation.pitch * PI / 180);
float cy = cos(rotation.yaw * PI / 180);
float sy = sin(rotation.yaw * PI / 180);
return FVector(-sp * cy, -sp * sy, cp);
}然后我们构建视图矩阵:
FMatrix BuildViewMatrix(FVector location, FRotator rotation) {
FVector forward = GetForwardVector(rotation);
FVector right = GetRightVector(rotation);
FVector up = GetUpVector(rotation);
// 构建旋转矩阵
FMatrix viewMatrix;
viewMatrix.M[0][0] = right.x;
viewMatrix.M[0][1] = right.y;
viewMatrix.M[0][2] = right.z;
viewMatrix.M[1][0] = up.x;
viewMatrix.M[1][1] = up.y;
viewMatrix.M[1][2] = up.z;
viewMatrix.M[2][0] = -forward.x;
viewMatrix.M[2][1] = -forward.y;
viewMatrix.M[2][2] = -forward.z;
// 加入平移
viewMatrix.M[3][0] = -(location.x * right.x + location.y * right.y + location.z * right.z);
viewMatrix.M[3][1] = -(location.x * up.x + location.y * up.y + location.z * up.z);
viewMatrix.M[3][2] = (location.x * forward.x + location.y * forward.y + location.z * forward.z);
viewMatrix.M[3][3] = 1.0f;
return viewMatrix;
}PS:
UE4中角度是以度为单位,需要转换为弧度
Forward向量在ViewMatrix中需要取负值
Translation部分也需要取负值