﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-GraphicSir-文章分类-图形技术</title><link>http://www.cppblog.com/topjackhjj/category/9563.html</link><description>游戏技术,实时渲染技术</description><language>zh-cn</language><lastBuildDate>Thu, 29 Sep 2011 10:33:03 GMT</lastBuildDate><pubDate>Thu, 29 Sep 2011 10:33:03 GMT</pubDate><ttl>60</ttl><item><title>跨越OpenGL和D3D的鸿沟[转]</title><link>http://www.cppblog.com/topjackhjj/articles/157038.html</link><dc:creator>翾</dc:creator><author>翾</author><pubDate>Wed, 28 Sep 2011 01:25:00 GMT</pubDate><guid>http://www.cppblog.com/topjackhjj/articles/157038.html</guid><wfw:comment>http://www.cppblog.com/topjackhjj/comments/157038.html</wfw:comment><comments>http://www.cppblog.com/topjackhjj/articles/157038.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/topjackhjj/comments/commentRss/157038.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/topjackhjj/services/trackbacks/157038.html</trackback:ping><description><![CDATA[注:本文转自<a href="http://www.klayge.org/"><font color="#1d5f83">KlayGE游戏引擎</font></a>.<br /><br /><span style="color: #0000ff; font-size: 24pt"><strong>（一）：开篇</strong></span><br />
<p>多年来，在论坛和各个网站上不断能看到拿OpenGL和D3D进行比较的帖子和文章。他们经常制造很多谜思，使得初学者和一些从业人员对OpenGL和D3D产生了各种各样的流言。</p>
<ol><li>有人说，OpenGL直接调到驱动，性能高于D3D。</li><li>有人说，Shader都得写两套，很麻烦。</li><li>有人说，OpenGL和D3D在底层有很多区别，而且不可设置。</li><li>有人说，图形引擎如果要兼容两者，就只能取其功能的交集，最后还不如任何一种API。</li></ol>
<p><strong>真的么？</strong></p>
<p>本文试图：</p>
<ul><li>找出现代OpenGL和D3D的共通之处</li><li>归纳如何让API对上层代码尽量透明</li></ul>
<p>本文不希望：</p>
<ul><li>讲解函数间的对应关系</li><li>如何在OpenGL和D3D之间作选择</li><li>贬低一方，抬高另一方</li></ul>
<p>下面先从几个比较基本的方面来探讨如何跨越两个API的鸿沟。</p>
<h2>架构</h2>
<p>OpenGL和D3D的架构基本上是这个样子的：</p>
<p><a href="http://www.klayge.org/wp/wp-content/uploads/2011/07/OGL_D3D_arch.png"><img class="aligncenter size-full wp-image-1245" title="OGL_D3D_arch" alt="The architecture of OGL and D3D" src="http://www.klayge.org/wp/wp-content/uploads/2011/07/OGL_D3D_arch.png" width="894" height="321" /></a></p>
<p>在架构上其实两者没有什么区别，只是D3D的runtime是在OS里，对于不同硬件来说都是一样的。而OpenGL的runtime直接是和驱动合为一体的。但这并不会造成性能有所差别，破解了流言1。</p>
<h2>Shader</h2>
<p>OpenGL 的原生shading language是GLSL，D3D的是HLSL。两者语法相似，但细节上天差地别。好在，NVIDIA的Cg在很大程度上类似于HLSL，而且可以编译 出GLSL来。所以，Cg编译器成了跨越这两种shader的桥梁。当然，要真正实用起来，还需要不少工作。比如Cg的Geometry Shader和HLSL 10+的有些许不同，需要通过#ifdef来分开。另外，Cg编译器生成的GLSL需要一些调整才能在ATI的驱动上工作，所以还需要多一次转换。好在这 些事情都可以通过程序自动完成，而且速度很快。具体可以参考KlayGE的OGLShaderObject::ConvertToGLSL。实际上，KlayGE的所有shader都只写了一份（语法用HLSL 11的），在不同API上可以自动编译成原生的shader使用（有OpenGL和OpenGL ES的编译器，曾经还有D3D9的）。这样就没有重写的繁琐，也没有增加runtime开销，破解了流言2。</p>
<p>当然，这里还有另一种更好的选择，把HLSL编译器生成的bytecode转换成GLSL。UE3等引擎用了<a href="http://icculus.org/mojoshader/" target="_blank"><font color="#1d5f83">MojoShader</font></a>来完成这件事情。优点是不需要多次编译，缺点是不支持SM4+。</p>
<h2>坐标系</h2>
<p>初学者经常 说，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，就需要乘上</p>
<p><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/topjackhjj/untitled.JPG" width="133" height="81" /><br />相当于把project space的顶点z都作了z = z * 2 &#8211; 1的操作，所以经过viewport变换就一致了。D3D到OpenGL的矩阵也可以依此类推。所以，在坐标系上，很容易就能使两者接受同样的输入，同时也没有增加runtime开销。 
<p>本篇讲的都是可以在不改变API的情况下，通过输入数据来消除OpenGL和D3D之区别。下一篇将讲解如何利用现代OpenGL提供的扩展和新功能，消除一些无法在上层解决的问题，继续破解各种流言。<br /><br /><br /><span style="color: #0000ff; font-size: 24pt"><strong>（二）：现代OpenGL</strong></span><br /><br /></p>
<p>上一篇提出了跨越OpenGL和D3D的基本问题，介绍了一些能在不改变API的情况下，通过输入数据来消除OpenGL和D3D之区别。本篇的重点是如何利用现代OpenGL提供的扩展和新功能，消除一些无法在上层解决的问题。</p>
<h2>顶点颜色顺序</h2>
<p>D3D9 最常用的顶点颜色格式是BGRA格式（也就是D3DCOLOR），而OpenGL默认用的是RGBA格式。D3D9用BGRA纯粹是因为历史原因，早期硬 件不支持UBYTE4的格式，只能用D3DCOLOR，然后再shader里调用D3DCOLORtoUBYTE4。现在的GPU都支持 UBYTE4，D3D10+也是可以直接使用RGBA，所以这已经不是问题了。</p>
<p>如果需要兼容已经生成BGRA格式数据，现代OpenGL提供了<a href="http://www.opengl.org/registry/specs/EXT/vertex_array_bgra.txt" target="_blank"><font color="#1d5f83">GL_EXT_vertex_array_bgra</font></a>这个扩展，也可以使用BGRA作为顶点颜色输入格式：<br /><br /></p>
<div class="cpp codecolorer">glColorPointer<span class="br0">(</span>GL_BGRA, GL_UNSIGNED_BYTE, stride, pointer<span class="br0">)</span><span class="sy4">;</span><br />glSecondaryColorPointer<span class="br0">(</span>GL_BGRA, GL_UNSIGNED_BYTE, stride, pointer<span class="br0">)</span><span class="sy4">;</span><br />glVertexAttribPointer<span class="br0">(</span>GL_BGRA, GL_UNSIGNED_BYTE, stride, pointer<span class="br0">)</span><span class="sy4">;</span>&nbsp;</div>
<p>&nbsp;</p>
<p>该扩展进入了OpenGL 3.2的核心。</p>
<h2>Flat shading</h2>
<p>Flat shading在渲染中用的机会远远少于Gouraud shading。很多人只知道Flat shading是选择一个顶点的属性作为primitive上每个像素的属性，而不会注意到D3D和OpenGL在&#8220;哪个顶点&#8221;上的选择有所区别。D3D 用line或triangle第一个顶点的属性。而OpenGL在line、triangle或quad的时候最后一个顶点的属性（但在polygon的 时候用的是第一个）。</p>
<p>现在，OpenGL出现了<a href="http://www.opengl.org/registry/specs/EXT/provoking_vertex.txt" target="_blank"><font color="#1d5f83">GL_EXT_provoking_vertex</font></a>这个扩展，可以选择使用哪个顶点的属性来驱动（这就是provoking的意思）一个primitive。它很容易使用：<br /><br /></p>
<div class="cpp codecolorer"><em><font color="#406040"><span class="co1">// OpenGL原生的方式</span><br /></font></em>glProvokingVertex<span class="br0">(</span>GL_LAST_VERTEX_CONVENTION<span class="br0">)</span><span class="sy4">;</span><br /><em><font color="#406040"><span class="co1">// D3D的方式</span><br /></font></em>glProvokingVertex<span class="br0">(</span>GL_FIRST_VERTEX_CONVENTION<span class="br0">)</span><span class="sy4">;</span></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>该扩展也进入了OpenGL 3.2的核心。</p>
<h2>状态切换</h2>
<p>D3D9的状态切换是通过SetRenderState这样的函数来完成的，而OpenGL则是完全基于状态机的结构，比如要设置model view矩阵，同时要求不影响状态，就需要：<br /><br /></p>
<div class="cpp codecolorer"><span class="kw4"><font color="#008080">void</font></span> set_model_view_matrix<span class="br0">(</span>GLfloat <span class="kw4"><font color="#008080">const</font></span> matrix<span class="br0">[</span><span class="nu0"><font color="#0080a0">16</font></span><span class="br0">]</span><span class="br0">)</span><br /><span class="br0">{</span><br />&nbsp; &nbsp;GLenum saved_mode<span class="sy4">;</span><br />&nbsp;&nbsp;&nbsp;glGetIntegerv<span class="br0">(</span>GL_MATRIX_MODE, <span class="sy3">&amp;</span>amp<span class="sy4">;</span>saved_mode<span class="br0">)</span><span class="sy4">;</span><br />&nbsp; &nbsp;glMatrixMode<span class="br0">(</span>GL_MODELVIEW<span class="br0">)</span><span class="sy4">;</span><br />&nbsp; &nbsp;glLoadMatrixf<span class="br0">(</span>matrix<span class="br0">)</span><span class="sy4">;</span><br />&nbsp; &nbsp;glMatrixMode<span class="br0">(</span>saved_mode<span class="br0">)</span><span class="sy4">;</span><br /><span class="br0">}</span>&nbsp;</div>
<p>&nbsp;</p>
<p>如果这里不这样繁琐，就很可能在十万八千里的地方出问题。相信每个用OpenGL的人都曾遇到过，尤其是多人合作的时候。一个状态的错误都可能导致灾难。</p>
<p>现在，救星来了。<a href="http://www.opengl.org/registry/specs/EXT/direct_state_access.txt" target="_blank"><font color="#1d5f83">GL_EXT_direct_state_access</font></a>扩展（简称DSA）的出现大大地改变了这点。该扩展提供了直接访问状态的能力，比如前面的设置model view矩阵，只需要：<br /><br /></p>
<div class="cpp codecolorer"><span class="kw4"><font color="#008080">void</font></span> set_model_view_matrix<span class="br0">(</span>GLfloat <span class="kw4"><font color="#008080">const</font></span> matrix<span class="br0">[</span><span class="nu0"><font color="#0080a0">16</font></span><span class="br0">]</span><span class="br0">)</span><br /><span class="br0">{</span><br />&nbsp; &nbsp;glMatrixLoadfEXT<span class="br0">(</span>GL_MODELVIEW, matrix<span class="br0">)</span><span class="sy4">;</span><br /><span class="br0">}</span></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>简单多了吧。DSA把绝大部分OpenGL核心和各个扩展提供的状态都增加了一个直接访问的版本，相当方便。理论上，性能还能有所提高。可惜的是，DSA至今还没进入OpenGL的核心，虽然在NV和ATI的卡上都可以使用。</p>
<h2>窗口原点</h2>
<p><a title="跨越OpenGL和D3D的鸿沟（一）：开篇" href="http://www.klayge.org/2011/07/15/%e8%b7%a8%e8%b6%8aopengl%e5%92%8cd3d%e7%9a%84%e9%b8%bf%e6%b2%9f%ef%bc%88%e4%b8%80%ef%bc%89%ef%bc%9a%e5%bc%80%e7%af%87/" target="_blank"><font color="#1d5f83">上一篇</font></a>提到了坐标系的区别，另一个类似的区别出现在窗口朝向上。D3D用了左上角作为原点，而OpenGL用了左下角。D3D9用了像素左上角作为原点，而OpenGL和D3D10+用了像素中心。在像素和纹理需要1:1对应的时候，该问题就需要严重关注了。详见<a href="http://msdn.microsoft.com/en-us/library/bb219690%28v=vs.85%29.aspx" target="_blank"><font color="#1d5f83">Directly Mapping Texels to Pixels</font></a>。</p>
<p>窗口原点的不同造成的结果就是，两个API做render to texture之后，产生的texture在y方向是相反的。这本身可以通过调整project matrix来调整。简而言之，就是：<br /><br /></p>
<div class="cpp codecolorer">glMatrixLoadIdentityEXT<span class="br0">(</span>GL_PROJECTION<span class="br0">)</span><span class="sy4">;<br /><span class="co1"><em><font color="#406040">// y方向取反</font></em></span><br /></span>glMatrixScalefEXT<span class="br0">(</span>GL_PROJECTION, <span class="nu0"><font color="#0080a0">1</font></span>, <span class="sy2">-</span><span class="nu0"><font color="#0080a0">1</font></span>, <span class="nu0"><font color="#0080a0">0</font></span><span class="br0">)</span><span class="sy4">;</span> <br /><span class="co1"><em><font color="#406040">// 调整到D3D9的话还需要偏移0.5个像素</font></em></span><br />glMatrixTranslatefEXT<span class="br0">(</span>GL_PROJECTION,&nbsp; <span class="nu17">0.5f</span> <span class="sy2">/</span> win_width, <span class="nu17">0.5f</span> <span class="sy2">/</span> win_height, <span class="nu0"><font color="#0080a0">0</font></span><span class="br0">)</span><span class="sy4">;</span>&nbsp;&nbsp;</div>
<p>&nbsp;</p>
<p>由于y方向反了，还需要调用glFrontFace(GL_CW)来把正面方向反一下，否则cull会出错。窗口原点就这样通过上层代码来解决了。</p>
<p>但这只能调整窗口原点，OpenGL下像素坐标仍是以左下角作为原点，而像素坐标在post process里很常用。因此，OpenGL提供了<a href="http://www.opengl.org/registry/specs/ARB/fragment_coord_conventions.txt" target="_blank"><font color="#1d5f83">GL_ARB_fragment_coord_conventions</font></a>这个扩展，专门用来指定像素坐标的原点和偏移。在GLSL的声明里添加个属性：<br /><br /></p>
<div class="cpp codecolorer"><em><font color="#406040"><span class="co1">// OpenGL原生的方式</span><br /></font></em>in vec4 gl_FragCoord<span class="sy4">;</span><br /><em><font color="#406040"><span class="co1">// D3D9的方式</span><br /></font></em>layout<span class="br0">(</span>origin_upper_left, pixel_center_integer<span class="br0">)</span> in vec4 gl_FragCoord<span class="sy4">;</span><br /><em><font color="#406040"><span class="co1">// D3D10+的方式</span><br /></font></em>layout<span class="br0">(</span>origin_upper_left<span class="br0">)</span> in vec4 gl_FragCoord<span class="sy4">;</span></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>这样就可以把像素坐标调整过来。</p>
<p>综上所述，通过现代OpenGL核心和扩展的支持，填平了一些原本被认为位于底层的区别，同时不会有性能损失。破解了<a title="跨越OpenGL和D3D的鸿沟（一）：开篇" href="http://www.klayge.org/2011/07/15/%e8%b7%a8%e8%b6%8aopengl%e5%92%8cd3d%e7%9a%84%e9%b8%bf%e6%b2%9f%ef%bc%88%e4%b8%80%ef%bc%89%ef%bc%9a%e5%bc%80%e7%af%87/"><font color="#1d5f83">上篇</font></a>提到的流言3。下篇将剖析两个API的功能异同，以及直接相互访问的可能性。</p>
<p><br /><br /><strong style="color: #0000ff; font-size: 24pt">（三）：交集？并集？</strong><strong><br /></strong><br /><a href="http://www.klayge.org/2011/07/17/跨越opengl和d3d的鸿沟（二）：现代opengl/" target="_blank">上一篇</a>讲到了如何填平OpenGL和D3D之间一些原本被认为位于底层的区别。本篇将剖析两个API在功能上的异同，以及直接相互访问的可能性。<br /><br /><font size="5"><strong>功能</strong></font><br />D3D9的功能早已被OpenGL 2.0所覆盖，网上可以找到很多资料，这里就不提了。本文注重的是新的GPU特性。下表列出了D3D10+的新功能，以及实现该功能所需要的OpenGL扩展或核心。<br />
<table class="t_table" cellspacing="0">
<tbody>
<tr>
<td>D3D 10的功能</td>
<td>OpenGL所对应的</td></tr>
<tr>
<td>Geomrtry shader</td>
<td>GL_ARB_geometry_shader4或OpenGL 3</td></tr>
<tr>
<td>Stream output</td>
<td>GL_EXT_transform_feedback或OpenGL 3</td></tr>
<tr>
<td>State对象</td>
<td>无，需要在上层封装GL_EXT_direct_state_access</td></tr>
<tr>
<td>Constant buffer</td>
<td>GL_ARB_uniform_buffer_object或OpenGL 3</td></tr>
<tr>
<td>Texture array和新的资源格式</td>
<td>GL_EXT_texture_array<br />+GL_ARB_texture_compression_rgtc<br />+GL_ARB_texture_rg<br />+GL_ARB_texture_rgb10_a2ui<br />+GL_EXT_texture_integer或OpenGL 3</td></tr>
<tr>
<td>texture和sampler解偶</td>
<td>GL_ARB_sampler_objects或OpenGL 3</td></tr>
<tr>
<td>在shader里进行整数和位操作</td>
<td>GL_ARB_shader_bit_encoding或OpenGL 3</td></tr>
<tr>
<td>Multisampled alpha-to-coverage</td>
<td>GL_NV_multisample_coverage或OpenGL 3</td></tr>
<tr>
<td>D3D 10.1的功能</td>
<td>OpenGL所对应的</td></tr>
<tr>
<td>读取multisample depth/stencil纹理</td>
<td>GL_ARB_texture_multisample或OpenGL 3</td></tr>
<tr>
<td>Cubemap array</td>
<td>GL_ARB_texture_cube_map_array或OpenGL 4</td></tr>
<tr>
<td>gather4</td>
<td>GL_ARB_texture_gather或OpenGL 4</td></tr>
<tr>
<td>D3D 11的功能</td>
<td>OpenGL所对应的</td></tr>
<tr>
<td>Compute Shader</td>
<td>GL_ARB_cl_event + OpenCL</td></tr>
<tr>
<td>Dynamic Shader Linkage</td>
<td>GL_ARB_gpu_shader5或OpenGL 4</td></tr>
<tr>
<td>Multithreading</td>
<td>无</td></tr>
<tr>
<td>Tessellation</td>
<td>GL_ARB_tessellation_shader或OpenGL 4</td></tr></tbody></table>这些都是<a href="http://msdn.microsoft.com/en-us/library/ee416796(v=VS.85).aspx" target="_blank">DX SDK文档</a>里提到的功能，其他一些比较小的功能，也可以很容易找到OpenGL的对应。从上表可以看出，几乎所有D3D的功能都可以直接用相应的OpenGL功能代替，同时没有性能损失。需要重点讨论的是一些例外：<br /><br /><font size="3"><strong>State对象</strong></font><br />D3D 10新增了State对象，可以极大地减少由于改变渲染状态所需的系统调用次数。OpenGL中目前还没有State对象，所以只能在上层自行封装。虽然 有些 性能损失，但接口可以和D3D统一起来。ARB针对OpenGL的State对象进行过旷日持久的讨论，还最终各大厂商没有达成一致。不过这是个趋势，相 信不久的将来就会出个相关的扩展。到时候这个区别就能被完美地填平。<br /><br /><font size="3"><strong>Compute Shader</strong></font><br />D3D 11引入了compute shader，在D3D中直接提供了GPGPU的能力。OpenGL没有因此增加一种shader，而是增强和同门师弟OpenCL的互操作能力。 OpenGL和OpenCL能直接共享texture和buffer等，起到了和compute shader等价的功能。与GLSL和HLSL的关系一样，这里存在着shader语言不同的问题，而且没有Cg可以作为桥梁，目前只能写两份代码。<br /><br /><font size="3"><strong>Multithreading</strong></font><br />D3D 11的multithreading能力允许多个context都调用D3D11 API，每个context保存下来的API调用流可以在主context执行依次执行。OpenGL目前也没有引入该机制，需要在上层自行实现。话说回 来了，目前的所有显卡 驱动都没有实现multithreading，所以所有多context都是由D3D runtime软件实现的，没有达到应有的提速效果。自己实现一个command list也能达到那样的性能。仍然希望某一天multithreading能成为OpenGL的功能 之一，简化上层的工作。<br /><br /><font size="3"><strong>总结</strong></font><br />所以说，OpenGL和D3D功能的交集几乎就是它们的并集，并不会因为需要兼容两者而失去很多功能。从功能上说，OpenGL和D3D之间的分歧甚至小于OpenGL和OpenGL ES。破解了第一篇说的流言4。<br /><br /><font size="5"><strong>互操作</strong></font><br />神奇扩展<a href="http://www.opengl.org/registry/specs/NV/DX_interop.txt" target="_blank">WGL_NV_DX_interop</a>的 出现，使得OpenGL可以正式与D3D进行互操作。（严格来说，互操作能力源自它的前身WGL_NVX_DX_interop，但鉴于他是个NVX实验 性质的扩展，最好小心点用。）该扩展的目的是，在D3D中建立资源，而在 OpenGL中访问它。目前可以支持的是D3D9的纹理、render target和VB的读写。D3D10+的支持将在未来加入。两个API之间所需的同步也是自动完成的。<br />使用WGL_NV_DX_interop进行相互渲染的范例如下：<br /><br /></p>
<div class="blockcode">
<p>// 跟平常一样建立D3D设备和资源<br /></p>
<p>d3d-&gt;CreateDevice(..., &amp;d3dDevice);<br /><br />d3dDevice-&gt;CreateRenderTarget(width, height, D3DFMT_A8R8G8B8,D3DMULTISAMPLE_4_SAMPLES, 0,FALSE, &amp;dxColorBuffer, NULL);<br /><br />d3dDevice-&gt;CreateDepthStencilSurface(width, height, D3DFMT_D24S8,D3DMULTISAMPLE_4_SAMPLES, 0,FALSE, &amp;dxDepthBuffer, NULL);<br /></p>
<p>// 把D3D设备注册给OpenGL</p>
<p>HANDLE gl_handleD3D = wglDXOpenDeviceNV(d3dDevice);<br /></p>
<p><br /></p>
<p>// 把D3Drender target注册成OpenGL纹理对象</p>
<p>GLuint names[2];<br /></p>
<p>HANDLE handles[2];<br /></p>
<p><br /></p>
<p>handles[0] = wglDXRegisterObjectNV(gl_handleD3D, dxColorBuffer,names[0], GL_TEXTURE_2D_MULTISAMPLE, WGL_ACCESS_READ_WRITE_NV);<br /></p>
<p>handles[1] = wglDXRegisterObjectNV(gl_handleD3D, dxDepthBuffer,names[0], GL_TEXTURE_2D_MULTISAMPLE, WGL_ACCESS_READ_WRITE_NV);<br /></p>
<p><br /></p>
<p>// 现在纹理就可以当成普通的OpenGL纹理来用了<br /></p>
<p>// D3D和OpenGL渲到同一个render target<br /></p>
<p><br /></p>
<p>direct3d_render_pass(); // 和平常一样进行D3D渲染<br /></p>
<p><br /></p>
<p>// 锁定render target，交给OpenGL<br /></p>
<p><br /></p>
<p>wglDXLockObjectsNV(handleD3D, 2, handles);<br /></p>
<p><br /></p>
<p>opengl_render_pass(); // 和平常一样进行OpenGL渲染<br /></p>
<p><br /></p>
<p>wglDXUnlockObjectsNV(handleD3D, 2, handles);<br /></p>
<p><br /></p>
<p>direct3d_swap_buffers(); // D3D present</p></div>
<p><br />这样两个API可以和谐共处了，但这个扩展目前仅限于NV的卡。<br />本篇讨论了两个API在功能上的交集和并集，以及互操作的方法。下一篇是本系列的结局，将讨论一些平台相关的问题，并进行系统性的总结。<br /><br /><br /><strong><font color="#0000ff"><span style="font-size: 24pt">（四）：完结篇，平台和未来</span></font><br /></strong><br /></p>
<p align="left"><a href="http://www.klayge.org/2011/07/20/跨越opengl和d3d的鸿沟（三）：交集？并集？/" target="_blank">上篇文章</a>讨论了两个API在功能上的交集，以及互操作的方法。本篇作为系列的结局，将讨论一些平台相关的问题。</p>
<p><br /><font size="5"><strong>平台</strong></font><br />长久以来，一直可以听到一种说法，D3D只能在Windows上用，而OpenGL可以用在所有平台。那么，我们就来看看在各个平台上，几种3D API的可用性。<br /><br /><font size="4"><strong>桌面平台</strong></font><br /><br /><font size="3"><strong>Windows</strong></font><br />Windows 平台在这方面相当全面，D3D11、D3D10、D3D9、OpenGL、OpenGL ES都支持（需要注意的是，只有Vista+支持D3D10和D3D11）。由于OpenGL 4.1可以建立OpenGL ES的context，NV和AMD的驱动都提供了原生的OpenGL ES。这也为浏览器中WebGL的实现提供了方便。<br /><br /><font size="3"><strong>Mac OS X</strong></font><br />Mac OS X所支持的OpenGL比较老旧，也不支持D3D和OpenGL ES。<br /><br /><font size="3"><strong>Linux</strong></font><br />Linux的主打API是OpenGL，最近也加入了OpenGL ES支持。但是实际上，<a href="http://cgit.freedesktop.org/mesa/mesa/commit/?id=e80d59faaa410bfc78af64204bc4055b837c7fad" target="_blank">Linux也是有D3D 1x的</a>！Mesa 的Gallium框架现在有D3D 10和11的state tracker，能把D3D 1x的API调用转到驱动层（其实和Windows上是一样的流程）。这不是个模拟器，而是原生的D3D 1x。虽然目前这个D3D1x for Linux还比较初级，只能执行DX SDK的那些例子，还没法在产品里使用，但这已经是一个很大的突破了。如果继续这么发展下去，在Linux上D3D 1x总有一天可以和OpenGL一样自由使用。<br /><br /><font size="4"><strong>游戏机</strong></font><br />游戏机上的一切都很专用，没必要像PC上那样多功能。所以他们支持的API也很单一。<br /><br /><font size="3"><strong>Xbox 360</strong></font><br />D3D9的改进版，没有OpenGL。因此OpenGL的死硬粉丝John Carmack也让idTech 5支持了D3D。<br /><br /><font size="3"><strong>PS3</strong></font><br />基于OpenGL ES和Cg的LibGCM和PSGL。和OpenGL有所区别。<br /><br /><font size="3"><strong>Wii</strong></font><br />Wii用了独立的专用API。接口上参考了OpenGL，但功能上差别很大。<br /><br /><font size="4"><strong>浏览器</strong></font><br />既然写到这里了，就干脆连浏览器也一起讨论了吧。浏览器支持3D API只是前不久才开始的事情。WebGL开启了这一大门，并迅速地被各大浏览器和开发者所支持。但是IE并没有原生支持WebGL，需要安装<a href="http://iewebgl.com/" target="_blank">第三方插件</a>。<br />最近不少人问我，有没有WebDX？有，就集成在Silverlight中。<a href="http://www.microsoft.com/silverlight/future/" target="_blank">Silverlight 5</a>支持GPU加速，而且内建了3D的能力。Silverlight也能做到和WebGL一样的能力，而且不必使用javascript来编程，直接用支持.NET的语言就可以了。<br /><br />所以，在平台方面，其实<strong>D3D既不是Windows专用的，OpenGL也不是什么平台都有</strong>。不要指望着用一种API统治所有平台。<br /><br /><font size="5"><strong>总结</strong></font><br />从 本系列可以看出，OpenGL和D3D的差异实际上远远小于原先所认为的。绝大部分地方都没有区别，少数地方还需要时间来缩小其差异。我相信要跨越 OpenGL和D3D的鸿沟并非难事，只要付出少许努力就能完成，而这些努力都是可以复用的。一旦上层代码脱离了具体API，在维护和移植方面都会受益无 穷。<br /><br />在shading language语言方面，不同API的分歧较大。我的想法是做一个D3D1x bytecode到GLSL的编译器。这样就可以用HLSL来编程、用D3D的编译器进行编译，然后直接用于OpenGL。甚至用同样的方法可以把 compute shader的bytecode编译成OpenCL kernel。以后我会有文章来专门讨论这件事情。<br /></p><img src ="http://www.cppblog.com/topjackhjj/aggbug/157038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/topjackhjj/" target="_blank">翾</a> 2011-09-28 09:25 <a href="http://www.cppblog.com/topjackhjj/articles/157038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>粒子系统-烟花模拟</title><link>http://www.cppblog.com/topjackhjj/articles/87908.html</link><dc:creator>翾</dc:creator><author>翾</author><pubDate>Wed, 17 Jun 2009 13:48:00 GMT</pubDate><guid>http://www.cppblog.com/topjackhjj/articles/87908.html</guid><wfw:comment>http://www.cppblog.com/topjackhjj/comments/87908.html</wfw:comment><comments>http://www.cppblog.com/topjackhjj/articles/87908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/topjackhjj/comments/commentRss/87908.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/topjackhjj/services/trackbacks/87908.html</trackback:ping><description><![CDATA[闲来没事，写了个烟花程序，用 OPENGL 实现，发个图留念：<br /><br /><img alt="fireworks1" src="http://www.cppblog.com/images/cppblog_com/topjackhjj/10917/r_1.PNG" /><br /><br /><img alt="fireworks2" src="http://www.cppblog.com/images/cppblog_com/topjackhjj/10917/r_2.PNG" /><br /><br /><img alt="fireworks3" src="http://www.cppblog.com/images/cppblog_com/topjackhjj/10917/r_3.PNG" /><br /><br /><br /><br /><a href="/Files/topjackhjj/Firework.rar">演示程序与代码</a><img src ="http://www.cppblog.com/topjackhjj/aggbug/87908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/topjackhjj/" target="_blank">翾</a> 2009-06-17 21:48 <a href="http://www.cppblog.com/topjackhjj/articles/87908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>