最近我实现了一个简单的Opengl程序,它由一个物体场景组成,我已经应用了大部分的转换&投影矩阵,在这样的地方,我能够rotate transform & scale objects, move my camera through z & x coordinates and applied perspective projection
但是当涉及到相机旋转时,事情变得奇怪,我的相机旋转矩阵只是一个旋转矩阵,可以均匀地旋转世界,但是当我旋转世界时所以我向上看; +y
;当我向前移动时,相机似乎没有朝着它正在看的方向前进; as it is the case in FPS games
我的相机相对于世界空间移动,我知道我错过了指定方向的向量{ {1}}坐标,但我无法将这些矢量与我的相机(视图转换)矩阵合并,互联网上的大多数教程要么在框图中描述它,要么使用传统的gluLookAt()函数,我真的需要一个简短的关于视图转换的说明,特别是相机旋转以及我应该如何在我的矩阵中实现它,我的最终矩阵如下:
resultTransform = perspectiveTrans * cameraTrans * modelTrans;
其中:
perspectiveTrans =仅应用透视投影转换
cameraTrans =是影响场景中所有obj.s的旋转,平移矩阵的组合
modelTrans =是应用于模型的转换
Matrix4X4.cpp文件:
x,y,z
我在主块中使用的转换代码:
#include "Matrix4X4.h"
using namespace std;
////////////////////////////////// Constructor Declerations ////////////////////////////////
Matrix4X4::Matrix4X4()
{
setIdentity();
}
Matrix4X4::Matrix4X4(float value)
{
for(int i = 0 ; i < 4; i++)
for ( int j = 0; j < 4; j++)
Matrix[i][j] = value;
}
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////// Destructor Decleration //////////////////////////////
Matrix4X4::~Matrix4X4()
{
}
///////////////////////////////////////////////////////////////////////////////////
/////////////////////// Set Identity Matrix /////////////////////////////////////////
void Matrix4X4::setIdentity()
{
Matrix[0][0] =1; Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = 0;
Matrix[1][0] =0; Matrix[1][1] = 1; Matrix[1][2] = 0; Matrix[1][3] = 0;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = 1; Matrix[2][3] = 0;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0; Matrix[3][3] = 1;
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////// Set Translation Matrix //////////////////////////////////
Matrix4X4 Matrix4X4::setTranslation(float x,float y,float z)
{
Matrix[0][0] =1; Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = x;
Matrix[1][0] =0; Matrix[1][1] = 1; Matrix[1][2] = 0; Matrix[1][3] = y;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = 1; Matrix[2][3] = z;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0; Matrix[3][3] = 1;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Set Rotation Matrix ///////////////////////////////////////////
Matrix4X4 Matrix4X4::setRotation(float x,float y,float z)
{
Matrix4X4 xRot;
Matrix4X4 yRot;
Matrix4X4 zRot;
x = (float)x * 3.14/ 180.0;
y = (float)y * 3.14/ 180.0;
z = (float)z * 3.14/ 180.0;
xRot.Matrix[0][0] =1; xRot.Matrix[0][1] = 0; xRot.Matrix[0][2] = 0; xRot.Matrix[0][3] = 0;
xRot.Matrix[1][0] =0; xRot.Matrix[1][1] = cosf(x); xRot.Matrix[1][2] = -sinf(x); xRot.Matrix[1][3] = 0;
xRot.Matrix[2][0] =0; xRot.Matrix[2][1] = sinf(x); xRot.Matrix[2][2] = cosf(x); xRot.Matrix[2][3] = 0;
xRot.Matrix[3][0] =0; xRot.Matrix[3][1] = 0; xRot.Matrix[3][2] = 0; xRot.Matrix[3][3] = 1;
yRot.Matrix[0][0] = cosf(y); yRot.Matrix[0][1] = 0; yRot.Matrix[0][2] = -sinf(y); yRot.Matrix[0][3] = 0;
yRot.Matrix[1][0] =0; yRot.Matrix[1][1] = 1; yRot.Matrix[1][2] = 0; yRot.Matrix[1][3] = 0;
yRot.Matrix[2][0] = sinf(y); yRot.Matrix[2][1] = 0; yRot.Matrix[2][2] = cosf(y); yRot.Matrix[2][3] = 0;
yRot.Matrix[3][0] =0; yRot.Matrix[3][1] = 0; yRot.Matrix[3][2] = 0; yRot.Matrix[3][3] = 1;
zRot.Matrix[0][0] = cosf(z); zRot.Matrix[0][1] = -sinf(z); zRot.Matrix[0][2] = 0; zRot.Matrix[0][3] = 0;
zRot.Matrix[1][0] = sinf(z); zRot.Matrix[1][1] = cosf(z); zRot.Matrix[1][2] = 0; zRot.Matrix[1][3] = 0;
zRot.Matrix[2][0] =0; zRot.Matrix[2][1] = 0; zRot.Matrix[2][2] = 1; zRot.Matrix[2][3] = 0;
zRot.Matrix[3][0] =0; zRot.Matrix[3][1] = 0; zRot.Matrix[3][2] = 0; zRot.Matrix[3][3] = 1;
return (zRot * yRot * xRot) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////// Set Scale Matrix //////////////////////////////////////////
Matrix4X4 Matrix4X4::setScale(float x,float y,float z)
{
Matrix[0][0] =x; Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = 0;
Matrix[1][0] =0; Matrix[1][1] = y; Matrix[1][2] = 0; Matrix[1][3] = 0;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = z; Matrix[2][3] = 0;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0; Matrix[3][3] = 1;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Set Perspective Projection ///////////////////////////////////////
void Matrix4X4::setPerspective(float fov,float aRatio,float zNear,float zFar)
{
fov = (fov/2) * 3.14 / 180.0;
float tanHalfFOV = tanf(fov);
float zRange = zNear - zFar;
Matrix[0][0] =1.0f / (tanHalfFOV * aRatio); Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = 0;
Matrix[1][0] =0; Matrix[1][1] = 1.0f / tanHalfFOV; Matrix[1][2] = 0; Matrix[1][3] = 0;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = (-zNear - zFar)/ zRange; Matrix[2][3] = 2* zFar * zNear / zRange;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 1; Matrix[3][3] = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Getters & Setters ////////////////////////////////////////////
float * Matrix4X4::getMat()
{
return (float *) Matrix;
}
float Matrix4X4::getMember(int x, int y) const
{
return Matrix[x][y];
}
void Matrix4X4::setMat(int row,int col,float value)
{
Matrix[row][col] = value;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// (*) Operator Overload //////////////////////////////////////
Matrix4X4 operator * (const Matrix4X4 & lhs,const Matrix4X4 & rhs)
{
Matrix4X4 result;
for(int i = 0 ; i < 4; i++)
for ( int j = 0; j < 4; j++)
result.setMat(i, j, lhs.getMember(i,0) * rhs.getMember(0, j) +
lhs.getMember(i,1) * rhs.getMember(1, j) +
lhs.getMember(i,2) * rhs.getMember(2, j) +
lhs.getMember(i,3) * rhs.getMember(3, j));
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
答案 0 :(得分:2)
矩阵乘法与标量乘法的规则不同,在你的情况下,A * B在乘以矩阵时不等于B * A.如果其余的代码都很好,那么您的解决方案可能只是转向
result = Projection * camTrans * modelTrans;
进入
result = Projection * (modelTrans * camTrans);
在处理除标量值之外的任何事情时,请务必注意乘法顺序和括号。
通常,在组合平移和旋转矩阵时,您需要在矩阵自己的空间坐标系中进行思考,这就像播放FPS一样:
乘以rotation*translation
表示对象将首先旋转,然后翻译意味着对象位置将取决于已经应用的旋转,180度旋转将从第3视图角度向后平移对象。
倍增translation*rotation
表示对象将首先平移然后旋转,这意味着无论旋转如何,它实际上都会移动到相同的方向,只有对象面向的方向才会被旋转矩阵改变。
这是一个很好的例子,如果你想在太阳周围呈现地球运动(地球围绕太阳旋转,同时围绕自己的轴旋转在某个半径上):
Matrix4X4 orbitRotation; //rotation matrix for where in orbit the object is
Matrix4X4 objectRotation; //object rotation around its own axis
Matrix4X4 orbitRadius; //object orbit radius
Matrix4X4 result = (orbitRotation*orbitRadius)*objectRotation;
答案 1 :(得分:0)
我的代码似乎忽略了之前的矩阵计算,并重新计算了关于我的场景的初始状态,所需的世界旋转和转换的变换。通过使用固定的旋转值来实现平移。翻译,修改后的代码块如下:
for (int x = 0; x< 256; x++)
{
if (state[x] == 1 )
{
if(x == 26)
tranForward = -0.001;
if (x == 22)
tranForward = 0.001;
if (x == 4)
tranRight = 0.0009;
if (x == 7)
tranRight = -0.0009;
if (x == 82)
lookUp = 0.02;
if (x == 81)
lookUp = -0.02;
if (x == 80)
lookRight = -0.02;
if (x == 79)
lookRight = 0.02;
}
}
camTrans = Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward);
result = camTrans * result;
modelTrans = Projection * result;
tranForward = 0.0;
tranRight = 0.0;
lookUp = 0.0;
lookRight = 0.0;
glUniformMatrix4fv(uniformloc, 1, GL_TRUE, modelTrans.getMat());
请注意,结果矩阵会跟踪先前的状态,并对其应用当前的状态转换。