我的Go矩阵函数(透视/截锥和Lookat矩阵)在OpenGL中有什么问题?

3

首先,这是非常简单的“新手标准”顶点着色器:

in vec3 aPos;
uniform mat4 uMatModel; uniform mat4 uMatView; uniform mat4 uMatProj;

void main () {
    gl_Position = uMatProj * uMatView * uMatModel * vec4(aPos, 1.0);
}

现在我正在渲染一个简单的六面立方体。36个顶点坐标中没有应用旋转或固有旋转。标准的教程风格,-0.5..+0.5的东西。我会在这里省略顶点数组,但请放心,它就是那么简单。 uMatModel现在只是一个身份矩阵,还没有缩放/平移/旋转。 uMatView是一个LookAt矩阵(以下是Go代码),使用pos={ 0.1, 0.1, -3.0 }, target={ 0.1, 0.1, 0.1 }, up={ 0, 1, 0 }调用(请记住,立方体顶点坐标在所有维度上都在-0.5和0.5之间,因此0.1应该是“几乎中心”)。 uMatProj是一个透视矩阵(以下是Go代码),使用fov=45 aspect=winwidth/winheight near=0.1 far=100调用。
理论上,“相机”应该在立方体后面约2-3个单位并直接面对它。但实际上,我得到了……
我想知道旋转来自哪里……我甚至还没有实现旋转。
因此,总结一下,我尝试根据数学原理自己在Go中实现所需的矩阵函数。但是在某个地方,我一定出错了。有人能发现我的下面的代码中是否存在任何矩阵理论问题吗?
type Mat4x4 [4][4]float64

func (me *Mat4x4) Identity () {
    me[0][0], me[0][1], me[0][2], me[0][3] = 1, 0, 0, 0
    me[1][0], me[1][1], me[1][2], me[1][3] = 0, 1, 0, 0
    me[2][0], me[2][1], me[2][2], me[2][3] = 0, 0, 1, 0
    me[3][0], me[3][1], me[3][2], me[3][3] = 0, 0, 0, 1
}

func (me *Mat4x4) Frustum (left, right, bottom, top, near, far float64) {
    me[0][0], me[0][1], me[0][2], me[0][3] = (near * 2) / (right - left), 0, 0, 0
    me[1][0], me[1][1], me[1][2], me[1][3] = 0, (near * 2) / (top - bottom), 0, 0
    me[2][0], me[2][1], me[2][2], me[2][3] = (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1
    me[3][0], me[3][1], me[3][2], me[3][3] = 0, 0, -(far * near * 2) / (far - near), 0
}

func (me *Mat4x4) Perspective (fovY, aspect, near, far float64) {
    var top = near * math.Tan(fovY * math.Pi / 360)
    var right = top * aspect
    me.Frustum(aspect * -top, right, -top, top, near, far)
}

func (me *Mat4x4) LookAt (eyePos, lookTarget, worldUp *Vec3) {
    var vz = eyePos.Sub(lookTarget)
    vz.Normalize()
    var vx = worldUp.Cross(&vz)
    vx.Normalize()
    var vy = vz.Cross(&vx)
    vy.Normalize()
    me[0][0], me[0][1], me[0][2], me[0][3] = vx.X, vy.X, vz.X, 0
    me[1][0], me[1][1], me[1][2], me[1][3] = vx.Y, vy.Y, vz.Y, 0
    me[2][0], me[2][1], me[2][2], me[2][3] = vx.Z, vy.Z, vz.Z, 0
    me[3][0], me[3][1], me[3][2], me[3][3] = -((vx.X * eyePos.X) + (vx.Y * eyePos.Y) + (vx.Z * eyePos.Z)), -((vy.X * eyePos.X) + (vy.Y * eyePos.Y) + (vy.Z * eyePos.Z)), -((vz.X * eyePos.X) + (vz.Y * eyePos.Y) + (vz.Z * eyePos.Z)), 1
}

注意,这里的Vec3是同一软件包中的自定义类型,我没有包含它。目前我假设Vec3函数是正确的(而且更容易验证),并怀疑我在矩阵结构中某些地方弄错了LookAt和/或Perspective算法。


似乎它们可能被错误地转置,但我不太了解Go,无法确定。如果你转置你的LookAt和Perspective矩阵,会有任何改善吗?请注意,您可以通过在glUniformMatrix中快速进行布尔翻转来转置它们,因此您不必编辑实际的矩阵函数。 - Tim
现在我发现GLSL矩阵是列主序的,而我的矩阵是行主序的——你绝对是对的。我会看看这是否解决了问题,但这肯定是问题的一部分... - metaleap
完全将矩阵库更改为列主序,但核心问题没有变化,仍然是45度倾斜的摄像机视图... - metaleap
1个回答

1

这个(大概)是角度转弧度的转换,没问题吗?

func (me *Mat4x4) Perspective (fovY, aspect, near, far float64) {
        var top = near * math.Tan(fovY * math.Pi / 360)
        var right = top * aspect
        me.Frustum(aspect * -top, right, -top, top, near, far)
}

也许应该有:

        top := near * math.Tan(fovY * 2 * math.Pi / 360)

不,那会稍微改变相机视角,但核心问题仍然存在,整个视图仍然像是旋转了45度... - metaleap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接