对于我为 3D 游戏制作的屏幕叠加层,我需要在 3D 世界中的某些位置上显示图标。我已经设法从游戏中获得了几个使这成为可能的变量:
- 玩家位置 (x,y,z)
- 相机位置 (x,y,z)
- 点位置 (x,y,z)
- 相机角度(FOV)
使用这些变量,我设法获得了相机视图的左右边缘。使用这 2 个变量,我可以获得 0 到 1 之间的点,该点应在 x 轴上显示图标。(0 在左边缘,1 在右边缘)这似乎工作得很好,但前提是我与 X 或 Z 轴对齐,如下例所示:
我一直在尝试使用以下旋转矩阵来解决这个问题:
[ Math.Cos(angle), -Math.Sin(angle) ]
[ Math.Sin(angle), Math.Cos(angle) ]
我所做的是,我将玩家位置、相机位置和相机边缘位置放在矩阵中,并以世界点作为旋转点。问题是,只要我将角度量设为 90 度,X 和 Y 就会被翻转。几天来我一直在努力寻找解决方案,但我找不到它,所以我希望任何人都可以在这里推动我朝着正确的方向前进。以下是我的代码的一些部分,可能有助于找到解决方案:
float PCDistXZ = (float)Math.Sqrt(deltaPCx * deltaPCx + deltaPCz * deltaPCz); // X/Z distance from the world point to the camera
Point fakeAvatarPos = RotateAround(new Point((int)point.x, (int)point.z), new Point((int)avatar.x, (int)avatar.z), (int)90);
Point fakeCameraPos = RotateAround(new Point((int)point.x, (int)point.z), new Point((int)camera.x, (int)camera.z), (int)90);
double edgeRight = fakeC.X + (Math.Sin(45) * PCDistXZ);
double edgeLeft = fakeC.X - (Math.Sin(45) * PCDistXZ);
float edgeTest_ScreenPositionX = (1 - (float)((edgeRight - P.x) / (edgeRight - edgeLeft))) * screenWidth;
public static Point RotateAround(Point pCenter,Point pPoint, float pAngle)
{
double angle = (pAngle * Math.PI) / 180;
double[,] matrix = new Double[2, 2] {
{ Math.Cos(angle), Math.Sin(angle) },
{ Math.Sin(angle), Math.Cos(angle) }
};
double xOffset = pPoint.X - pCenter.X;
double yOffset = pPoint.Y - pCenter.Y;
Point newPoint = new Point(
(int)(((pPoint.X - xOffset) * matrix[0, 0]) - ((pPoint.Y - xOffset) * matrix[0, 1])),
(int)(((pPoint.X - yOffset) * matrix[1, 0]) + ((pPoint.Y - yOffset) * matrix[1, 1]))
);
newPoint.X += (int)xOffset;
newPoint.Y += (int)yOffset;
return new Point(newPoint.X,newPoint.Y);
}
注意:我已将一些变量的名称更改为更易于理解的名称,因此名称可能存在不一致。
编辑:我发现了视图和投影矩阵。我也许可以使用它们将 3D 位置转换为屏幕。我不确定是否可以用我所拥有的有限信息制作这个矩阵。