c# – 使用偏航和俯仰创建旋转矩阵并模拟FPS摄像机
首先,我必须说我想在这里做的只是关于点,而不是对象或其他任何东西.我在这里使用OpenGL更多的是用于计算.
所以这是我的问题.我想在我的2D环境中显示一些3d点(例如winform或图像); 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,-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)); } 我还写了另一个名为Project cuz的函数我没有在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) }; } 当所有三个值(偏航,俯仰和滚动)都为零时,它似乎按预期工作.我可以通过改变偏航和使用音高值垂直移动水平点.滚动也按照它应该的方式移动它. 当我将音高设置为90度时,问题就出现了.在这种情况下,偏航而不是水平移动,垂直移动,更糟糕的是,仅将其向下移动.无论我走向正面还是负面(-20度或20度)它总是会下降.有趣的是,当音高为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,c,-s,s,1.0f); } if (axis == 'Y') { return new Matrix4(c,1.0f,1.0f); } return new Matrix4(c,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; } 你有什么主意吗? 以下是我知道的订单: 我可以提供一个示例程序来自己查看问题. 解决方法
我认为问题的一部分来自你在第一个代码块中使用LookAt函数.这些函数的工作方式是通过查看与您正在查找的方向垂直的全局“向上”向量的部分来计算局部“向上”向量.在您查找的情况下,全局“向上”向量(上述代码中的(0,0))没有与查看方向垂直的分量,结果可能是未定义的或不稳定的.当你向下看时也是如此.
相反,尝试将LookAt函数的“向上”向量计算为: Vector3 localUpVec = Vector3.Transform(new Vector3(0,0),Matrix4.Invert(cameraRotationMatrix)); Matrix4 viewMatrix = Matrix4.LookAt(cameraPosition,localUpVec); 或者甚至更好,您可以完全绕过LookAt功能并自行计算: Matrix4 viewMatrix = Matrix4.Subtract( Matrix4.Transpose(cameraRotationMatrix),Matrix4.Translation(cameraPosition) ); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |