作者:游蓝海(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坐标系统的更多相关文章

  1. opengl坐标系统

    概述 为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model).观察(View).投影(Projection)三个矩阵.我们的顶点坐标起始于局部空间(L ...

  2. OpenGL.Tutorial16_ShadowMapping

    1. 2. In Tutorial 15 we learnt how to create lightmaps, which encompasses(包含) static lighting. While ...

  3. Vulkan vs OpenGL ES

    Vulkan 简介 Vulkan是一个免费开放的.跨平台的.底层的图形API,在一定程度上比AMD Mantle.微软DirectX 12.苹果Metal更值得开发者关注. Vulkan的最大任务不是 ...

  4. OpenGL与Directx的区别

    OpenGL 只是图形函数库. DirectX 包含图形, 声音, 输入, 网络等模块. 单就图形而论, DirectX 的图形库性能不如 OpenGL OpenGL稳定,可跨平台使用.但 OpenG ...

  5. OpenGL ES 入门

    写在前面 记录一下 OpenGL ES Android 开发的入门教程.逻辑性可能不那么强,想到哪写到哪.也可能自己的一些理解有误. 参考资料: LearnOpenGL CN Android官方文档 ...

  6. OpenGL ES: (1) OpenGL ES的由来 (转)

    1. 电脑是做什么用的? 电脑又被称为计算机,那么最重要的工作就是计算.看过三体的同学都知道, 电脑中有无数纳米级别的计算单元,通过 0 和 1 的转换,完成加减乘除的操作. 2. 是什么使电脑工作? ...

  7. 64 计算机图形学入门(1)——OpenGL环境配置与图形流水线(图像管线)

    0 引言 最近想学一下计算机图形学方面的知识,原因如下.目前本人接触了数字图像处理(opencv)以及点云处理(PCL)方面的知识,对从图像和点云中提取特征信息,并将特征转化为底层/中层语义信息有了一 ...

  8. OpenGL在图形管道中调用了什么用户模式图形驱动程序(UMD)?

    OpenGL在图形管道中调用了什么用户模式图形驱动程序(UMD)? 图形硬件供应商,需要为显示适配器编,编写用户模式显示驱动程序.用户模式显示驱动程序,是由Microsoft Direct3D运行时加 ...

  9. Opengl ES之纹理贴图

    纹理可以理解为一个二维数组,它可以存储大量的数据,这些数据可以发送到着色器上.一般情况下我们所说的纹理是表示一副2D图,此时纹理存储的数据就是这个图的像素数据. 所谓的纹理贴图,就是使用Opengl将 ...

随机推荐

  1. mac date命令

    usage: date [-jnu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... [-f fmt date | [[[mm]dd ...

  2. ueditor在QQ浏览器或者IE浏览器中无法加载

    因为IE浏览器有兼容问题,打开网址,浏览器不一定以最新的文档模式加载.按F12查看 在你网址的head标签中加入:<meta http-equiv="x-ua-compatible&q ...

  3. linux命令(24):find命令

    1.命令格式: find pathname -options [-print -exec -ok ...] 2.命令功能: 用于在文件树种查找文件,并作出相应的处理 3.命令参数: pathname: ...

  4. redis之(十)redis实现消息中间件的功能

    [一]任务队列的好处 --->松耦合:生产者和消费者无需知道彼此实现的细节,只需要约定好任务的描述格式.这使得生产者和消费者可以由不同的团队使用不同的编程语言编写. --->易于扩展:消费 ...

  5. hdu 3729(二分图最大匹配)

    I'm Telling the Truth Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  6. js实现图片下载

    <img src='src' data-name='自定义名称'><script>//js实现图片下载 function download(){ var name = $('# ...

  7. lr计算程序执行消耗时间的比较:

    去除程序执行的两种方式: 1.通过一个事务:在需要消除的代码段,使用lr_wasted_time(wasteTime); querySubmit() { char newStr4[10000]=&qu ...

  8. gitlab备份与恢复

    (1)备份 1.创建备份目录,并授权 mkdir /data/backups/gitlab -pv chown -R git.git /data 2.修改gitlab配置 vim /etc/gitla ...

  9. POJ1742 Coin [DP补完计划]

    题目传送门 Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 41707   Accepted: 14125 Des ...

  10. Shiro过滤器的维护与匹配执行

    servlet的初始化会触发核心过滤器的创建: public Object getObject() throws Exception { if (instance == null) { instanc ...