我有以下代码用于我自己的查看矩阵(矩阵的乘法和向量的交叉产品完美地工作,我检查了它):
模板< typename类型>void setLookAt(Matrix4x4< …
"projectionMatrix" 和 "viewMatrix" 是统一变量。统一的位置可以得到 glGetUniformLocation 而不是 glGetAttribLocation ,它将返回活动属性的属性索引:
"projectionMatrix"
"viewMatrix"
glGetUniformLocation
glGetAttribLocation
GLint projLoc = glGetUniformLocation( mProgramID, "projectionMatrix" ); GLint viewLoc = glGetUniformLocation( mProgramID, "viewMatrix" );
在透视投影中,投影矩阵描述了从针孔相机到视口的2D点看世界中3D点的映射。 相机平截头体(截头金字塔)中的眼睛空间坐标被映射到立方体(标准化设备坐标)。 在透视投影中,视图空间(体积)由平截头体(截头金字塔)定义,其中金字塔的顶部是观察者的位置。 视线方向(视线)以及近距离和远距离定义了将金字塔截断为平截头体的平面(视线方向是该平面的法向矢量)。 这意味着两个值,到近平面的距离和到远平面的距离必须是正值:
Matrix4x4f lookAt; setLookAt(lookAt, { 0.0f, 0.0f, 3.0f }, { 0.0f, 0.0f, -1.0f }, { 0.0f, 1.0f, 0.0f }); glUniformMatrix4fv(viewLoc, 1, GL_TRUE, lookAt); Matrix4x4f projection; setPerspectiveMatrix(projection, 45.0f, width / height, 0.1f, 100.0f); // 0.1f instead of -0.1f glUniformMatrix4fv(projLoc, 1, GL_TRUE, projection);
视图空间是本地系统,它由场景的视点定义。 视图的位置,视线和视图的向上方向定义了相对于世界坐标系的坐标系。 视图矩阵必须从世界空间变换到视图空间,因此视图矩阵是视图坐标系的逆矩阵。 如果视图空间的坐标系是a 右手持拍 系统,其中X轴指向左侧,Y轴指向上方,然后Z轴指向视图外(注意在右侧系统中,Z轴是X轴和X轴的叉积和Y轴)。
从视点看,z轴视线是矢量 eye 到了traget center :
eye
center
template<typename Type> void setLookAt(Matrix4x4<Type>& matrix, const Vector3<Type> eye, const Vector3<Type> center, const Vector3<Type> up) noexcept { Vector3f mz( { eye.getX()-center.getX(), eye.getY()-center.getY(), eye.getZ()-center.getZ() } ); mz = mz.normalize(); Vector3f my = up.normalize(); Vector3f mx = cross(my, mz).normalize(); Type tx = dot( mx, eye ); Type ty = dot( my, eye ); Type tz = -dot( mz, eye ); matrix = { mx.getX(), mx.getY(), mx.getZ(), tx, my.getX(), my.getY(), my.getZ(), ty, mz.getX(), mz.getY(), mz.getZ(), tz, 0.0, 0.0, 0.0, 1.0 }; } template<typename Type> Vector3<Type> cross(Vector3<Type> vector, Vector3<Type> anotherVector) noexcept { const Type x = vector.getY()*anotherVector.getZ() - vector.getZ()*anotherVector.getY(); const Type y = -(vector.getX()*anotherVector.getZ() - vector.getZ()*anotherVector.getX()); const Type z = vector.getX()*anotherVector.getY() - vector.getY()*anotherVector.getX(); return { x, y, z }; } template<typename Type> Vector3<Type> Vector3<Type>::normalize(void) const { Type len = std::sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); return { mV[0] / len, mV[1] / len, mV[2] / len }; } template<typename Type> Type dot(Vector3<Type> vector, Vector3<Type> anotherVector) noexcept { Type ax = vector.getX(), ay = vector.getY(), az = vector.getZ(); Type bx = anotherVector.getX(), by = anotherVector.getY(), bz = anotherVector.getZ(); return ax*bx + ay*by + az*bz; }
透视投影矩阵可以由a定义 的 视锥 强> 。 距离 left , right , bottom 和 top ,是近视平面上从视图中心到平截头体侧面的距离。 near 和 far 指定平截头体上距近平面和远平面的距离。
left
right
bottom
top
near
far
r = right, l = left, b = bottom, t = top, n = near, f = far x y z t 2*n/(r-l) 0 (r+l)/(r-l) 0 0 2*n/(t-b) (t+b)/(t-b) 0 0 0 -(f+n)/(f-n) -2*f*n/(f-n) 0 0 -1 0
如果投影是对称的,其中视线是视锥体的对称轴,那么矩阵可以简化:
x y z t 1/(ta*a) 0 0 0 0 1/ta 0 0 0 0 -(f+n)/(f-n) -2*f*n/(f-n) 0 0 -1 0
哪里:
a = w / h ta = tan( fov_y / 2 ); 2 * n / (r-l) = 1 / (ta * a) 2 * n / (t-b) = 1 / ta
此外,投影矩阵从右手系统切换到左手系统,因为z轴被转动。
template<typename Type> void setPerspectiveMatrix(Matrix4x4<Type>& matrix, Type fov, Type aspect, Type znear, Type zfar) noexcept { const Type yScale = static_cast<Type>(1.0 / tan(RADIANS_PER_DEGREE * fov / 2)); const Type xScale = yScale / aspect; const Type difference = zfar - znear; matrix = { xScale, 0, 0, 0, 0, yScale, 0, 0, 0, 0, -(zfar + znear) / difference, -2 * zfar * znear / difference, 0, 0, -1, 0 }; }