我正在尝试将我的OpenGL渲染管道从定点迁移到现代OpenGL。我的定点3D管道多年来运作良好。现在,当我切换到GLSL时,最终投影和对象方向看起来像“完全镜像或交换”。我已经排除了所有其他原因(例如未能设置矩阵制服等),因为我可以通过随机拖动鼠标来平移相机来不时渲染3D场景。所以问题缩小到以下几点:
由于这两个函数在定点流水线之前生成正确的视图/投影矩阵,现在我想知道是否/如何修改它们以使生成的矩阵适用于着色器管道?
很少stack overflow threads表明对于着色器管道,我们需要手动翻转投影矩阵的Z值,但视图矩阵怎么样?非常感谢任何建议。
更新 Soure代码
/*
Matrix4f has class members "float m00, m01, m02, m03, m10, m11, ..., m33" representing
a row-dominant 4x4 matrix, when passed to GLSL, I have remembered to transpose them
*/
void Matrix4f::_getPerspectiveByFov(float fov, float aspectRatio, float nearZ, float farZ, int matrixType)
{
float halfFov = MathUtil::degToRad(fov) * 0.5f;
float width, height;
//We use the small side out of width and height as the base size, then calculate the other side by aspect ratio.
float _tanFOV = (float)tan(halfFov);
if(aspectRatio < 1.f)//width is smaller
{
width = 2.f * nearZ * _tanFOV;
height = width / aspectRatio;
}
else //height is smaller
{
height = 2.f * nearZ * _tanFOV;
width = height * aspectRatio;
}
/*
Formula from OpenGL reference, see function "glFrustum".
|w 0 0 0|
|0 h 0 0|
|0 0 -C D|
|0 0 1 0|
w = 2.f * nearZ / width
h = 2.f * nearZ / height
C = -(farZ + nearZ) / (farZ - nearZ)
D = -2.f * farZ * nearZ / (farZ - nearZ);
*/
float w = 2.f * nearZ / width; // Is equal to: [ 1.f / tan(fov*0.5f) ]
float h = 2.f * nearZ / height; // Is equal to: [ 1.f / tan(fov*0.5f) / aspectRatio ]
float C = -(farZ + nearZ) / (farZ - nearZ);
float D = -2.f * farZ * nearZ / (farZ - nearZ);
//-----------------------
m00 = w;
m01 = 0.f;
m02 = 0.f;
m03 = 0.f;
m10 = 0.f;
m11 = h;
m12 = 0.f;
m13 = 0.f;
m20 = 0.f;
m21 = 0.f;
m22 = -C;
m23 = D;
m30 = 0.f;
m31 = 0.f;
m32 = 1.f;
m33 = 0.f;
}
void Matrix4f::_getLookAt(Vector3f& pos, Vector3f& lookat, Vector3f& upAxis)
{
//Note _forward, _right, _up are working vector of type Vector3f
_up.set(upAxis);
_forward.sub(lookat, pos);
_forward.normalize();
_right.cross(_up, _forward);
_right.normalize();
_up.cross(_forward, _right);
_up.normalize();
m00 = _right.x;
m10 = _right.y;
m20 = _right.z;
m01 = _up.x;
m11 = _up.y;
m21 = _up.z;
m02 = _forward.x;
m12 = _forward.y;
m22 = _forward.z;
// Locate the camera
m03 = pos.x;
m13 = pos.y;
m23 = pos.z;
m30 = 0.f;
m31 = 0.f;
m32 = 0.f;
m33 = 1.f;
}
答案 0 :(得分:1)
没有看到你在顶点着色器中做了什么,我们只能猜测。但是,您可以在新OpenGL中使用与旧OpenGL中相同的矩阵。你可能没有的唯一矩阵是gluPerspective
所以你可以自己实现它(如果你不再使用glu.h)。我是这样做的:
void glPerspective(double fovy,double aspect,double zNear,double zFar)
{
double per[16],f;
for (int i=0;i<16;i++) per[i]=0.0;
// original gluProjection
// f=divide(1.0,tan(0.5*fovy*deg))
// per[ 0]=f/aspect;
// per[ 5]=f;
// corrected gluProjection
f=divide(1.0,tan(0.5*fovy*deg*aspect));
per[ 0]=f;
per[ 5]=f*aspect;
// z range
per[10]=divide(zFar+zNear,zNear-zFar);
per[11]=-1.0;
per[14]=divide(2.0*zFar*zNear,zNear-zFar);
glLoadMatrixd(per);
// zNear=divide(-per[11],per[10]); // get znear from perspective projection matrix
}
它或多或少地模仿了gluPerspective
,但它修复了不准确的tan
,这会在将更多的frustrums堆叠在一起时造成问题。注释行显示如何计算原始gluPerspective
(同时修复tan
),最后一条注释显示如何从矩阵中获取znear
(对于光线跟踪器)
粗略而非glLoadMatrixd(per);
您可以根据需要使用per
...(例如发送为uniform
)
现在要实现lookat,你只需构建自己的矩阵。参见:
因此,您只需计算X,Y,Z
向量和O
原点位置
Z = -forward
X = +right
Y = +up
O = +camera_position - znear
并将它们送到您所需位置的矩阵中......
现在,如果您的lookat
是目标对象的位置而不是
Z = normalize(camera_position-lookat)
Y = up
X = cross(Y,Z)
不确定X
是否应该+或 - 只是尝试并且如果场景被镜像,则否定它。