opengl - OpenTK 矩阵变换

标签 opengl matrix opentk

这是顶点着色器:

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

void main(void)
{
    gl_Position = projection * view * model * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
}

我的理解是,使用各种变换,模型空间最终会变成剪辑空间,它是一个由每个轴中的每个单元绑定(bind)的盒子,直接绘制到视口(viewport),即 (-1, 1,0) 处的东西是在视口(viewport)的左上角。当我从着色器中删除所有矩阵变换时,

gl_Position = gl_Vertex;

并传入一个简单的四边形作为模型

public Vector3[] verts = new Vector3[] {
    new Vector3(-1f, -1f, 0),
    new Vector3(1f, -1f, 0),
    new Vector3(1f, 1f, 0),
    new Vector3(-1f, 1f, 0),
};

public Vector2[] coords = new Vector2[] {
    new Vector2(0, 1f),
    new Vector2(1f, 1f),
    new Vector2(1f, 0f),
    new Vector2(0f, 0f),
};

public uint[] indices = new uint[] {
    0,1,2,
    0,2,3,
};

我得到了预期的全屏图像。当我应用转换时,图像显示为 正如您所期望的,屏幕中央的一个小方 block 。当我尝试在 CPU 上的剪辑坐标中计算模型顶点的位置时,出现了问题:

public Vector4 testMult(Vector4 v, Matrix4 m)
{
    return new Vector4(
        m.M11 * v.X + m.M12 * v.Y + m.M13 * v.Z + m.M14 * v.W,
        m.M21 * v.X + m.M22 * v.Y + m.M23 * v.Z + m.M24 * v.W,
        m.M31 * v.X + m.M32 * v.Y + m.M33 * v.Z + m.M34 * v.W,
        m.M41 * v.X + m.M42 * v.Y + m.M43 * v.Z + m.M44 * v.W);
}

Matrix4 test = (GlobalDrawer.projectionMatrix * GlobalDrawer.viewMatrix) * modelMatrix;

Vector4 testv = (new Vector4(1f, 1f, 0, 1));
Console.WriteLine("Test Input: " + testv);
Console.WriteLine("Test Output: " + Vector4.Transform(testv, test));
Vector4 testv2 = testMult(testv, test);
Console.WriteLine("Test Output: " + testv2);
Console.WriteLine("Test Output division: " + testv2 / testv2.W);

(传入的矩阵与传递给着色器的矩阵相同)

程序然后继续在剪辑空间之外给出输出,除以 W 导致除以 0:

Test Input: (1, 1, 0, 1)
Test Output: (0.9053301, 1.207107, -2.031746, 0)
Test Output: (0.9053301, 1.207107, -1, 0)
Test Output division: (Infinity, Infinity, -Infinity, NaN)

矩阵的创建方式如下:

projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, window.Width / (float)window.Height, 1.0f, 64.0f);
projectionMatrix =
(1.81066, 0, 0, 0)
(0, 2.414213, 0, 0)
(0, 0, -1.031746, -1)
(0, 0, -2.031746, 0)

viewMatrix = Matrix4.LookAt(new Vector3(0,0,4), -Vector3.UnitZ, Vector3.UnitY);
viewMatrix = 
(1, 0, 0, 0)
(0, 1, 0, 0)
(0, 0, 1, 0)
(0, 0, -4, 1)

modelMatrix = 
(0.5, 0  , 0  , 0)
(0  , 0.5, 0  , 0)
(0  , 0  , 1  , 0)
(0  , 0  , 0  , 1)

所以,问题是为什么;我做错了什么?

最佳答案

编辑(从评论中添加真实答案)

默认情况下,您的 OpenTK 矩阵会转置。它看起来使用行向量而不是列向量。因此,您需要将乘法计算为 (model * view * proj),而不是 (proj * view * model)。或者在上传之前转置所有矩阵。


实际上剪辑空间不是从-1到1,而是从-W到W,其中W是剪辑空间向量的第四个分量。

您可能想到的是标准化设备坐标,每个轴的范围为 -1 到 1。通过将剪辑空间向量的 X、Y 和 Z 坐标除以剪辑空间 W 分量即可获得该值。这种划分称为透视划分

这是在将剪辑空间坐标传递给 gl_Position 后在幕后完成的。

你的剪辑空间坐标是 0,这对我来说似乎不正确。

这里有更多详细信息:OpenGL FAQ : Transformations

关于opengl - OpenTK 矩阵变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11452241/

相关文章:

java - 使用 OpenGL 和 libgdx 在运行时生成非常大的图像

matrix - 26 模山密码加密

ruby - 使用 Ruby 搜索矩阵

c# - 将建模矩阵应用于 View 矩阵 = 失败

c# - 在 OpenTK 中获取鼠标窗口坐标 (C#~.NET)

c++ - 加载的 OpenGL 函数是上下文特定的还是线程特定的? ( Windows )

opengl - Valgrind:libnvidia-glcore.so.346.47 条件跳转或移动取决于未初始化的值

c++ - GL_R32I TexImage2D 上传不正确

python - 当矩阵中的行多 10 倍时,为什么 np.dot 不会(至少)长 10 倍

xna - 如何在 MonoGame 中获取底层 Window?