﻿<?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++博客-gauss-文章分类-图形引擎</title><link>http://www.cppblog.com/gauss/category/18355.html</link><description>智者在人生中耗尽了生活，凡人在生活中度过人生。
</description><language>zh-cn</language><lastBuildDate>Mon, 26 Dec 2011 12:27:06 GMT</lastBuildDate><pubDate>Mon, 26 Dec 2011 12:27:06 GMT</pubDate><ttl>60</ttl><item><title>[转]D3d9c的固定渲染管道（fixed function pipeline）与可编程管道（programmable function pipeline）的异同点 </title><link>http://www.cppblog.com/gauss/articles/161922.html</link><dc:creator>gauss</dc:creator><author>gauss</author><pubDate>Sun, 11 Dec 2011 08:23:00 GMT</pubDate><guid>http://www.cppblog.com/gauss/articles/161922.html</guid><wfw:comment>http://www.cppblog.com/gauss/comments/161922.html</wfw:comment><comments>http://www.cppblog.com/gauss/articles/161922.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gauss/comments/commentRss/161922.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gauss/services/trackbacks/161922.html</trackback:ping><description><![CDATA[<div><p><span style="font-family: mceinline;">&nbsp;&nbsp;现在的游戏图形部分越来多依靠GPU来渲染绘制。说起GPU先说着色器，着色器是可编程的（programmable），分为顶点着色器和像素着色器。着色器是一段运行在GPU上的程序，可以取代渲染的固定功能流水线中部分功能。</span></p> <p><span style="font-family: mceinline;">&nbsp;在D3d9c可以用固定管道渲染（fixed function pipeline），也可以用可编程的管道（programmable&nbsp;function pipeline）渲染。下面大概总结下各自对</span><span style="font-family: Calibri;"><span style="font-family: mceinline;">vertex</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">的绘制流程。看看传统的渲染流程和利用可编程管道渲染的异同。</span></span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;固定管道。</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;先来看看初始化部分，前</span><span style="font-family: Calibri;"><span style="font-family: mceinline;">5</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">步基本是在构造函数中调用实现。</span></span></p> <p><span style="font-family: mceinline;">1:&nbsp;</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">定义其结构</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Struct{}</span></span></p> <p><span style="font-family: mceinline;">struct&nbsp;Vertex</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DXVECTOR3&nbsp;pos;</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DXVECTOR3&nbsp;normal0;</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DXVECTOR3&nbsp;normal1;</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DXVECTOR3&nbsp;normal2;</span></p> <p><span style="font-family: mceinline;">};</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">2:创建一组D3DVERTEXELEMENT9[]</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">结构的元素描述上面定义的</span></span><span style="font-family: 'Times New Roman';"><span style="font-family: mceinline;">Struct{}</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">，以在后面告诉</span></span><span style="font-family: 'Times New Roman';"><span style="font-family: mceinline;">Directx</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">我们定义什么样的顶点结构。</span></span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;D3DVERTEXELEMENT9&nbsp;decl[]&nbsp;=</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;{</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;{0,&nbsp;&nbsp;0,&nbsp;D3DDECLTYPE_FLOAT3,&nbsp;D3DDECLMETHOD_DEFAULT,&nbsp;D3DDECLUSAGE_POSITION,&nbsp;0},</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;{0,&nbsp;12,&nbsp;D3DDECLTYPE_FLOAT3,&nbsp;D3DDECLMETHOD_DEFAULT,&nbsp;D3DDECLUSAGE_NORMAL,&nbsp;&nbsp;&nbsp;0},</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;{0,&nbsp;24,&nbsp;D3DDECLTYPE_FLOAT3,&nbsp;D3DDECLMETHOD_DEFAULT,&nbsp;D3DDECLUSAGE_NORMAL,&nbsp;&nbsp;&nbsp;1},</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;{0,&nbsp;36,&nbsp;D3DDECLTYPE_FLOAT3,&nbsp;D3DDECLMETHOD_DEFAULT,&nbsp;D3DDECLUSAGE_NORMAL,&nbsp;&nbsp;&nbsp;2},</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;D3DDECL_END()</span></p> <p><span style="font-family: mceinline;">&#183;&nbsp;};</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">3</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">：创建了</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">D3DVERTEXELEMENT9[]</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">后，我们便可以获取指向类</span></span><span style="font-family: mceinline;">IDirect3DVertexDeclaration9的指针，其是用表示</span><span style="font-family: 'Times New Roman';"><span style="font-family: mceinline;">D3DVERTEXELEMENT9[]</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">结构的。我们通过下面的函数来依据</span></span><span style="font-family: 'Times New Roman';"><span style="font-family: mceinline;">D3DVERTEXELEMENT9[]</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">获取指向</span></span><span style="font-family: mceinline;">IDirect3DVertexDeclaration9的指针。</span></p> <p><span style="font-family: mceinline;">HRESULT&nbsp;IDirect3DDevice9::CreateVertexDeclaration(</span></p> <p><span style="font-family: mceinline;">CONST&nbsp;D3DVERTEXELEMENT9*&nbsp;pVertexElements,</span></p> <p><span style="font-family: mceinline;">IDirect3DVertexDeclaration9**&nbsp;ppDecl)</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">例如：</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;IDirect3DVertexDeclaration9*&nbsp;d3dVertexDecl&nbsp;=&nbsp;0;</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;CreateVertexDeclaration(decl,&nbsp;&amp;d3dVertexDecl));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">4:&nbsp;&nbsp;</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">接下来我们为我们的顶点和顶点序号申请一片内存的存储空间</span></span></p> <p><span style="font-family: mceinline;">HRESULT&nbsp;IDirect3DDevice9::CreateVertexBuffer(</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;Length,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;Usage,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;FVF,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DPOOL&nbsp;Pool</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;IDirectSDVertexBuffer9**&nbsp;ppVertexBuffer,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE*&nbsp;pSharedHandle);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">HRESULT&nbsp;IDirect3DDevice9::CreateIndexBuffer(</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;Length,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;Usage,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DFORMAT&nbsp;Format,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;D3DPOOL&nbsp;Pool,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;IDirectSDIndexBuffer9**&nbsp;ppIndexBuffer,</span></p> <p><span style="font-family: mceinline;">&nbsp;HANDLE*&nbsp;pSharedHandle);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">例如</span></p> <p><span style="font-family: mceinline;">IDirect3DVertexBuffer9*&nbsp;vb;</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;CreateVertexBuffer(&nbsp;8&nbsp;*&nbsp;sizeof(&nbsp;Vertex&nbsp;),&nbsp;0,&nbsp;0,D3DPOOL_MANAGED,&nbsp;&amp;vb,&nbsp;0);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">IDirect3DIndexBuffer9*&nbsp;ib;</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;CreateIndexBuffer(36&nbsp;*&nbsp;sizeof(&nbsp;WORD&nbsp;),D3DUSASE_DYNAMIC&nbsp;|&nbsp;D3DUSASE_WRITEONLY,&nbsp;D3DFMTJNDEX16,D3DPOOL_DEFAULT,&nbsp;&amp;ib,&nbsp;0);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">5&nbsp;&nbsp;</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">再接着获取指向上面申请到的内存（空白）的指针，以对这片区域进行写操作。</span></span></p> <p><span style="font-family: mceinline;">HRESULT&nbsp;IDirect3DVertexBuffer9::Lock(</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;UINT&nbsp;OffsetToLock,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;UINT&nbsp;SizeToLock,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;BYTE**&nbsp;ppbData,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;DWORD&nbsp;Flags);</span></p> <p>&nbsp;</p> <p><span style="font-family: mceinline;">HRESULT&nbsp;IDirect3DIndexBuffer9::Lock(</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;UINT&nbsp;OffsetToLock,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;UINT&nbsp;SizeToLock,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;BYTE**&nbsp;ppbData,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;DWORD&nbsp;Flags);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">例如</span></p> <p><span style="font-family: mceinline;">Vertex*&nbsp;vertices;</span></p> <p><span style="font-family: mceinline;">vb-&gt;Lock(0,&nbsp;0,&nbsp;(void**)&amp;vertices,&nbsp;0);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;lock&nbsp;the&nbsp;entire&nbsp;buffer</span></p> <p><span style="font-family: mceinline;">Vertices[0]&nbsp;=&nbsp;Vertex(-1.0f,&nbsp;0.0f,&nbsp;2.0f);&nbsp;//&nbsp;write&nbsp;vertices&nbsp;to&nbsp;</span></p> <p><span style="font-family: mceinline;">vertices[1]&nbsp;=&nbsp;Vertex(&nbsp;0.0f,&nbsp;1.0f,&nbsp;2.0f);&nbsp;//&nbsp;the&nbsp;buffer</span></p> <p><span style="font-family: mceinline;">vertices[2]&nbsp;=&nbsp;Vertex(&nbsp;1.0f,&nbsp;0.0f,&nbsp;2.0f);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">vb-&gt;Unlock();&nbsp;//&nbsp;unlock&nbsp;when&nbsp;you're&nbsp;done&nbsp;accessing&nbsp;the&nbsp;buffer</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面几步则是每次系统更新的时候在DrawScene()中调用。</span></p> <p><span style="font-family: mceinline;">6</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">：想调用</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Direct3D</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">的</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">draw**&nbsp;</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">函数了？</span></span><span style="font-family: mceinline;">快了。在之前，我们必须告诉</span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Direct3D</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">去哪里找到顶点和顶点序号的数据。</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Direct3D</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">的</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">draw**</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">系列函数是从顶点流</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">(vertex&nbsp;stream:</span></span><span style="font-family: mceinline;">a&nbsp;vertex&nbsp;stream&nbsp;is&nbsp;essentially&nbsp;an&nbsp;array&nbsp;of&nbsp;vertex&nbsp;component&nbsp;data)</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中获得顶点数据的。记得我们将我们的顶点放在</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">vertex&nbsp;buffer</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中，所以为了能够画</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">vertex&nbsp;buffer</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中的顶点，我们必须将</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">vertex&nbsp;buffer</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">与某个</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">vertex&nbsp;stream</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">联系上。这可以通过下面的函数实现</span></span></p> <p><span style="font-family: mceinline;">HRESULT&nbsp;IDirect3DDevice9::SetStreamSource(</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;UINT&nbsp;StreamNumber,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;IDirect3DVertexBuffer9*&nbsp;pStreamData,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;UINT&nbsp;OffsetInBytes,</span></p> <p><span style="font-family: mceinline;">UINT&nbsp;Stride);</span></p> <p><span style="font-family: mceinline;">例如，假定vb是指向一个已经用顶点类型为Vertex填好了的vertex&nbsp;buffer。那么我们可以通过下面的句子来将这段buffer与vertex&nbsp;stream联系起来。</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetStreamSource(0,&nbsp;vb,&nbsp;0,&nbsp;sizeof(Vertex)));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">7</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">：记得上面我们已经创建了顶点的</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Declaration</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">来描述我们定义的顶点结构。那么最后我们要做的就是在</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Direct3D</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中给这个顶点类型注册，正式告之</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">Direct3D</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">如何处理我们定义的顶点。例如</span></span></p> <p><span style="font-family: mceinline;">//&nbsp;d3dVertexDecl&nbsp;is&nbsp;a&nbsp;pointer&nbsp;to&nbsp;an&nbsp;IDirect3DVertexDeclaration9&nbsp;type</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetVertexDeclaration(d3dVertexDecl);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">8：最后我们就可以调用Draw**（）来绘制各种图案了。当遇到不同物体需要不同的顶点时，我们就需要重新调用SetStreamSource（）,SetVertexDelaration()等来告之Direct3D。例如下面：</span></p> <table border="0"> <tbody> <tr> <td valign="top" width="481"> <p><span style="font-family: mceinline;">//&nbsp;Object&nbsp;1&nbsp;uses&nbsp;its&nbsp;own&nbsp;vertex&nbsp;buffer,&nbsp;index&nbsp;buffer,&nbsp;and</span></p> <p><span style="font-family: mceinline;">//&nbsp;vertex&nbsp;declaration</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetStreamSource(&nbsp;0,&nbsp;vbl,&nbsp;0,&nbsp;sizeof(&nbsp;Vertexl&nbsp;)&nbsp;);</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetIndices(indexBufferl);</span></p> <p><span style="font-family: mceinline;">gdSdDevice-&gt;SetVertexDeclaration(decl1);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;DRAW&nbsp;OBJECT&nbsp;1&nbsp;HERE</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;DrawPrimitive(...);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Object&nbsp;2&nbsp;uses&nbsp;its&nbsp;own&nbsp;vertex&nbsp;buffer,&nbsp;index&nbsp;buffer,&nbsp;and</span></p> <p><span style="font-family: mceinline;">//&nbsp;vertex&nbsp;declaration</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetStreamSource(&nbsp;0,&nbsp;vb2,&nbsp;0,&nbsp;sizeof(&nbsp;Vertex2&nbsp;)&nbsp;);</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetIndices(indexBuffer2);</span></p> <p><span style="font-family: mceinline;">gdSdDevice-&gt;SetVertexDeclaration(decl2);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;DRAW&nbsp;OBJECT&nbsp;2&nbsp;HERE</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;DrawPrimitive(...);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Object&nbsp;3&nbsp;uses&nbsp;its&nbsp;own&nbsp;vertex&nbsp;buffer,&nbsp;index&nbsp;buffer,&nbsp;and</span></p> <p><span style="font-family: mceinline;">//&nbsp;vertex&nbsp;declaration</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetStreamSource(&nbsp;0,&nbsp;vb3,&nbsp;0,&nbsp;sizeof(&nbsp;Vertex3&nbsp;)&nbsp;);</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;SetIndices(indexBuffer3);</span></p> <p><span style="font-family: mceinline;">gdSdDevice-&gt;SetVertexDeclaration(decl3);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;DRAW&nbsp;OBJECT&nbsp;3&nbsp;HERE</span></p> <p><span style="font-family: mceinline;">gd3dDevice-&gt;DrawPrimitive(...);</span></p> </td> </tr> <tr> <td valign="middle" width="481"> <p><span style="font-family: mceinline;"><br /> </span></p> </td> </tr> </tbody> </table> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">可编程管道</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;可编程管道绘制顶点和固定管道大体上差不多。只是有三个主要的 不同点。1:编写HLSL程序，自己制定渲染形式&nbsp;。2：初始化时创建个与GPU交互的C++接口ID3DXEffect&nbsp;*，并利用 ID3DXEffect来对GPU做一些初始化工作，比如建立HLSL中变量与C++中相关变量的联系。3：在最后一步drawScene()中通过 ID3DXEffect&nbsp;*来调用HLSL的mhTech来进行绘制。</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">1：HLSL语言？好大的题目，具体自己找本教科书了。</span></p> <p><span style="font-family: mceinline;">下面直接贴代码举个简单例子。</span></p> <p><span style="font-family: mceinline;">uniform&nbsp;extern&nbsp;float4x4&nbsp;gWVP;</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">struct&nbsp;OutputVS</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;float4&nbsp;posH&nbsp;:&nbsp;POSITION0;</span></p> <p><span style="font-family: mceinline;">};</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">OutputVS&nbsp;TransformVS(float3&nbsp;posL&nbsp;:&nbsp;POSITION0)</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Zero&nbsp;out&nbsp;our&nbsp;output.</span></p> <p><span style="font-family: mceinline;">OutputVS&nbsp;outVS&nbsp;=&nbsp;(OutputVS)0;</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Transform&nbsp;to&nbsp;homogeneous&nbsp;clip&nbsp;space.</span></p> <p><span style="font-family: mceinline;">outVS.posH&nbsp;=&nbsp;mul(float4(posL,&nbsp;1.0f),&nbsp;gWVP);</span></p> <p>&nbsp;</p> <p><span style="font-family: mceinline;">//&nbsp;Done--return&nbsp;the&nbsp;output.</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;outVS;</span></p> <p><span style="font-family: mceinline;">}</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">float4&nbsp;TransformPS()&nbsp;:&nbsp;COLOR</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4(0.0f,&nbsp;0.0f,&nbsp;0.0f,&nbsp;1.0f);</span></p> <p><span style="font-family: mceinline;">}</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">technique&nbsp;TransformTech</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;pass&nbsp;P0</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;{</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Specify&nbsp;the&nbsp;vertex&nbsp;and&nbsp;pixel&nbsp;shader&nbsp;associated&nbsp;with&nbsp;this&nbsp;pass.</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vertexShader&nbsp;=&nbsp;compile&nbsp;vs_3_0&nbsp;TransformVS();</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixelShader&nbsp;&nbsp;=&nbsp;compile&nbsp;ps_3_0&nbsp;TransformPS();</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Specify&nbsp;the&nbsp;render/device&nbsp;states&nbsp;associated&nbsp;with&nbsp;this&nbsp;pass.</span></p> <p><span style="font-family: mceinline;">FillMode&nbsp;=&nbsp;Wireframe;</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;}</span></p> <p><span style="font-family: mceinline;">}</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">2：在d3d9的实例的构造函数或者初始化的时候，我们可以通过调用D3DXCreateEffectFromFile()函数来创建与GPU联系的C++指针D3DXEffect&nbsp;*。</span></p> <p><span style="font-family: mceinline;">HRESULT&nbsp;&nbsp;D3DXCreateEffectFromFile(</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;LPDIRECT3DDEVICE9&nbsp;pDevice,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;LPCSTR&nbsp;pSrcFile,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;CONST&nbsp;D3DXMACRO*&nbsp;pDefines,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;LPD3DXINCLUDE&nbsp;pInclude,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;Flags,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;LPD3DXEFFECTPOOL&nbsp;pPool,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;LPD3DXEFFECT*&nbsp;ppEffect,</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;LPD3DXBUFFER&nbsp;*ppCompilationErrors</span></p> <p><span style="font-family: mceinline;">);</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;我们可以通过</span><span style="font-family: Calibri;"><span style="font-family: mceinline;">ID3DXEffect&nbsp;*</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">来建立</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">C++</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">程序与</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">HLSL</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">程序的沟通桥梁。而这个桥梁就是变量</span></span><span style="font-family: mceinline;">D3DXHANDLE。</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;然后我们可以通过以下函数为</span><span style="font-family: Calibri;"><span style="font-family: mceinline;">HLSL</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">每个变量在</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">C++</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">层面创建一个对应变量，即对一个</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">HLSL</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">变量</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">X'</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">建立一个在</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">C++</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中的对应变量</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">D3DXHANDLE&nbsp;mX</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">。</span></span></p> <p><span style="font-family: mceinline;">D3DXHANDLE&nbsp;&nbsp;ID3DXEffect::GetParameterByName(  &nbsp;&nbsp;&nbsp;&nbsp;D3DXHANDLE&nbsp;hParent,&nbsp;//&nbsp;scope&nbsp;of&nbsp;variable&nbsp;-&nbsp;parent&nbsp;structure  &nbsp;&nbsp;&nbsp;&nbsp;LPCSTR&nbsp;pName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;name&nbsp;of&nbsp;variable );</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;然后通过下面这个系列的函数来设置</span><span style="font-family: Calibri;"><span style="font-family: mceinline;">HLSL</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中对应</span></span><span style="font-family: mceinline;">hParameter的变量的值。</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;ID3DXEffect::SetValue( &nbsp;&nbsp;&nbsp;&nbsp;D3DXHANDLE&nbsp;hParameter, &nbsp;&nbsp;&nbsp;&nbsp;LPCVOID&nbsp;pData, &nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;Bytes);</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;</span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;HLSL</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">与</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">C++</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">沟通的实例：</span></span></p> <p><span style="font-family: mceinline;">//&nbsp;1&nbsp;</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">：</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">C++</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中的变量</span></span></p> <p><span style="font-family: mceinline;">D3DXMATRIX&nbsp;M;</span></p> <p><span style="font-family: mceinline;">D3DXMatrixRotationY(&amp;M,&nbsp;D3DX_PI);</span></p> <p><span style="font-family: mceinline;">D3DXVECTOR4&nbsp;V(x,&nbsp;y,&nbsp;z,&nbsp;1.0f);</span></p> <p><span style="font-family: mceinline;">//&nbsp;2</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">：</span></span><span style="font-family: mceinline;">为HLSL</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中的变量创建对应的在</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">C++</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中的</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">D3DXHANDLE</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">系列的变量。</span></span><span style="font-family: mceinline;">&nbsp;(assume&nbsp;"mtx"&nbsp;and&nbsp;"vec"&nbsp;are&nbsp;parameters  //&nbsp;declared&nbsp;in&nbsp;.fx&nbsp;file).</span></p> <p><span style="font-family: mceinline;">D3DXHANDLE&nbsp;hMatrix&nbsp;=&nbsp;mFX-&gt;GetParameterByName(0,&nbsp;"mtx");</span></p> <p><span style="font-family: mceinline;">D3DXHANDLE&nbsp;hVec&nbsp;=&nbsp;mFX-&gt;GetParameterByName(0,&nbsp;"vec");</span></p> <p><span style="font-family: mceinline;">//&nbsp;3</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">：</span></span><span style="font-family: mceinline;">通过D3DXHANDLE把C++</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">中的值赋给</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">HLSL</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">。</span></span></p> <p><span style="font-family: mceinline;">mFX-&gt;SetMatrix(hMatrix,&nbsp;&amp;M);</span></p> <p><span style="font-family: mceinline;">mFX-&gt;SetVector(hVec,&nbsp;&amp;V);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;全部流程调用实例</span></p> <p><span style="font-family: mceinline;">void&nbsp;MeshDemo::buildFX()</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">//&nbsp;Create&nbsp;the&nbsp;FX&nbsp;from&nbsp;a&nbsp;.fx&nbsp;file.</span></p> <p><span style="font-family: mceinline;">ID3DXBuffer*&nbsp;errors&nbsp;=&nbsp;0;</span></p> <p><span style="font-family: mceinline;">HR(D3DXCreateEffectFromFile(gd3dDevice,&nbsp;"transform.fx",&nbsp;</span></p> <p><span style="font-family: mceinline;">0,&nbsp;0,&nbsp;D3DXSHADER_DEBUG,&nbsp;0,&nbsp;&amp;mFX,&nbsp;&amp;errors));</span></p> <p><span style="font-family: mceinline;">if(&nbsp;errors&nbsp;)</span></p> <p><span style="font-family: mceinline;">MessageBox(0,&nbsp;(char*)errors-&gt;GetBufferPointer(),&nbsp;0,&nbsp;0);</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Obtain&nbsp;handles.</span></p> <p><span style="font-family: mceinline;">mhTech&nbsp;=&nbsp;mFX-&gt;GetTechniqueByName("TransformTech");</span></p> <p><span style="font-family: mceinline;">mhWVP&nbsp;&nbsp;=&nbsp;mFX-&gt;GetParameterByName(0,&nbsp;"gWVP");</span></p> <p><span style="font-family: mceinline;">}</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;最后来比较下在固定管道下与在GPU</span><span style="font-family: 宋体;"><span style="font-family: mceinline;">可编程下的</span></span><span style="font-family: Calibri;"><span style="font-family: mceinline;">drawScene()</span></span><span style="font-family: 宋体;"><span style="font-family: mceinline;">函数（自己定义的在周期内调用所有绘图渲染相关函数）的不一样之处。注意黑色加粗的代码。</span></span></p> <p><span style="font-family: mceinline;">&nbsp;&nbsp;&nbsp;&nbsp;首先是固定的渲染管道：</span></p> <p><span style="font-family: mceinline;">void&nbsp;CubeDemo::drawScene()</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">//&nbsp;Clear&nbsp;the&nbsp;backbuffer&nbsp;and&nbsp;depth&nbsp;buffer.</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;Clear(0,&nbsp;0,&nbsp;D3DCLEAR_TARGET&nbsp;|&nbsp;D3DCLEAR_ZBUFFER,&nbsp;0xffffffff,&nbsp;1.0f,&nbsp;0));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;BeginScene());</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Let&nbsp;Direct3D&nbsp;know&nbsp;the&nbsp;vertex&nbsp;buffer,&nbsp;index&nbsp;buffer&nbsp;and&nbsp;vertex&nbsp;</span></p> <p><span style="font-family: mceinline;">//&nbsp;declaration&nbsp;we&nbsp;are&nbsp;using.</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetStreamSource(0,&nbsp;mVB,&nbsp;0,&nbsp;sizeof(VertexPos)));</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetIndices(mIB));</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetVertexDeclaration(VertexPos::Decl));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;World&nbsp;matrix&nbsp;is&nbsp;identity.</span></p> <p><span style="font-family: mceinline;">D3DXMATRIX&nbsp;W;</span></p> <p><span style="font-family: mceinline;">D3DXMatrixIdentity(&amp;W);</span></p> <p><strong><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetTransform(D3DTS_WORLD,&nbsp;&amp;W));</span></strong></p> <p><strong><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetTransform(D3DTS_VIEW,&nbsp;&amp;mView));</span></strong></p> <p><strong><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetTransform(D3DTS_PROJECTION,&nbsp;&amp;mProj));</span></strong></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><strong><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetRenderState(D3DRS_FILLMODE,&nbsp;D3DFILL_SOLID));</span></strong></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;DrawIndexedPrimitive(D3DPT_TRIANGLELIST,&nbsp;0,&nbsp;0,&nbsp;8,&nbsp;0,&nbsp;12));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">mGfxStats-&gt;display();</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;EndScene());</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Present&nbsp;the&nbsp;backbuffer.</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;Present(0,&nbsp;0,&nbsp;0,&nbsp;0));</span></p> <p><span style="font-family: mceinline;">}</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">再来是可编程管道</span></p> <p><span style="font-family: mceinline;">void&nbsp;MeshDemo::drawScene()</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><span style="font-family: mceinline;">//&nbsp;Clear&nbsp;the&nbsp;backbuffer&nbsp;and&nbsp;depth&nbsp;buffer.</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;Clear(0,&nbsp;0,&nbsp;D3DCLEAR_TARGET&nbsp;|&nbsp;D3DCLEAR_ZBUFFER,&nbsp;0xffffffff,&nbsp;1.0f,&nbsp;0));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;BeginScene());</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Let&nbsp;Direct3D&nbsp;know&nbsp;the&nbsp;vertex&nbsp;buffer,&nbsp;index&nbsp;buffer&nbsp;and&nbsp;vertex&nbsp;</span></p> <p><span style="font-family: mceinline;">//&nbsp;declaration&nbsp;we&nbsp;are&nbsp;using.</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetStreamSource(0,&nbsp;mVB,&nbsp;0,&nbsp;sizeof(VertexPos)));</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetIndices(mIB));</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;SetVertexDeclaration(VertexPos::Decl));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Setup&nbsp;the&nbsp;rendering&nbsp;FX</span></p> <p><strong><span style="font-family: mceinline;">HR(mFX-&gt;SetTechnique(mhTech));</span></strong></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Begin&nbsp;passes.</span></p> <p><span style="font-family: mceinline;">UINT&nbsp;numPasses&nbsp;=&nbsp;0;</span></p> <p><span style="font-family: mceinline;">HR(mFX-&gt;Begin(&amp;numPasses,&nbsp;0));</span></p> <p><span style="font-family: mceinline;">for(UINT&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;numPasses;&nbsp;++i)</span></p> <p><span style="font-family: mceinline;">{</span></p> <p><strong><span style="font-family: mceinline;">HR(mFX-&gt;BeginPass(i));</span></strong></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><strong><span style="font-family: mceinline;">HR(mFX-&gt;SetMatrix(mhWVP,&nbsp;&amp;(mView*mProj)));</span></strong></p> <p><strong><span style="font-family: mceinline;">HR(mFX-&gt;CommitChanges());</span></strong></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;DrawIndexedPrimitive(D3DPT_TRIANGLELIST,&nbsp;0,&nbsp;0,&nbsp;mNumGridVertices,&nbsp;0,&nbsp;mNumGridTriangles));</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><strong><span style="font-family: mceinline;">HR(mFX-&gt;EndPass());</span></strong></p> <p><span style="font-family: mceinline;">}</span></p> <p><strong><span style="font-family: mceinline;">HR(mFX-&gt;End());</span></strong></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">mGfxStats-&gt;display();</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;EndScene());</span></p> <p><span style="font-family: mceinline;"><br /> </span></p> <p><span style="font-family: mceinline;">//&nbsp;Present&nbsp;the&nbsp;backbuffer.</span></p> <p><span style="font-family: mceinline;">HR(gd3dDevice-&gt;Present(0,&nbsp;0,&nbsp;0,&nbsp;0));</span></p> <p><span style="font-family: mceinline;">}</span></p> <span style="font-family: mceinline;">转自http://blog.csdn.net/qiul12345/article/details/5937701</span></div><img src ="http://www.cppblog.com/gauss/aggbug/161922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gauss/" target="_blank">gauss</a> 2011-12-11 16:23 <a href="http://www.cppblog.com/gauss/articles/161922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]游戏引擎中的通用编程技术（一）</title><link>http://www.cppblog.com/gauss/articles/161921.html</link><dc:creator>gauss</dc:creator><author>gauss</author><pubDate>Sun, 11 Dec 2011 08:21:00 GMT</pubDate><guid>http://www.cppblog.com/gauss/articles/161921.html</guid><wfw:comment>http://www.cppblog.com/gauss/comments/161921.html</wfw:comment><comments>http://www.cppblog.com/gauss/articles/161921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gauss/comments/commentRss/161921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gauss/services/trackbacks/161921.html</trackback:ping><description><![CDATA[<div>http://dev.gameres.com/Program/Abstract/Design/PublicEngineDesign1.htm <p>你是否正在考虑构建一个游戏引擎呢？你对如何构建一个游戏引擎是否已经有了一个明确的计划呢？你是否已经对如何组织游戏引擎各个模块之间的关系有了 一个通盘的考虑？如果没有，那么本文将对你建立一个良好的游戏架构提出一些有益的方案，如果你已经对上面的问题有了一个明确的答案，那么本文不是你需要阅 读的内容。本文的目的是给那些没有任何建立完整游戏引擎经验的人提供一些入门性的知识，使他们初步了解一下如何来构建一个游戏引擎，构建游戏引擎应该注意 哪些方面的问题，并提供了一些成熟的设计模版并指出这些设计模版使用的范围，我希望这些内容对那些中级编程人员也有一个良好的参考作用。本文的内容来源于 一些流行的编程书籍，具体书目请见本文最后的部分，由于本文是介绍性质的文章，因此如果你对哪方面的内容非常感兴趣请参考相应的书籍，本文或许有很多错误 的地方，如果你有什么看法的话可以通过Email和我进行讨论，我的地址为dreams_wu@sina.com。</p> <br /> 　　这里必须再次提醒你，本文介绍的是一些通用的游戏编程技巧，虽然是通用但是可能并不是非常全面，可能存在这样或那样的缺陷，因此如果你希望它发挥最大 的效用必须恰当的使用它，而不是不分场合的滥用。切记切记，一个初学者最容易犯的错误就是任意使用一些设计模版而不顾它的使用范围。<br /> 在开始构建一个游戏引擎时你需要先考虑哪些方面的问题呢？这是你必须认真考虑的问题，我的答案是首先必须考虑代码的可读性，尤其是在多人进行开发时更必须 高度重视，如果你写的代码其他人需要花费非常大的精力进行阅读，那么根本谈不上提高工作效率，下面是提高代码可读性的一些良好建议：<br /> <br /> 1、建立一份简单明了的命名规则。一份良好的命名规则可以大幅提高代码的可读性，规则必须简单明了，通常只需要两三分钟的阅读应该可以让其他人掌握，例如 在代码中直接使用匈牙利命名法这种大家熟知的规则，使用字母I作为接口类的首字母，使用C开头作为实现类的首字母，使用g_开头的变量名作为全局变 量，s_开头作为静态变量名，m_开头作为内部变量名，使用_开头作为类内部使用的函数名等等，通过名字就可以使你大概了解对象的使用范围和基本功能。<br /> <br /> 2、不要讨厌写注释。一个编程者易犯的错误就是不写注释，认为它会增加自己的工作量，但是他没有考虑到相应的工作量已经转移到代码阅读者的身上，可能看代 码的人会花费比写注释时间两倍或者三倍的时间来阅读代码，这是一种非常不负责任的行为，通过一段简短的注释可以使阅读者迅速的了解代码的功能，从而把时间 更多的用到功能的扩展上。下面是一些良好的建议：尽量对每一个变量标明它的功能。对每一个函数声明的地方标明它的功能，对于复杂的函数还应当写清参数和返 回值的作用，注意是在声明函数的头文件中。在关键的代码处写清它的作用，尤其是在进行复杂的运算时更应如此。在每一个类声明的地方简要的介绍它的功能。<br /> <br /> 3、减少类的继承层次。通常对于游戏编程来说每一个类的继承层次最好不要超过4层，因为过多的继承不仅会减少代码的可读性，同时使类表指针变长，代码体积 增大，减低类的执行效率。还要注意要减少多重继承，因为不小心它会形成编程者非常讨厌的&#8220;钻石&#8221;形状。同时还要注意如果能使用类的组合的话那么就尽量减少 使用类的继承，当然这是设计技巧的问题。<br /> <br /> 4、减少每行代码的长度。尽量不要在一行代码中完成一个复杂的运算，这样做会增加阅读难度，同时不符合现代CPU的执行，由于CPU现在都使用了超长流水 线的设计，它非常适合执行那些每行代码非常短而行数非常多的代码，例如对一个复杂的数学运算，写成一行不如每一步骤写一行。<br /> <br /> 　　以上建议是我的一些粗略看法，如果你还有什么好的看法可以给我指出来，同时上面的建议并不是绝对的，例如类的继承并不是绝对不能超过4层，如果你需要的话可以使用更多的继承，前提是这样带来的好处大于代码执行效率的损失。<br /> <br /> 　　接着看看要考虑什么，在Game Programming  Gems3的《一个基于对象组合的游戏架构》一文指出了几个值得考虑的问题，首先是平台相关性与独立性和游戏相关性与独立性的问题，也就是说应当作到引擎 的架构与平台和游戏都无关。为什么要做到与平台无关性呢？这是因为你必须在开始架构引擎考虑它的可移植性，如果在开始你没有注意到这个问题，那么一旦在游 戏完成后需要移植到其他的游戏平台上，你会发现麻烦大了，你需要修改的地方实在是太多了，所有与平台相关的API调用都需要修改，所有使用了平台特定功能 的模块也需要修改，这是一个非常耗费精力的事情，可能需要花费和开发一个游戏一样的时间，而如果你在开始的时候就考虑到这个问题，那么非常简单，只需要写 一个相应平台的模块替换掉原来的模块即可，这样精力就可以放在如何充分的利用特定平台的能力来提高游戏的表现力上，而不是代码修改上。下面简单的谈一下如 何使引擎作到与平台无关。<br /> <br /> 1、注意操作系统的差异。现在主流的操作系统主要是Windows和Linux两种，当然还有Unix和Mac，在编程时你必须注意这一点，当你需要包含Windows的头文件时，你必须将它包含在宏_WIN32中，下面是一个简单的例子：<br /> <br /> #ifdef _WIN32<br /> #include "windows.h"<br /> #endif<br /> <br /> 而你使用Windows平台特定的API时也应当如此，这样在其他平台上编译时可以保证Windows平台相应的代码不会被编译进去。对于其他平台也应当如此。<br /> <br /> 2、注意编译器的差异。现在通用的编译器主要有VC，BC和gcc几种，在进行Windows平台编程时，你通常会使用VC或BC，而对Linux平台编 程时通常使用gcc，使用VC编译器你不可能编译出用于Linux平台的代码，因此在编程时也需要注意，你可以使用上面的方法通过特定的宏来将不同的编译 器分离开。举一个简单的例子：<br /> <br /> #ifdef _WIN32<br /> #ifdef _MSC_VER<br /> typedef signed __int64 int64;<br /> #endif<br /> #elif defined _LINUX<br /> typedef long long int64;<br /> #endif<br /> <br /> 在不同的编译器中对64位变量的命名是不同的，因为它并不是C++标准的一部分，而是编译器的扩展部分。另外一个例子是编译器使用的内联汇编代码，在VC中你可以使用_asm来指明，而对于Linux平台的编译器你需要使用它的专用关键字了。<br /> <br /> 3、注意CPU的差异。对于不同平台来说它通常会使用不同的CPU，不过幸好Windows和Linux都支持X86的CPU，这也是PC游戏的主流 CPU平台，而XBOX使用的也是X86的CPU，除非你需要移植到PS2平台，否则这将大大减轻你的编程负担，在X86平台上提供了一个cpuid的指 令可以非常方便的检查CPU的特性，如是否支持MMX，SSE，SSE2，3DNow!技术等，通过它你可以使用特定的CPU特性来加速你的代码执行速 度。<br /> <br /> 4、注意图形API的差异。现在图形API主要存在两种主流的平台DirectX和OpenGL，DirectX只能用于Windows平台，而 OpenGL几乎被所有的平台所支持。因此你需要为不同的图形API进行封装，将它做成不同的模块，在需要的时候进行切换。完成这个工作最好的方法是使用 后面介绍的类厂模式。<br /> <br /> 5、注意显卡的差异。现在显卡有两大主流ATI和NV，虽然显卡可以被主流的操作系统所支持，但是必须注意在不同的游戏平台上还是使用不同的GPU，而在GPU之间也相应有自己的功能扩展，因此在使用特定的扩展功能时必须检查一下是否被显卡所支持。<br /> <br /> 6、注意shader语言的差异。可编程图形语言的出现是最重要的一项发明，现在几乎每一个游戏都在使用这项技术，而正由于它的重要性现在出现了多个标 准，HLSL只能用于DX中，而OpenGL由于标准的开放性更加混乱，每一个显卡厂商都根据自己的产品推出相应的扩展指令来实现shader，而NV更 推出了GC可以同时适用于DirectX和OpenGL，这是一个非常好的想法，不过由于这不是一个开放的标准因此没有得到其他厂商的支持，在ATI显卡 上运行GC代码你会发现比在NV显卡慢了几个数量级，由于上面的情况你需要根据不同的平台相应进行封装，方法和第4条一样。下面的建议值得你去考虑，当你 使用DirectX平台时应当使用HLSL，而对于OpenGL可以封装为两个模块，根据显卡的不同进行切换，也可以使用GC特别为NV的显卡封装一个模 块来对它进行优化。<br /> <br /> 　　这里需要补充一点，如果可以的话尽量和OGRE一样为不同的操作系统进行封装，这样方便在不同的系统之间进行切换。<br /> <br /> 　　接着看看如何实现游戏无关性，通常游戏引擎如果要实现游戏的无关性是非常困难的，这也就是说要求你的引擎适合所有的游戏类型，这太难了，考虑一下一个 RPG游戏引擎如果用来做一个RTS游戏那简直是不可能，类似的你不可能拿Q3引擎来做RTS游戏，但是如果引擎设计的非常良好的话还是可以实现部分的游 戏无关性。也就是说你可以将引擎的一部分模块设计成通用的模块，这样在开发其他类型的游戏时可以重用这部分的代码，这部分代码包括底层显示，声音，网络， 输入等部分，在设计它们时你必须保证它们具有良好的通用性。<br /> <br /> 　　在这些问题之后你应当考虑程序的国际化问题。这也是非常重要的方面，因为你的游戏可能在其它国家发行，这主要是注意语言方面的问题，尤其是字符串的处 理，在C++的标准库中提供了一个String容器，它提供了对国际化的良好支持，因此在引擎中你需要从头到尾的使用它。<br /> <br /> 　　接下来我们看看本文最重要的内容，如何组织一个引擎的架构。这是引擎最重要的部分，为什么重要呢？如果我们把引擎看作一间房子的话，那么架构可以看作 是房子的框架，当你完成这个框架后就可以向框架内添砖加瓦盖房子了。下面让我们来看看如何构建这个框架，通常一个大型的软件工程是按照模块化的方式来构建 的，编程之前要进行必要的需求分析，将软件工程根据不同的功能划分为几个较大的功能模块，对比较复杂的模块你可能还需要将它分为几个子模块，并需要给出各 个模块之间的逻辑关系。当你编写一个引擎时也需要进行相应的功能分析，让我们看看如何来划分引擎的功能模块，如果按照上面的游戏无关性和相关性进行分析的 话我们可以发现它可以分为游戏相关层和无关层两层，游戏相关层由于包含了游戏的逻辑性代码也被称为逻辑层。逻辑层应该位于引擎的最顶层，如果你在开发一个 局域网或在线游戏的话，按照网络程序的C/S开发模式，这一层应该分为两个模块，服务器和客户端模块,它包含了和特定游戏相关的所有功能，如AI，游戏角 色，游戏事件管理，网络管理等等。在它下面就是游戏无关层了，包括了引擎核心模块，GUI模块，文件系统管理模块等等，其中引擎的核心模块是最重要的部 分，逻辑层主要通过它来和底层的模块打交道，它应该包含场景管理，特效管理，控制台管理，图形处理等等内容。在向下就是一些底层模块了，如图形渲染模块， 输入设备模块，声音模块，网络模块，物理模块，角色模型模块等等，所有的这些底层模块必须通过核心模块来和逻辑层进行交互，因此核心模块是整个引擎的枢 纽，所有的模块都通过它来进行交互。<br /> <br /> 下面看看应该如何来进行模块的设计，这里有一些通用的规则是你应当遵守的：<br /> <br /> 1、减少模块之间的关系复杂度。我们知道通常每一个模块内部都存在大量的对象需要在各个模块之间进行相互的调用，如果我们假设每一个模块内部对象的数量为 N的话，那么每两个模块之间的关系复杂度为N*N，这样的复杂度是不可接受的，为什么呢？首先是它非常不利于管理，由于各个模块都存在大量的全局对象，并 存在相互依存的关系，并且各自建立的时间各不相同，这就存在初始化顺序的矛盾，考虑这种情况，一个模块中存在一个对象需要另外一个模块中的对象才能进行初 始化，当这个对象进行初始化时而另外的对象在之前并没有初始化就会引发程序的崩溃。其次，不利于多人进行同时的开发，由于各个模块存在相互依存的关系，当 复杂度非常高时就会出现模块与模块的高度依存，也就是说一个模块没有完成下一个模块就无法完成，因此就需要一个模块一个模块按照它的依存关系进行编程，而 无法同步进行。因此在设计模块时的第一件事情是减少模块之间的复杂度，为此你在设计模块时必须为模块设计一个交互接口，并约定所有模块之间的交互必须通过 这个接口来进行，这样模块之间的关系复杂度就降低为1*1了，非常方便管理，同<br /> 时这非常利于多人之间进行开发，假如每个人负责一个模块的开发的话，那么你只需要先完成这个接口类，其他人就可以利用这个接口进行其他模块的开发，而不必等到你完成所有的类再进行，这样所有的模块都是同步进行，可以节省大量宝贵的开发时间。<br /> <br /> 2、对类的抽象接口而不是类的实现编程。这是《Design  Patten》一书作者对所有软件编程者的建议，它也对游戏编程有很大的指导意义。对模块中所有被其它模块使用的类都要建立一个抽象接口，其它模块要使用 这个抽象接口进行编程，这样其它模块就可以在不需要知道类是如何实现的情况下进行编程。这样做的好处是在接口不改变的情况下任意对类的实现进行改变而不必 通知其它人，这对多人开发非常有用。<br /> <br /> 3、根据调用对象的不同对类进行分层。实际上本条还是对第2条的补充，分层还是为了更好隐藏底层的实现。通常一个类不仅被其它模块使用还要被自身模块所调 用，而且它们需要的功能也不同，因此我们可以让一个类对外部显现一个接口而对内部也显现一个接口，这样做的好处和上面一样，因为一个复杂的模块也是多人在 进行编程的。<br /> <br /> 4、通过让一个类对外显现多个接口来减少类的数量。减少关系复杂度的一个方法是减少类的数量，因此我们可以把完成不同功能的类合并成一个类，并让它对外表现为多个接口，也就是一个类的实现可以继承多个接口。<br /> <br /> 上面的建议只是起到参考作用，具体实现时你应该根据情况灵活使用，而不是任意乱用。<br /> <br /> 　　下面的内容涉及到具体的编程技巧，对于引擎中的全局对象你可以使用Singleton，如果你不了解它是什么可以阅读《Design Patten》，里面有对它的详细介绍，具体的使用可以通过OGRE引擎获得。<br /> <br /> 　　调用模块内的对象可以通过类厂来实现。COM可以看作是一种典型的类厂，DX就是使用它来进行设计的，而著名的开源引擎Crystle  Space也是通过建立一个类似的COM物体来实现的，但是我并不对它很认可，首先构建一个类似COM的类厂非常复杂，开销有点大，其次COM的一个优点 是可以对程<br /> 序实现向下兼容，这也是DX使用它的重要原因，而一个游戏引擎并不需要。OGRE中也实现了一个类厂结构，这是一个比较通用的类厂，但是使用起来还是需要 写一段代码。我比较欣赏VALVE的做法，它通过使用一个宏就解决了这个问题，非常高效，使用起来也非常方便。这个做法很简单，它把每个<br /> 模块中需要对外暴露的接口都连接到一个内部维护的链表上，每一个接口都和一个接口名相连，这样外部模块可以通过传入一个接口名给CreateInterface函数就可以获得这个接口的指针了，非常简单。下面看看它的具体实现。它内部保存的链表结构如下：<br /> <br /> class InterfaceReg<br /> {<br /> public:<br /> &nbsp;&nbsp;&nbsp; InterfaceReg( InstantiateInterfaceFn fn , const char *pName );<br /> <br /> public:<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>InstantiateInterfaceFn m_CreateFn;<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>const char *m_pName;<br /> <br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>InterfaceReg *m_pNext;<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>static InterfaceReg *s_pInterfaceRegs;<br /> };<br /> <br /> 并定义了两个函数指针和一个函数<br /> <br /> #define CREATEINTERFACE_PROCNAME "CreateInterface"<br /> typedef void *(CreateInterfaceFn)( const char *pName , int *pReturnCode );<br /> <br /> typedef void *(InstantiateInterfaceFn)( void );<br /> DLL_EXPORT void *CreateInterface( const char *pName , int *pReturnCode );<br /> <br /> 下面看看它如何通过宏来建立链表<br /> <br /> #define EXPOSE_INTERFACE( className , interfaceName , versionName ) \<br /> static void *__Create##className##_Interface() { return (interfaceName*) new className; } \<br /> static InterfaceReg __g_Create##interfaceName##_Reg( __Create_##className##_Interface , versionName );<br /> <br /> 如果你有一个类CPlayer它想对外暴露接口IPlayer，那么很简单，可以这么做<br /> <br /> #define PLAYER_VERSION_NAME "IPlayer001"<br /> EXPOSE_INTERFACE( CPlayer , IPlayer , PALYER_VERSION_NAME );<br /> <br /> 如果在其他模块内你需要获得这个接口，可以这么做<br /> <br /> CreateInterfaceFn factory = reinterpret_cast&lt;CreateInterfaceFn&gt; (GetProcAddress( hDLL , CREATEINTERFACE_PROCNAME ));<br /> IPlayer player = factory( PLAYER_VERSION_NAME , 0 );<br /> <br /> 其中hDLL为模块的句柄。这里函数指针factory实际指向模块内部的CreateInterface函数，这个函数通过比较传入的接口名从链表找到指定类指针。<br /> <br /> 　　解决了类厂问题，下面让我们看看如何建立模块对外的接口，在Game Programming  Gems3的《一个基于对象组合的游戏架构》一文提出了一种架构，Half  Life2引擎中对这种架构进行了有效的扩展，你可以让所有的对外暴露的接口都使用这个架构，前提是模块只有一个接口对外暴露。<br /> <br /> class IAppSystem<br /> {<br /> public:<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>// Here's where the app systems get to learn about each other<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>virtual bool Connect( CreateInterfaceFn factory ) = 0;<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>virtual void Disconnect() = 0;<br /> <br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>// Here's where systems can access other interfaces implemented by this object<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>// Returns NULL if it doesn't implement the requested interface<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>virtual void *QueryInterface( const char *pInterfaceName ) = 0;<br /> <br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>// Init, shutdown<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>virtual InitReturnVal_t Init() = 0;<br /> <span style="font-family: Arial;">&nbsp;&nbsp;&nbsp;</span>virtual void Shutdown() = 0;<br /> };<br /> <br /> 　　通过Connect方法你可以将两个模块建立一个连接关系，通过QueryInterface方法你可以检索到其他需要暴露接口，这种方法很好的为所 有的模块建立一个标准的对外接口，极大的减轻了编程的复杂性，遗憾的是在HL2引擎中只有部分模块使用了这个方法，可能是这个接口引入时间太晚的缘故</div><img src ="http://www.cppblog.com/gauss/aggbug/161921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gauss/" target="_blank">gauss</a> 2011-12-11 16:21 <a href="http://www.cppblog.com/gauss/articles/161921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>