首先,我必须说,我在这里要做的都是关于点,而不是对象或其他任何东西。而我这里使用的OpenGL更多是为了计算。
所以这是我的问题。我想在我的 2d 上下文中显示一些 3d 点(例如 winform 或图像);为此,我编写了这个函数:(它使用 C# 并使用 OpenTK(OpenGL 包装器),但我确信如果您了解 OpenGL,无论您是否了解 C#,都可以理解它)
private Vector3 GetProjectedLocation(
Vector3 pointPosition,
Vector3 cameraPosition,
Matrix4 cameraRotationMatrix)
{
float horizentalFov = MathHelper.DegreesToRadians(60.0f);
float viewRatio = (float)this.RenderSize.Width / this.RenderSize.Height;
Vector3 cameraReference = new Vector3(0, 0, -1);
Vector3 transformedReference = Vector3.Transform(cameraReference, Matrix4.Invert(cameraRotationMatrix));
Vector3 cameraLookatTarget = cameraPosition + transformedReference;
Matrix4 modelMatrix = Matrix4.Identity;
Matrix4 viewMatrix = Matrix4.LookAt(cameraPosition, cameraLookatTarget, new Vector3(0, 1, 0));
Matrix4 projectionMatrix = Matrix4.CreatePerspectiveFieldOfView(horizentalFov, viewRatio, 0.1f, 100.0f);
Matrix4 viewModelMatrix = viewMatrix * modelMatrix;
return Helper.Project(
pointPosition,
viewModelMatrix,
projectionMatrix,
new Rectangle(new Point(), this.RenderSize));
}
Run Code Online (Sandbox Code Playgroud)
我还写了另一个名为 Project 的函数,因为我在 OpenTK 中没有找到它:
public static Vector3 Project(Vector3 point, Matrix4 viewmodel, Matrix4 projection, Rectangle viewport)
{
Vector4 point4 = new Vector4(point, 1.0f);
Vector4 pointModel = Vector4.Transform(point4, viewmodel);
Vector4 pointProjection = Vector4.Transform(pointModel, projection);
pointProjection.W = (float)(1.0 / pointProjection.W);
pointProjection.X *= pointProjection.W;
pointProjection.Y *= pointProjection.W;
pointProjection.Z *= pointProjection.W;
return new Vector3
{
X = (float)((pointProjection.X * 0.5 + 0.5) * viewport.Width + viewport.X),
Y = (float)((pointProjection.Y * 0.5 + 0.5) * viewport.Height + viewport.Y),
Z = (float)((1.0 + pointProjection.Z) * 0.5)
};
}
Run Code Online (Sandbox Code Playgroud)
当所有三个值(偏航、俯仰和滚转)都为零时,它似乎按预期工作。我可以通过使用俯仰值更改偏航和垂直来水平移动点。滚动也会按照它应该的方式移动它。
当我将音高设置为 90 度时,问题就出现了。在这种情况下,偏航而不是水平移动,而是垂直移动,更糟糕的是,只会将其向下移动。无论我去正面还是负面(-20deg 或 +20deg),它总是下降。有趣的是,当俯仰角为 90 度时,Roll 具有相同的效果,并且它只会像偏航一样垂直向下移动它。将俯仰设置为 -90deg 具有相同的效果,但这次偏航和滚动只会将其向上移动。
当我的两个轴平行并且我失去了一个方向时,这似乎是万向节锁定问题,在这种情况下是滚动。我仍然不明白为什么偏航只在一个方向上起作用。
无论如何,问题在于这种锁定发生在垂直观察时,这是我的程序大部分时间看起来的地方。我已经读到,如果我改变旋转顺序,我可以将万向节锁移到顶部(不太频繁查看的地方)。我尝试了许多订单,但找不到好的订单。所以这是我的代码,也许我做错了:
private Matrix4 CreateRotationMatrix(char axis, float radians)
{
float c = (float)Math.Cos(radians);
float s = (float)Math.Sin(radians);
if (axis == 'X')
{
return new Matrix4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, c, -s, 0.0f, 0.0f, s, c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
}
if (axis == 'Y')
{
return new Matrix4(c, 0.0f, s, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -s, 0.0f, c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
}
return new Matrix4(c, -s, 0.0f, 0.0f, s, c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
}
private Matrix4 MatrixFromEulerAngles(Vector3 euler, string order)
{
return CreateRotationMatrix(order[2], GetEulerAngle(order[2], euler))
* CreateRotationMatrix(order[1], GetEulerAngle(order[1], euler))
* CreateRotationMatrix(order[0], GetEulerAngle(order[0], euler));
}
private float GetEulerAngle(char angle, Vector3 euler)
{
if (angle == 'X') return euler.X;
if (angle == 'Y') return euler.Y;
return angle == 'Z' ? euler.Z : 0f;
}
Run Code Online (Sandbox Code Playgroud)
你有什么主意吗?
这是我知道的命令:“XYZ”、“XZY”、“YXZ”、“YZX”、“ZXY”、“ZYX”
我可以提供一个示例程序,自己看问题。
小智 1
我认为部分问题来自于您LookAt在第一个代码块中使用该函数。这些函数的工作方式是通过查看与您正在查看的方向垂直的全局“向上”向量的部分来计算局部“向上”向量。在向上查找的情况下,全局“向上”向量(上面代码中的 (0,1,0) )没有垂直于查找方向的分量,结果可能是未定义或不稳定的。当你向下看时,这同样适用。
相反,尝试计算LookAt函数的“向上”向量:
Vector3 localUpVec = Vector3.Transform(new Vector3(0, 1, 0), Matrix4.Invert(cameraRotationMatrix));
Matrix4 viewMatrix = Matrix4.LookAt(cameraPosition, cameraLookatTarget, localUpVec);
Run Code Online (Sandbox Code Playgroud)
或者更好的是,您可以LookAt完全绕过该函数并自己计算:
Matrix4 viewMatrix = Matrix4.Subtract( Matrix4.Transpose(cameraRotationMatrix), Matrix4.Translation(cameraPosition) );
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2035 次 |
| 最近记录: |