统一D3D与OpenGL坐标系统

Posted cynchanpin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了统一D3D与OpenGL坐标系统相关的知识,希望对你有一定的参考价值。

作者:游蓝海(http://blog.csdn.net/you_lan_hai


        DirectX 3D与OpenGL坐标系统的差异性,给我们带来非常大的麻烦。让跨平台编程的新手非常困惑。近期在做一个跨平台的游戏,细致看了下两者的矩阵。发现并没有什么大差别,将d3d左手系的矩阵传递给opengl shader全然能够正常工作。

        先说一下两者一些概念上的差别:

        (1)坐标系统不同

        d3d左手坐标系,opengl右手坐标系

        (2)矩阵行序不同

        d3d行优先,opengl列优先。这两个不同,直接导致了坐标变换顺序与矩阵乘法顺序的相反性。假设是先缩放。再旋转,最后平移。相应的矩阵分别为S、R、T,则d3d的终于矩阵为M = S * R * T。opengl为M = T * R * S

        (3)裁减空间z取值范围不同

        d3d是[0, 1]。opengl是[-1, 1]


        表面上来看,两者矩阵区别非常大。但事实上不然。

1.左右手坐标系

        对于显卡设备来说,设备坐标系是左手坐标系,即z轴指向屏幕里面。z值越大表示距离视线越远。

因此,opengl的右手系,在进入裁减空间的时候。会转换成左手系。

这也就是说。在渲染管线内部。坐标系是统一的。无论是左手坐标系矩阵,还是右手坐标系矩阵。仅仅要变换到裁减空间中的点是左手系就能够了。


2.矩阵行序

        行矩阵和列矩阵,在逻辑上一个是还有一个的转置。但在物理存贮结构上却是全然一致的。如一个平移变换(x, y, z):

技术分享

        须要注意的是,矩阵乘法并不关心矩阵是行矩阵还是列矩阵。都是依照第一个矩阵的行去乘以第二个矩阵的列。对于列矩阵而言,这正是其蹩脚的地方,为了保证乘法意义的有效性,其坐标变换顺序跟矩阵乘法顺序恰好相反。

        还要注意一点,在shader中,opengl的矩阵乘法规则跟d3d是不同的。

依照矩阵乘法规则(第一个矩阵行*第二个矩阵列):

        d3d矩阵乘法:      Ma(0 1 2 3) * Mb(0 4 8 12)

        opengl矩阵乘法: Ma(0 4 8 12) * Mb(0 1 2 3)

        因此。对于opengl shader而言。变换顺序跟矩阵乘法顺序依旧是反的。假设我们能将传入opengl shader的矩阵做一次转置。那么opengl shader的矩阵乘法意义将跟d3d shader全然一致!


3.改动投影矩阵

        因为opengl的裁减空间z取值范围为[-1, 1]跟d3d的[0, 1]不同,我们不能简单的使用d3d投影矩阵。必须又一次定义d3d投影矩阵。

void Matrix::perspectiveProjectionLH2( float fov, float aspectRatio,
        float nearPlane, float farPlane )
{
        float h = (1.0f / tanf(fov * 0.5f));
        float w = h / aspectRatio;

        float a = (farPlane + nearPlane) / (farPlane - nearPlane);
        float b = -2.0f * farPlane * nearPlane / (farPlane - nearPlane);
        
        m[0][0] = w; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
        m[1][0] = 0; m[1][1] = h; m[1][2] = 0; m[1][3] = 0;
        m[2][0] = 0; m[2][1] = 0; m[2][2] = a; m[2][3] = 1;
        m[3][0] = 0; m[3][1] = 0; m[3][2] = b; m[3][3] = 0;
}


4.总结

        使用左手系变换来统一两个平台是比較方便的。总结一下改动opengl渲染管线的步骤:

        (1)在c++层统一使用左手坐标系变换。

        (2)改动投影矩阵。以适应裁减空间z坐标范围[-1, 1];

        (3)矩阵在传入shader的时候,将矩阵的转置矩阵传入;

        (4)在shader层,统一使用左手坐标系变换。

假设,不想改动shader中的变换,仅仅用做到(1)和(2)就够了。


5.很多其它阅读

推导投影矩阵 http://blog.csdn.net/popy007/article/details/4091967

跨越opengl和d3d的鸿沟 http://www.cppblog.com/topjackhjj/articles/157038.html












以上是关于统一D3D与OpenGL坐标系统的主要内容,如果未能解决你的问题,请参考以下文章

CSOL OpenGL与D3D哪个好?

跨多个着色器的 OpenGL 统一

Qt+Windows,Windows 底层默认使用d3d还是opengl?

OPENGL和D3D哪个好

OpenGL 440 - 控制片段中的线条粗细。

在 CG 和 openGL 中使用统一的 1D 纹理参数时出错