统一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

时间: 07-18

统一D3D与OpenGL坐标系统的相关文章

OpenGL.坐标系统的介绍与坐标变换的实现

坐标变换其实一直是一个比较让人着迷的内容,嘿嘿嘿 从中也可以看到矩阵的魅力 记得一篇文章讲,矩阵就是记录一个向量到另一个向量的运动,一个点可以用一个向量来表示,乘上一个矩阵就变成了另一个向量,对应着另一个点.所以说矩阵就是记录向量空间中向量的运动,记录向量之间的转换规则. 齐次坐标 只讲三维的情况啊 向量空间中,只有标量和向量 向量 + 向量 = 向量 标量 * 向量 = 向量 三维向量空间中,可以视任意一组线性无关的向量为基 基 V = [ v1 , v2 , v3 ] 其他向量可以用一个三维

OpenGL坐标系统

一.坐标系统概述 本文类容见LearnOpenGL CN.直接copy过来留个存档. OpenGL希望每次顶点着色后,我们的可见顶点都为标准化设备坐标(Normalized Device Coordinate,NDC).也就是说每个顶点的\(z,y,z\)都应该在\(-1\)到\(1\)之间,超出这个范围的顶点将是不可见的.通常情况下我们会自己设定一个坐标范围,之后再在顶点着色器中将这些坐标变换为表转化设备坐标.然后这些标化设备坐标传入光栅器(Rasterizer),将它们变换为屏幕上的二维坐标

Android OpenGL ES向导学习笔记(扫盲专用)

Android 目前支持下面几个版本的OpenGL ES API : OpenGL ES 1.0 和 1.1 :Android 1.0和更高的版本支持这个API规范. OpenGL ES 2.0 : Android 2.2(API 8)和更高的版本支持这个API规范. OpenGL ES 3.0 : Android 4.3(API 18)和更高的版本支持这个API规范. OpenGL ES 3.1 :  Android 5.0(API 21)和更高的版本支持这个API规范. 支持OpenGL E

图形世界分裂的两派——理清Direct3D和OpenGL的脉络

计算机三维图形是指将用数据描述的三维空间通过计算转换成二维图像并显示或打印出来的技术,API(Application Programming Interface)即"应用程序接口"是连接应用程序与操作系统.实现对计算机硬件控制的纽带,Direct3D和OpenGL是目前的两大3D图形 API,要在你的3D显卡上进行3D特效的制作.实现都必须通过它们(Vooodoo迷们肯定对Glide接口记忆尤深,可惜已随着3dfx的倒闭而作古,其它还有Heidi等接口).关于D3D和OpenGL的理论

OpenGL与Directx的区别

OpenGL 只是图形函数库. DirectX 包含图形, 声音, 输入, 网络等模块. 单就图形而论, DirectX 的图形库性能不如 OpenGL OpenGL稳定,可跨平台使用.但 OpenGL 多需要显卡支持. ---------------------------------------------------------------------------------------------- 做windows平台上的游戏,当然是DX,想跨平台,想做科学计算程序,想做CAD, 想做

(转)固定渲染管线与可编程渲染管线

1.固定渲染管线与可编程渲染管线的区别: 1).固定渲染管线 ——这是标准的几何&光照(T&L)管线,功能是固定的,它控制着世界.视.投影变换及固定光照控制和纹理混合.T&L管线可以被渲染状态控制,矩阵,光照和采制参数. 2).顶点着色器——图形开发人员可以对渲染管线中的顶点运算和像素运算分别进行编程处理了,而无须象以前那样套用一些固定函数,取代设置参数来控制管线,最早出现与DX8,包括PS和VS两部分. 2.为了解决D3D或者OpenGL对不同硬件厂商的支持,解决移植性的问题,可

固定渲染管线与可编程渲染管线的区别

1.固定渲染管线与可编程渲染管线的区别: 1).固定渲染管线 ——这是标准的几何&光照(T&L)管线,功能是固定的,它控制着世界.视.投影变换及固定光照控制和纹理混合.T&L管线可以被渲染状态控制,矩阵,光照和采制参数. 2).顶点着色器——图形开发人员可以对渲染管线中的顶点运算和像素运算分别进行编程处理了,而无须象以前那样套用一些固定函数,取代设置参数来控制管线,最早出现与DX8,包括PS和VS两部分. 2.为了解决D3D或者OpenGL对不同硬件厂商的支持,解决移植性的问题,可

Cg与RenderMonkey 之旅

http://news.mydrivers.com/1/15/15020_all.htm [前言] 您可能还没有意识到---您手头的这块显卡(或者说这块GPU)---它不仅仅是一个应用工具(游戏.平面设计或诸如此类)---它还是一个开发工具. 游戏开发者的硬件配置似乎总比我们普通用户的要高(当然是指3D游戏的开发者,现在没有游戏不是3D的了吧?抛开多如牛毛的FPS不说,一直是2D唱主角的RTS,如魔兽争霸III到命令与征服-将军也都已毫不例外的转到了3D),在"ATi的魔咒日-程序员的训练课程&

转:Ogre源码分析之Root类、Facade模式

Ogre源码分析(一)Root类,Facade模式 Ogre中的Root对象是一个Ogre应用程序的主入口点.因为它是整个Ogre引擎的外观(Façade)类.通过Root对象来开启和停止Ogre是最简单的一种方式:当你构造构造一个Root实例的时候你就启动了整个Ogre,当析构的时候(让它停止活动或者执行delete删除它)Ogre也就关闭了. API手册中这样介绍到:Ogre::Root 类代表了客户应用程序的入口点.在这里,应用程序可以获得系统的重要的访问权,也就是获取渲染系统 ,管理配置