我正在制作一个小型游戏引擎,我想在其中使用 OpenGL 绘制东西。我将所有 OpenGL 对象抽象为类(缓冲区、顶点数组、着色器、程序...)。一切正常,直到我进行 3D 渲染。我实现了自己的矩阵和 vector (我没有像 glm 那样使用),当我将着色器中的顶点位置与任何矩阵相乘时,z 坐标翻转(z = -z)。我什至尝试过使用单位矩阵。这是顶点着色器:
#version 330 core
layout(location = 0) in vec4 i_pos;
layout(location = 1) in vec4 i_color;
out vec4 p_color;
uniform mat4 u_MVP;
uniform vec4 u_pos;
void main()
{
gl_Position = u_MVP * (i_pos + u_pos);
p_color = i_color;
}
我用了
u_Pos
统一只是出于调试原因。在这里我设置了制服:void Frame() override
{
deltaTime = timer.Reset();
if (Input::GetKey(Key::W).value == KeyDown) pos.z += deltaTime;
if (Input::GetKey(Key::S).value == KeyDown) pos.z -= deltaTime;
//mat4f(1.0f) creates a identity matrix
shaderSelection.SetUniform("u_MVP", mat4f(1.0f));
shaderSelection.SetUniform("u_pos", vec4f(pos));
ren.DrawTriangles(vertexArray, indexBuffer, shaderSelection);
}
虽然我确定矩阵结构没有任何内容,但它是:
template<typename T = float, int sizeX = 4, int sizeY = 4>
struct BLAZE_API mat
{
private:
T v[sizeY][sizeX];
public:
mat()
{
for (unsigned i = 0; i < sizeX * sizeY; i++)
((T*)v)[i] = 0;
}
mat(T* ptr, bool transpose = false)
{
if (transpose)
for (unsigned i = 0; i < sizeX * sizeY; i++)
((T*)v)[i] = ptr[i];
else
for (unsigned i = 0; i < sizeX * sizeY; i++)
((T*)v)[i] = ptr[i % sizeY * sizeX + i / sizeY];
}
mat(T n)
{
for (int x = 0; x < sizeX; x++)
for (int y = 0; y < sizeY; y++)
if (x == y)
operator[](x)[y] = n;
else
operator[](x)[y] = 0;
}
mat(const mat<T, sizeX, sizeY>& mat)
{
for (int x = 0; x < sizeX; x++)
for (int y = 0; y < sizeY; y++)
v[x][y] = mat[x][y];
}
inline T* operator[] (unsigned i) const { return (T*)(v[i]); }
inline void operator= (const mat<T, sizeX, sizeY>& mat)
{
for (int x = 0; x < sizeX; x++)
for (int y = 0; y < sizeY; y++)
v[x][y] = mat[x][y];
}
};
和
SetUniform
做这个:glUniformMatrix4fv( ... , 1, GL_FALSE, m[0]);
我制作了矩阵结构,这样我就不必使用
GL_TRUE
对于 transpose
glUniformMatrix4fv
中的参数.我很确定这不是我的矩阵实现反转 z 坐标。就像相机在 -Z 方向上看一样,但是当我在 +X 方向上移动对象时,它也会在屏幕上移动 +X(也适用于 Y 方向),如果相机面对,它不应该-Z。
这是应该发生的,如果是这样我可以改变它吗?
最佳答案
如果不变换顶点坐标(或通过 Identity matrix 变换),则直接在标准化设备空间中设置坐标。 NDC 是一个独特的立方体,左、下、近为 (-1, -1, -1),右、上、远为 (1, 1, 1)。这意味着 X 轴向右,Y 轴向上,Z 轴指向 View 。
通常,OpenGL 坐标系是 Right-handed系统。在 View 空间中,X 轴指向右侧,Y 轴指向上方。
由于 Z 轴是 Cross product在 X 轴和 Y 轴的位置,它指向视口(viewport)之外并且看起来是倒置的。
为了补偿 View 空间中 Z 轴方向与标准化设备空间相比的差异,必须反转 Z 轴。
典型的 OpenGL 投影矩阵(例如 glm::ortho
、 glm::perspective
或 glm::frustum
)将右手系统转换为左手系统并镜像 Z 轴。
这意味着,如果您使用(典型的)投影矩阵(并且没有其他转换),那么顶点坐标等于 View 空间坐标。 X 轴向右,Y 轴向上,Z 轴指向视野外。
简而言之,在标准化设备空间中,相机指向 +Z。在 View 空间中(在通过典型投影矩阵进行转换之前),相机指向 -Z。
请注意,如果您设置了 Viewing frustum ,然后 0 < near
和 near < far
.这两个条件都必须满足。几何图形必须位于近平面和远平面之间,否则会被剪裁。通常, View 矩阵用于从某个角度查看场景。视锥体的近平面和远平面以这种方式选择,几何形状介于两者之间。
由于深度不是线性的(参见 How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?),近平面应尽可能靠近几何体放置。
关于c++ - 为什么在与GLSL中的矩阵相乘后z坐标会翻转 - OpenGL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60195019/