在基于着色器的核心配置文件OpenGL中“反转Z轴”的方法?

时间:2013-03-08 07:53:25

标签: opengl matrix projection perspective

在我的业余爱好者基于着色器(非FFP)GL(3.2+核心)“引擎”中,世界空间和模型空间中的所有东西都是设计为“左撇子”(并保持这种状态),所以X轴从-1(“左”)变为1(“右”),Y从-1(“底部”)变为1(“顶部”),Z从-1(“近”)变为1(“远“)。

现在,默认情况下,在OpenGL中,NDC空间的工作方式相同,但剪辑空间没有,从我收集到的,这里z从1(“near”)延伸到-1(“far”)。

与此同时,我希望理想地继续使用“kinda-sorta inofficial quasi-standard”矩阵函数进行外观和透视,目前定义为:

func (me *Mat4) Lookat(eyePos, lookTarget, upVec *Vec3) {
    l := lookTarget.Sub(eyePos)
    l.Normalize()
    s := l.Cross(upVec)
    s.Normalize()
    u := s.Cross(l)
    me[0], me[4], me[8], me[12] = s.X, u.X, -l.X, -eyePos.X
    me[1], me[5], me[9], me[13] = s.Y, u.Y, -l.Y, -eyePos.Y
    me[2], me[6], me[10], me[14] = s.Z, u.Z, -l.Z, -eyePos.Z
    me[3], me[7], me[11], me[15] = 0, 0, 0, 1
}

//  a: aspect ratio. n: near-plane. f: far-plane.
func (me *Mat4) Perspective(fovY, a, n, f float64) {
    s := 1 / math.Tan(DegToRad(fovY)/2) // scaling
    me[0], me[4], me[8], me[12] = s/a, 0, 0, 0
    me[1], me[5], me[9], me[13] = 0, s, 0, 0
    me[2], me[6], me[10], me[14] = 0, 0, (f+n)/(n-f), (2*f*n)/(n-f)
    me[3], me[7], me[11], me[15] = 0, 0, -1, 0
}

所以,对于lookat-part来说,让我的世界空间相机(正-Z)按照这个伪代码使用lookat(负-Z):

// world-space position:
camPos := cam.Pos 
// normalized direction-vector, up/right/forward are 1 not -1:
camTarget := cam.Dir
// lookat-target:
camTarget.Add(&camPos)
// invert both Z:
camPos.Z, camTarget.Z = -camPos.Z, -camTarget.Z
// compute lookat-matrix:
cam.mat.Lookat(&camPos, &camTarget, &Vec3{0, 1, 0})

效果很好。在所有6个自由度中移动相机可以产生正确的屏幕移动并校正新的相机世界空间坐标。

但几何图形仍在Z轴上反转。当我放置两个方框时,A在(-2,1,-2),左边出现,B(2,1,2)出现在最右边,然后A出现在极左边,B出现在右边。 Z仍然倒在这里。

现在,这些节点有自己的世界空间坐标,并从他们自己的模型到世界矩阵更新。我不应该在那里反转posZ,因为它们形成了一个子节点的层次结构,乘以它们的父变换以及所有这些。他们仍然处于模范或世界空间,根据我的法令,他们仍然是左撇子。

他们的世界到相机计算发生在我的终端CPU上,而不是顶点着色器,它只获得一个单一的最终(mvp / clip-space)矩阵。

当发生这种情况时 - 世界空间 - 物体 - 矩阵与剪辑空间的外观和投影矩阵相乘 - 此时我需要以某种方式反转Z.

最好的方法是什么?或者,更一般地说,什么是常用的方式?我是否必须修改投影以接受左手但是右手输出到GL?如果是这样,怎么样?然后我不也要修改lookat?是否有一种聪明的方法可以做到这一切,而无需修改有些标准的外观/投影矩阵,同时还将模型变换矩阵保留在左手坐标中?

1 个答案:

答案 0 :(得分:1)

在透视图中,将我[11]从-1更改为1应该按照您描述的方式反转z轴。如果这不正确,请尝试否定我[10]。当然,因为z轴被反转,所以你的旋转方向也会受到影响。如果我回想一下围绕y轴的右旋转,也可能会反转x轴。如果是这种情况,你应该能够否定轮换以抵消它。