OPENGL设备坐标系(dns)是左手坐标系,屏幕坐标系原点在左下角向上向右增加

OPENGL屏幕坐标系原点在左下角向上向右增加,D3D屏幕坐标系原点在左上角向下向右增加。
所以glViewPort的从设备坐标系变换到屏幕空间的变换公式为:

使得(-1,-1)到左下角(x0,y0), (1,1)到右上角(x0 + w, y0 + h)。

D3D中设备坐标系变换到屏幕的公式为:
Xw = x* w/2 + w / 2 + x0;
Yw = -y * h/2 + h / 2 + y0;
使得(-1,1)到左上角(x0,y0), (1,-1)到右下角(x0 + w, y0 + h)。

还需要注意OPENGL中像素的位置在格子中心,D3D9在格子左上角因此偏移0.5个像素,D3D10在格子中心。

拓展OPENGL和D3D区别联系见: http://blog.chinaunix.net/uid-20235103-id-3060257.html
1.世界坐标系不同,视图坐标系和投影坐标系不同导致三角网格顶点数据不同,法向量需要调整,还有叉积和旋转变换不同,绘制正面不同。矩阵表示不同,OGL是用列式矩阵,和列式向量,所以要矩阵右乘向量得到变换结果。

2.屏幕坐标系不同和像素中心不同

    提到了坐标系的区别,另一个类似的区别出现在窗口朝向上。D3D用了左上角作为原点,而OpenGL用了左下角。D3D9用了像素左上角作为原点,而OpenGL和D3D10+用了像素中心。在像素和纹理需要1:1对应的时候,该问题就需要严重关注了。详见Directly Mapping Texels to Pixels。

窗口原点的不同造成的结果就是,两个API做render to texture之后,产生的texture在y方向是相反的。这本身可以通过调整project matrix来调整。简而言之,就是:

glMatrixLoadIdentityEXT(GL_PROJECTION);
glMatrixScalefEXT(GL_PROJECTION, 1, -1, 0); // y方向取反
glMatrixTranslatefEXT(GL_PROJECTION,  0.5f / win_width, 0.5f / win_height, 0); // 调整到D3D9的话还需要偏移0.5个像素

因此,OpenGL提供了GL_ARB_fragment_coord_conventions这个扩展,专门用来指定像素坐标的原点和偏移。在GLSL的声明里添加个属性:

// OpenGL原生的方式
in vec4 gl_FragCoord;

// D3D9的方式
layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;

// D3D10+的方式
layout(origin_upper_left) in vec4 gl_FragCoord;

这样就可以把像素坐标调整过来。

综上所述,通过现代OpenGL核心和扩展的支持,填平了一些原本被认为位于底层的区别,同时不会有性能损失。破解了上篇提到的流言3。下篇将剖析两个API的功能异同,以及直接相互访问的可能性。


 3.Z缓存值大小不同

    初学者经常 说,OpenGL用右手坐标系,而D3D用左手;裁剪空间里OpenGL的z是[-1, 1],而D3D是[0, 1];不可调和。实际上,直接把左手的顶点和矩阵给OpenGL也是没有问题的。毕竟如果在VS里执行的都是mul(v, matrix),得到的会是同样的结果。可能会造成麻烦的反而是viewport的z。假设一个经过clip之后的顶点坐标为(x, y, z, w),那么在OpenGL上,该顶点经过viewport变换的z是(z/w + 1) / 2,而在D3D上则是z/w而已。这对于depth test不影响,但depth buffer里的值就不同了。所以需要对project matrix做一些调整,才能让他们写到depth buffer中的数值相同。具体来说,如果要让OpenGL流水线接受D3D的project matrix,就需要乘上

为什么是这样,其实不用关注的?

相当于把project space的顶点z都作了z = z * 2 – 1的操作,所以经过viewport变换就一致了。D3D到OpenGL的矩阵也可以依此类推。所以,在坐标系上,很容易就能使两者接受同样的输入,同时也没有增加runtime开销。



4.颜色值格式不同

D3D9 最常用的顶点颜色格式是BGRA格式(也就是D3DCOLOR),而OpenGL默认用的是RGBA格式。D3D9用BGRA纯粹是因为历史原因,早期硬 件不支持UBYTE4的格式,只能用D3DCOLOR,然后再shader里调用D3DCOLORtoUBYTE4。现在的GPU都支持 UBYTE4,D3D10+也是可以直接使用RGBA,所以这已经不是问题了。

如果需要兼容已经生成BGRA格式数据,现代OpenGL提供了GL_EXT_vertex_array_bgra这个扩展,也可以使用BGRA作为顶点颜色输入格式:

glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, stride, pointer);
glSecondaryColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, stride, pointer);
glVertexAttribPointer(GL_BGRA, GL_UNSIGNED_BYTE, stride, pointer);

该扩展进入了OpenGL 3.2的核心。


5.D3D11的一些高级特性还只是软件层面的,而且OPENGL也可以实现

State对象

D3D 10新增了State对象,可以极大地减少由于改变渲染状态所需的系统调用次数。OpenGL中目前还没有State对象,所以只能在上层自行封装。虽然 有些 性能损失,但接口可以和D3D统一起来。ARB针对OpenGL的State对象进行过旷日持久的讨论,还最终各大厂商没有达成一致。不过这是个趋势,相 信不久的将来就会出个相关的扩展。到时候这个区别就能被完美地填平。

Compute Shader

D3D 11引入了compute shader,在D3D中直接提供了GPGPU的能力。OpenGL没有因此增加一种shader,而是增强和同门师弟OpenCL的互操作能力。 OpenGL和OpenCL能直接共享texture和buffer等,起到了和compute shader等价的功能。与GLSL和HLSL的关系一样,这里存在着shader语言不同的问题,而且没有Cg可以作为桥梁,目前只能写两份代码。

Multithreading

D3D 11的multithreading能力允许多个context都调用D3D11 API,每个context保存下来的API调用流可以在主context执行依次执行。OpenGL目前也没有引入该机制,需要在上层自行实现。话说回 来了,目前的所有显卡 驱动都没有实现multithreading,所以所有多context都是由D3D runtime软件实现的,没有达到应有的提速效果。自己实现一个command list也能达到那样的性能。仍然希望某一天multithreading能成为OpenGL的功能 之一,简化上层的工作。

总结

所以说,OpenGL和D3D功能的交集几乎就是它们的并集,并不会因为需要兼容两者而失去很多功能。从功能上说,OpenGL和D3D之间的分歧甚至小于OpenGL和OpenGL ES。破解了第一篇说的流言4。

6.Shader部分,cg可以编译大部分着色器代码为GLSL和HLSL.


你可能感兴趣的:(OpenGL图形学)