﻿<?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++博客-Render Donkey-随笔分类-GPU and Graphic</title><link>http://www.cppblog.com/Leaf/category/13352.html</link><description>~~</description><language>zh-cn</language><lastBuildDate>Fri, 14 Jun 2013 21:23:59 GMT</lastBuildDate><pubDate>Fri, 14 Jun 2013 21:23:59 GMT</pubDate><ttl>60</ttl><item><title>镜面反射矩阵推导</title><link>http://www.cppblog.com/Leaf/archive/2013/06/15/201017.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 14 Jun 2013 16:48:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2013/06/15/201017.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/201017.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2013/06/15/201017.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/201017.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/201017.html</trackback:ping><description><![CDATA[<p>最近公司游戏正在准备上线，所以FlasCC也就没有研究了，偶尔有闲功夫，也是玩玩3DMAX和UNITY3D。 感觉不会3DMAX，是一种局限。</p> <p>回到主题，记录一下镜面反射矩阵的推导。</p> <p>在用Irrlicht和RTT做镜面效果的时候，用到了反射矩阵。 就是需要把摄相机镜像，渲染一个RT，贴到镜面模型上。这个其实还纠结了许久，因为之前做水面渲染的时候，水面是平的，很好计算摄相机在水面以下的位置。 但是换成镜面，就不一样了，因为镜面可能是任意面。 于是就需要一个通用的反射矩阵。</p> <p>反射矩阵的计算是基于平面的，因为，任何反射，都需要一个反射面。</p> <p>所以，我们先给出平面表示 Plane(nx,ny,nz,d); 其中(nx,ny,nz)已经单位化。</p> <p>然后，我们假设空间中有任意一点P(x,y,z,1)</p> <p>设这个点P以Plane为反射面的镜像点为P1(x1,y1,z1,w)。</p> <p>&nbsp;</p> <p>－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－</p> <p>根据定理，我们知道， 若两个点以某一点为镜像，则两个点的坐标之和除以2，就刚好是中点。 </p> <p>这个理论我们用到这里的话， 那这个中点就刚好是平面上的一个点。 平面上的这个点就是 P(x,y,z,1) - (nx,ny,nz,0)*D .&nbsp; 其中D就是点P到平面的距离</p> <p>而D=Plane dot P = (x*nx+y*ny+z*nz+d);</p> <p>由上面的描述，我们马上想到，那么要求点P1的话，就是这样&nbsp; </p> <p>(P+P1)/2 = P(x,y,z,1) - (nx,ny,nz,0)*D</p> <p>=&gt; P1 = P(x,y,z,1) - 2(nx,ny,nz,0)*D</p> <p>=&gt;P1 = P(x,y,z,1) - 2(nx,ny,nz,0)*(x*nx+y*ny+z*nz+d)</p> <p>&nbsp;</p> <p>换成矩阵形式则为</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ｜1-2*nx*nx&nbsp;&nbsp; -2*nx*ny&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -2*nx*nz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; |</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | -2*ny*nx&nbsp;&nbsp;&nbsp;&nbsp; 1 - 2*ny*ny&nbsp;&nbsp;&nbsp;&nbsp; -2*ny*nz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; |</p> <p>P1 = {x,y,z,1}&nbsp;&nbsp; x&nbsp;&nbsp; | -2*nz*nx&nbsp;&nbsp;&nbsp;&nbsp; -2*nz*ny&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1-2*nz*nz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; |</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | -2*d*nx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -2*d*ny&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -2*d*nz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; |</p> <p>&nbsp;</p> <p>大功告成</p> <p>btw:这是行主矩阵表示法</p> <img src ="http://www.cppblog.com/Leaf/aggbug/201017.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2013-06-15 00:48 <a href="http://www.cppblog.com/Leaf/archive/2013/06/15/201017.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Deferred Shading</title><link>http://www.cppblog.com/Leaf/archive/2011/03/13/141705.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Sun, 13 Mar 2011 03:56:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2011/03/13/141705.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/141705.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2011/03/13/141705.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/141705.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/141705.html</trackback:ping><description><![CDATA[<p>一直在关注这个东西，最近忙里偷闲，深入地了解了一下。 首先，我们说说延迟渲染的好处。毕竟一个东西的产生，是为了解决当前已有的东西不能解决的问题。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb.png" width="777" height="358"></a> </p> <p><a href="http://files.cnblogs.com/GameRambler/Deferred_Shading_Tutorial_SBGAMES2005.pdf">Deferred Shading Tutorial下载</a></p> <p>&nbsp;</p> <p>上面的文章很好地讨论了采用传统着色方案所需要面对的问题。主要是下面两种情况。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_1.png" width="780" height="381"></a> </p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_6.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_2.png" width="779" height="399"></a> </p> <p>&nbsp;</p> <p>而对于延迟着色的第一个好处，就是可以将光照处理对物体渲染的开销由 M*N 变为 M+N （其中M为物体数目，N为光源数目）</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_8.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_3.png" width="780" height="111"></a> </p> <p>&nbsp;</p> <p>延迟着色的一般框架图如下：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_10.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_4.png" width="782" height="355"></a> </p> <p>&nbsp;</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_12.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_5.png" width="784" height="442"></a> </p> <p></p> <p></p> <p></p> <p></p> <p></p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_14.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_6.png" width="784" height="329"></a> </p> <p>&nbsp;</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_16.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_7.png" width="780" height="469"></a> </p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_18.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_8.png" width="780" height="462"></a> </p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_20.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_9.png" width="778" height="384"></a> </p> <p>&nbsp;</p> <p>延迟着色的好处</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_24.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_11.png" width="778" height="446"></a> </p> <p>&nbsp;</p> <p>而延迟着色面临的最大问题就是透明处理</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_22.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_10.png" width="777" height="152"></a></p> <p>&nbsp;</p> <p>另外，延迟着色主要得益于MRT（Multi Render Target).因为，MRT的限制即是延迟着色本身的限制，DX SDK DOC中有提到。</p> <p>MSDN：<a title="http://msdn.microsoft.com/en-us/library/bb147221(v=vs.85).aspx" href="http://msdn.microsoft.com/en-us/library/bb147221(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/bb147221(v=vs.85).aspx</a></p> <p>&nbsp;</p> <p>RenderMonkey中也有延迟着色例子。　我也用RenderMonkey重写了一个自己的例子。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_26.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/DeferredShading_A6EF/image_thumb_12.png" width="767" height="461"></a>&nbsp;</p> <p></p> <p>OK, 完事儿！！！！</p><img src ="http://www.cppblog.com/Leaf/aggbug/141705.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2011-03-13 11:56 <a href="http://www.cppblog.com/Leaf/archive/2011/03/13/141705.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>2D Skinned Mesh（3D的完全翻版 带旋转）</title><link>http://www.cppblog.com/Leaf/archive/2011/01/14/138493.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Thu, 13 Jan 2011 16:24:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2011/01/14/138493.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/138493.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2011/01/14/138493.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/138493.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/138493.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 由下面几个文章引发的欲望，让我自己也试着实现了一个基于2D的骨骼动画。<br><br> <br><br>一篇讲述骨骼动画数学运算的文章<br><br>http://www.cnblogs.com/neoragex2002/archive/2007/09/13/891945.html<br><br> <br><br>两篇讲述骨骼动画原理和实现的文章　一篇也是用的2D，老外的那篇用的是DX　<br><br>http://www.cppblog.com/Leaf/archive/2010/12/31/137818.html<br><br> <br><br>空明流转用C#写的一个，当然也可以下载源码。只是在他的BLOG中，他未解释任何东西。并且我也未曾下载任何源码，不知是否源码中有文档<br><br>http://www.cppblog.com/lingjingqiu/archive/2008/06/07/52463.aspx<br><br> <br><br>很不爽的是，许多例子或原理讲的时候没有带旋转。　其实那才是重头戏。　空明流转的貌似有旋转，可&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2011/01/14/138493.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/138493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2011-01-14 00:24 <a href="http://www.cppblog.com/Leaf/archive/2011/01/14/138493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Reflect &amp;amp; Refract (以水渲染为例)</title><link>http://www.cppblog.com/Leaf/archive/2011/01/08/138172.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Sat, 08 Jan 2011 14:35:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2011/01/08/138172.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/138172.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2011/01/08/138172.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/138172.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/138172.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:  <br><br>我不是Shader帝，虽然知道Shader怎么写，但一直没仔细研究过。最近蛋疼至极，研究了下RenderMonkey，于是抽着几个看着比较有趣的效果做了一下。<br><br> <br><br>先前的模型贴花http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html<br><br>和CUBE MAP http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html<br><br>就是此次蛋疼期的产物之一。<br><br> <br><br>还是先围观，上图再说<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2011/01/08/138172.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/138172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2011-01-08 22:35 <a href="http://www.cppblog.com/Leaf/archive/2011/01/08/138172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CubeMap视线反射方向计算详解</title><link>http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 07 Jan 2011 05:32:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/138106.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/138106.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/138106.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 其基本原理很多例子上有讲到。下面给出一些比较合适的链接<br><br>http://developer.nvidia.com/object/cube_map_ogl_tutorial.html    NVIDIA官网上的 Opengl Cube texture mapping<br>http://www.zwqxin.com/archives/shaderglsl/review-cube-mapping-shader.html  某位兄弟的个人BLOG。<br>以上两位都适合OPENGL控。<br>本文给出一个DX HLSL例子。并解释了反射方向计算的数学模型。希望能给大家一定的帮助。<br><br>CUBE映射主要分为两步：<br>一、在VS中根据法线和观察位置计算反射方向，并且得到观察空间中的反射方向。<br>反射方向有两种计算方法。<br>1、在世界坐标系空间中计算，然后再将计算到的反射方向转换到观察空间。 这要求我们转入观察位置。<br>2、在观察空间中进行计算，此时观察位置已经为0,0,0,于是不需要传入观察位置，并且得到的向量即为所求。本文的代码采用此&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/138106.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2011-01-07 13:32 <a href="http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用投影纹理进行模型贴花(Mesh Decals)</title><link>http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Thu, 06 Jan 2011 16:37:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/138093.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/138093.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/138093.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、投影纹理进行模型贴花时，主要是进行三角面剔除，使在渲染贴花时，提交最少的三角面。<br><br>二、在贴花PASS中，需要将全局混合开启，并设置相应的SRCBLEND(SRC_ALPHA)和DESTBLEND(DEST_ALPHA)值。括号内为我用的值。<br><br>当然，如果你不想让贴花与场景（模型）混合，则可以不开启。　<br><br>三、请注意纹理的寻址方式以及纹理边缘的ALPHA情况。　若纹理边缘ALPHA不为0，则可以手工进行裁剪。<br><br>四、本文仅是采用了固定的投影方向和SHADER内部定义变量的方式来进行贴花渲染。　并且，并未进行模型三角面剔除。所以若要使用，则需要注意第一个问题。<br><br>五、本文灵感来源于此贴：http://forums.create.msdn.com/forums/p/34339/198791.aspx<br><br>六、支持邮件交流:BoYueGame#Gmail#com<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/138093.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2011-01-07 00:37 <a href="http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>两篇讲述Skinned Mesh原理的文章</title><link>http://www.cppblog.com/Leaf/archive/2010/12/31/137818.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 31 Dec 2010 15:04:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/12/31/137818.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/137818.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/12/31/137818.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/137818.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/137818.html</trackback:ping><description><![CDATA[<p>个人觉得，对于一个东西，理解其根本才是王道。</p>
<p>就拿骨骼动画来说吧，DX的例子虽然可以让人清楚地知道骨骼动画是怎么动作的，并且知道了有.X这种骨骼动画文件。　但着手时，依然会被DX那神奇的各种框架弄得晕头转向。　并且M$向来是想人变成213，而非学者。　</p>
<p>&nbsp;</p>
<p>在网上一搜Skinned Mesh, 会出来一大堆围绕着DX例子的解释，翻译，或者什么什么的。　而下面这些文章，则充分讲述了其基本原理。　你可以离开DX，离开OPENGL而全神惯注地集中思考骨骼动画到底是什么。　</p>
<p>&nbsp;</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/SkinnedMesh_14379/image_2.png"><img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=image border=0 alt=image src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/SkinnedMesh_14379/image_thumb.png" width=439 height=283></a> </p>
<p>Skinned Mesh原理解析和一个最简单的实现示例　<a title=http://blog.csdn.net/n5/archive/2008/10/19/3105872.aspx href="http://blog.csdn.net/n5/archive/2008/10/19/3105872.aspx">http://blog.csdn.net/n5/archive/2008/10/19/3105872.aspx</a></p>
<p>这是一篇中文，虽然是前两年发表的了，但依然适用。文中作者以文+代码的方式循序渐进，并在最后详解了其DEMO的实现代码。　可以说是真枪实弹的演习，而非空谈。</p>
<p>&nbsp;</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/SkinnedMesh_14379/image_4.png"><img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=image border=0 alt=image src="http://www.cppblog.com/images/cppblog_com/Leaf/WindowsLiveWriter/SkinnedMesh_14379/image_thumb_1.png" width=444 height=202></a> </p>
<p>Skined Mesh With DX9.pdf&nbsp; <a href="http://www.google.com/">www.google.com</a>&nbsp;&nbsp;&nbsp; <a href="http://www.baidu.com/">www.baidu.com</a><br>也可以点击<a style="COLOR: red" href="http://files.cppblog.com/Leaf/Skined%20Mesh%20With%20DX9.rar">这里下载</a><br></p>
<p>这是一篇老外的，也是由上一篇文章中提到的。　搜索引擎上随便一搜就能下到。　挺厚的，足足36页的PDF。　够你消耗一段时间的光阴了。</p>
<img src ="http://www.cppblog.com/Leaf/aggbug/137818.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-12-31 23:04 <a href="http://www.cppblog.com/Leaf/archive/2010/12/31/137818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HLSL中的MUL指令深层剖析</title><link>http://www.cppblog.com/Leaf/archive/2010/12/28/137588.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Mon, 27 Dec 2010 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/12/28/137588.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/137588.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/12/28/137588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/137588.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/137588.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文主要内容有： <br><br>一、部分背景内容 <br><br>二、HLSL中的row-major matrix picking and column-major matrix picking <br><br>三、MUL规则 <br><br>四、观察矩阵的另类解释和TBN空间的类推 <br><br>五、HLSL中矩阵的构造（为什么WorldToTargentSpaceMatrix要左乘LightDir） <br><br>  <br><br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/12/28/137588.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/137588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-12-28 00:05 <a href="http://www.cppblog.com/Leaf/archive/2010/12/28/137588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序中的四元数表示法</title><link>http://www.cppblog.com/Leaf/archive/2010/12/20/137079.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Mon, 20 Dec 2010 15:22:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/12/20/137079.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/137079.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/12/20/137079.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/137079.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/137079.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 网上有很多四元数相关的文章。<br><br>百度百科 http://baike.baidu.com/view/319754.htm<br><br>某位的博客 http://caterpillar.onlyfun.net/Gossip/ComputerGraphics/QuaternionsRotate.htm<br><br>但当你看完这些后。再看着下面这样的代码，你能快速回过神来么？<br><br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/12/20/137079.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/137079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-12-20 23:22 <a href="http://www.cppblog.com/Leaf/archive/2010/12/20/137079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Computing Tangent Space Basis Vectors for an Arbitrary Mesh</title><link>http://www.cppblog.com/Leaf/archive/2010/12/20/137078.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Mon, 20 Dec 2010 15:17:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/12/20/137078.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/137078.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/12/20/137078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/137078.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/137078.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原文地址：http://www.terathon.com/code/tangent.html<br><br>为一个任意网格模型计算其切线空间的基本向量（即切线空间的T B N三个向量）<br><br>Modern bump mapping (also known as normal mapping) requires that tangent plane basis vectors be calculated for each vertex in a mesh. This article presents the theory behind the computation of per-vertex tangent spaces for an arbitrary triangle mesh and provides source code that implements the proper mathematics.<br><br>现在的bump mapping(或者normal mapping)需要每个顶点的切面的基本向量。这篇文章描述了逐顶点计算任意三角模型的切线空间原&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/12/20/137078.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/137078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-12-20 23:17 <a href="http://www.cppblog.com/Leaf/archive/2010/12/20/137078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>四元数与欧拉角互换</title><link>http://www.cppblog.com/Leaf/archive/2010/12/18/136861.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Sat, 18 Dec 2010 14:15:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/12/18/136861.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/136861.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/12/18/136861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/136861.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/136861.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文乃转载，但原文地址不知。若作者有幸看到，请及时认领。<br><br>        在3D图形学中，最常用的旋转表示方法便是四元数和欧拉角，比起矩阵来具有节省存储空间和方便插值的优点。本文主要归纳了两种表达方式的转换，计算公式采用3D笛卡尔坐标系： <br><br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/12/18/136861.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/136861.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-12-18 22:15 <a href="http://www.cppblog.com/Leaf/archive/2010/12/18/136861.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HDR效果简介</title><link>http://www.cppblog.com/Leaf/archive/2010/05/27/116431.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Wed, 26 May 2010 16:53:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/05/27/116431.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/116431.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/05/27/116431.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/116431.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/116431.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 首先我们先来看看HDR是什么意思。<br>HDR 是 high dynamic rang（高动态范围） 的简称。<br>OK，现在我们知道了什么叫高动态范围。<br>还是过把隐，先看看截图。。&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/05/27/116431.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/116431.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-05-27 00:53 <a href="http://www.cppblog.com/Leaf/archive/2010/05/27/116431.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CPU GPU设计工作原理《转》</title><link>http://www.cppblog.com/Leaf/archive/2010/05/18/115646.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Tue, 18 May 2010 01:51:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/05/18/115646.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/115646.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/05/18/115646.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/115646.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/115646.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要:          我知道这很长,但是,我坚持看完了.希望有幸看到这文章并对图形方面有兴趣的朋友,也能坚持看完.一定大有收获.毕竟知道它们到底是怎么"私下勾搭"的.会有利于我们用程序来指挥它们....(这是我加上去的)<br><br>原文从这里开始:<br><br>要说到设计的复杂程度，那还是CPU了！这个不用讨论，很简单的道理你看看显卡芯片的更新速度和CPU的更新速度就可见一斑了。还是简单说说他们的设计原理吧。<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/05/18/115646.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/115646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-05-18 09:51 <a href="http://www.cppblog.com/Leaf/archive/2010/05/18/115646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[原]Irrlicht(鬼火引擎）中多设备的支持</title><link>http://www.cppblog.com/Leaf/archive/2010/04/26/113558.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Mon, 26 Apr 2010 01:10:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/04/26/113558.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/113558.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/04/26/113558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/113558.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/113558.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 理清一个引擎，不得不先理清它的层次结构，进而理清渲染流程。 本文给出了鬼火引擎中的设备抽象层，有助于对鬼火引擎源码的快速阅读&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/04/26/113558.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/113558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-04-26 09:10 <a href="http://www.cppblog.com/Leaf/archive/2010/04/26/113558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于《3D管线导论》这本书</title><link>http://www.cppblog.com/Leaf/archive/2010/04/26/113552.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Sun, 25 Apr 2010 16:03:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/04/26/113552.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/113552.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/04/26/113552.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/113552.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/113552.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 游戏开发中，计算机图形学是必不可少的东西。许多人也是从接触图形开始而进入游戏行业的。3D管线导论这本书诠释了3D管线的细节。为大家解开了萦绕已久的迷团。&nbsp;&nbsp;<a href='http://www.cppblog.com/Leaf/archive/2010/04/26/113552.html'>阅读全文</a><img src ="http://www.cppblog.com/Leaf/aggbug/113552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-04-26 00:03 <a href="http://www.cppblog.com/Leaf/archive/2010/04/26/113552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>切线空间（纹理空间）的计算</title><link>http://www.cppblog.com/Leaf/archive/2010/03/23/110327.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Mon, 22 Mar 2010 16:03:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/03/23/110327.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/110327.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/03/23/110327.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/110327.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/110327.html</trackback:ping><description><![CDATA[<p style="FONT-FAMILY: 方正姚体; COLOR: #000080; FONT-SIZE: 18pt">终于找到了两篇让人易懂的文章，这两篇结合着看，很容易看清计算过程，没有想象中的那么复杂<br><br>这是一篇老外的：<a href="http://www.terathon.com/code/tangent.html">http://www.terathon.com/code/tangent.html</a><br><br><br><br>这是另一个大哥的：<a href="http://jingli83.blog.sohu.com/94746672.html">http://jingli83.blog.sohu.com/94746672.html</a><br><br>两篇结合看，方显其效！<br><br>有了这两篇的理解后，再去看其它的关于切线空间的文章，就不会再摸不着东南西北了！<br><br></p>
<img src ="http://www.cppblog.com/Leaf/aggbug/110327.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-03-23 00:03 <a href="http://www.cppblog.com/Leaf/archive/2010/03/23/110327.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SSAO</title><link>http://www.cppblog.com/Leaf/archive/2010/03/22/110271.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Mon, 22 Mar 2010 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/03/22/110271.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/110271.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/03/22/110271.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/110271.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/110271.html</trackback:ping><description><![CDATA[<p style="COLOR: red">SSAO全称&#8220;Screen-Space Ambient Occlusion&#8221; (屏幕空间环境光遮蔽)。其最先运用于 Crysis（孤岛危机） 游戏中，通过GPU的 shader实现 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　SSAO通过采样象素周围的信息，并进行简单的深度值对比来计算物体身上环境光照无法到达的范围，从而可以近似地表现出物体身上在环境光照下产生的轮廓阴影。可以利用&#8220;逐象素场景深度计算&#8221;技术计算得出的深度值直接参与运算。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　现在的效果确实错误还比较大，应该先进行简单的空间划分（或类似处理）然后计算。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　不过个人认为这种方法只是近似地模拟，效果并不正确，但确实能增强场景的层次感，让画面更细腻，让场景细节更加明显。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　不同于显卡驱动中普通的AO选项，burnout的SSAO是全动态的，无需预处理，无loading时间，无需消耗内存，不使用CPU，全由GPU处理，对GPU有较大的消耗 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　SSAO默认是关闭的，可以在游戏视频选项中打开 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　评测 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　在7950GT下跑，加了ssao后，下降了15%。而且，显卡性能越低，下降的越厉害。效率消耗主要是在于要多渲染一遍场景到深度以及之后进行的ssao处理。这遍可以进行优化，如果物体的纹理不带alpha,则可以把他们都合在一批或几批渲染。至于深度图的尺寸 ，我采用了与窗口一样的尺寸，这样精度高。也可以采用低分辨率，但效果会有锯齿，还需要进行模糊处理才比较自然。当然，如果本来就用了延迟渲染技术，本来就有深度图了，那就可以直接拿来用了。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　与PRT对比 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　PRT用于静态场景确实是个比较好的方案，毕竟可以预计算。但是对于动态的场景，还需要动态更新。另外，PRT的质量依赖于网格的细分程度，要是模型太简，则效果也糟糕。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　因此 ，PRT对于虚拟现实项目里的高楼大厦等场景（这些模型都是很精简的）来说，就显得不合适了 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　目前已发行的游戏中，运用SSAO的游戏有 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　Crysis（孤岛危机） </p>
<div class=spctrl></div>
<p style="COLOR: red">　　Burnout(TM) Paradise The Ultimate Box（火爆狂飙5天堂） </p>
<div class=spctrl></div>
<p style="COLOR: red">　　帝国：全面战争 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　另外，星际争霸2的开发也运用到了SSAO </p>
<h3><a name=""></a>什么是SSAO？</h3>
<p style="COLOR: red">　　从HL2开始，众多游戏公司开始对于如何表现&#8220;间接光照&#8221;进行研究，这些昙花一现的技术有： </p>
<div class=spctrl></div>
<p style="COLOR: red">　　运用于HL2的radiosity Normal Maps技术，效果比较垃圾 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　运用于Stalker的GI（？）技术，算法不好，开销巨大。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　初期Crytek准备运用在Crysis上的Photon Mapping（光子映射）技术，开销同样比较垃圾，被抛弃。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　随后Crytek又准备运用在Crysis上的Real-Time Ambient Map（实时环境光照贴图，简称RAM），这个是与之前Stalker使用的技术比较类似的，也是最接近SSAO的一个技术。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　不过Crytek不愧为&#8220;间接光照&#8221;研究上的先锋，其技术员对于RAM进行了改进，新的算法成为了如今的SSAO </p>
<div class=spctrl></div>
<p style="COLOR: red">　　SSAO开与关的区别所在 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　SSAO（Screen-Space Ambient Occlusion）是一个纯粹的渲染技术，或者说，是一个算法。虽然从上文知道是为了实现&#8220;间接光照&#8221;的效果，不过从技术上讲，就是一个对于AO（Ambient Occlusion环境光吸收，也就是NV 185.20驱动加入的那个，一个渲染技术，我们可以在Maya等3D软件中可以见到）的一个逼近函数，并且以此为据进行实时渲染。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　SSAO比起185.20驱动中AO的优点： </p>
<div class=spctrl></div>
<p style="COLOR: red">　　与场景复杂性无关 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　无数据预处理，无loading时间，无系统内存分配 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　动态渲染 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　每个像素工作方式始终一致 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　无CPU占用，完全通过GPU执行 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　与流行显卡的管线整合相当容易 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　缺点也是有的： </p>
<div class=spctrl></div>
<p style="COLOR: red">　　由于采样全部在可见点上进行的，对于不可见点的遮挡影响会有错误的估算。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　颗粒感比较重，需要与动态模糊紧密配合才能取得较好效果。 </p>
<h3><a name=""></a>SSAO屏幕空间环境光遮蔽的运作方式</h3>
<p style="COLOR: red">　　其实了解了AO环境光遮蔽的原理，SSAO（屏幕空间环境光遮蔽）已经可以融会贯通，SSAO通过采样像素周围的信息，并进行简单的深度值对比来计算物体身上环境光照无法到达的范围，从而可以近似地表现出物体身上在环境光照下产生的轮廓阴影。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　具体的运作方式上，SSAO会利用GPU计算出指定像素的空间坐标，然后以此坐标为基点，在周围选择数个采样点进行采样，然后将采样点的空间坐标投影回屏幕坐标，对深度缓冲进行采样，最后得到采样点的深度值，再进行后续计算，最终得到一个遮挡值。 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　 </p>
<div class=text_pic style="FLOAT: left; VISIBILITY: visible; PADDING-BOTTOM: 3px; WIDTH: 200px"><a href="http://baike.baidu.com/image/c8ab0bce4ef41907b600c8c3" target=_blank><img class=editorImg title=SSAO实现了较好的全局光照效果 src="http://imgsrc.baidu.com/baike/abpic/item/c8ab0bce4ef41907b600c8c3.jpg"></a>
<h3>S<wbr>S<wbr>A<wbr>O<wbr>实<wbr>现<wbr>了<wbr>较<wbr>好<wbr>的<wbr>全<wbr>局<wbr>光<wbr>照<wbr>效<wbr>果<wbr></h3>
</div>
<p style="COLOR: red">SSAO屏幕空间环境光遮蔽实现了较好的全局光照效果 </p>
<div class=spctrl></div>
<p style="COLOR: red">　　因为是基于指定空间的全局计算模式，因此SSAO实现效果的优劣取决于算法，包括空间的指定范围和采样点的选取等等。需要指明的是，不同游戏（引擎）在SSAO的细节算法方面可能不尽相同，另外SSAO还会结合其它光照技术共同达成游戏画面的渲染，所以SSAO在很多游戏中不会有专门的开关选项，其最终的表现结果可能是与其它技术共同作用的结果。</p>
<img src ="http://www.cppblog.com/Leaf/aggbug/110271.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-03-22 10:19 <a href="http://www.cppblog.com/Leaf/archive/2010/03/22/110271.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>渲染状态管理</title><link>http://www.cppblog.com/Leaf/archive/2010/01/29/106723.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 29 Jan 2010 06:40:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/01/29/106723.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/106723.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/01/29/106723.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/106723.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/106723.html</trackback:ping><description><![CDATA[转自：<a href="http://www.abc188.com/info/html/wangzhanyunying/jianzhanjingyan/20080417/71683.html">http://www.abc188.com/info/html/wangzhanyunying/jianzhanjingyan/20080417/71683.html</a><br>
<div class=intro>文档简介： 提高3D图像程式的性能是个很大的课题。图像程式的优化大致能够分成两大任务，一是要有好的场景管理程式，能快速剔除不可见多边形，并根据对象距相机远近选择合适的细节（LOD）；二是要有好的渲染程式，能快速渲染送入渲染管线的可见多边形。 我们知道，使用</div>
<div class=content>　　 <span class=articlebody>文档简介： <br>　　提高3D图像程式的性能是个很大的课题。图像程式的优化大致能够分成两大任务，一是要有好的场景管理程式，能快速剔除不可见多边形，并根据对象距相机远近选择合适的细节（LOD）；二是要有好的渲染程式，能快速渲染送入渲染管线的可见多边形。 <br>　　我们知道，使用OpenGL或Direct3D渲染图像时，首先要配置渲染状态，渲染状态用于控制渲染器的渲染行为。应用程式能够通过改变渲染状态来控制OpenGL或Direct3D的渲染行为。比如配置Vertex/Fragment Program、绑定纹理、打开深度测试、配置雾效等。 <br>　　改变渲染状态对于显卡而言是比较耗时的操作，而假如能合理管理渲染状态，避免多余的状态转换，将明显提升图像程式性能。这篇文章将讨论渲染状态的管理。 <br><br>文档目录： <br>　　基本思想 <br>　　实际问题 <br>　　渲染脚本 <br><br>文档内容： <br><br>基本思想 <br>　　我们考虑一个典型的游戏场景，包含人、动物、植物、建筑、交通工具、武器等。稍微分析一下就会发现，实际上场景里很多对象的渲染状态是相同的，比如任何的人和动物的渲染状态一般都相同，任何的植物渲染状态也相同，同样建筑、交通工具、武器也是如此。我们能够把具备相同的渲染状态的对象归为一组，然后分组渲染，对每组对象只需要在渲染前配置一次渲染状态，并且还能够保存当前的渲染状态，配置渲染状态时只需改变和当前状态不相同的状态。这样能够大大减少多余的状态转换。下面的代码段演示了这种方法： <br><br>// 渲染状态组链表，由场景管理程式填充 <br>RenderStateGroupList groupList; <br>// 当前渲染状态 <br>RenderState curState; <br><br>&#8230;&#8230; <br><br>// 遍历链表中的每个组 <br>RenderStateGroup *group = groupList.GetFirst(); <br>while ( group != NULL ) <br>{ <br>// 配置该组的渲染状态 <br>RenderState *state = group-&gt;GetRenderState(); <br>state-&gt;ApplyRenderState( curState ); <br><br>// 该渲染状态组的对象链表 <br>RenderableObjectList *objList = group-&gt;GetRenderableObjectList(); <br>// 遍历对象链表的每个对象 <br>RenderableObject *obj = objList-&gt;GetFirst(); <br>while ( obj != NULL ) <br>{ <br>// 渲染对象 <br>obj-&gt;Render(); <br><br>obj = objList-&gt;GetNext(); <br>} <br><br>group = groupList.GetNext(); <br>} <br><br>其中RenderState类的ApplyRenderState方法形如： <br>void RenderState::ApplyRenderState( RenderState &amp;curState ) <br>{ <br>// 深度测试 <br>if ( depthTest != curState.depthTest ) <br>{ <br>SetDepthTest( depthTest ); <br>curState.depthTest = depthTest; <br>} <br><br>// Alpha测试 <br>if ( alphaTest != curState.alphaTest ) <br>{ <br>SetAlphaTest( alphaTest ); <br>curState.alphaTest = alphaTest; <br>} <br><br>// 其他渲染状态 <br>&#8230;&#8230; <br>} <br><br>　　这些分组的渲染状态一般被称为Material或Shader。这里Material不同于OpenGL和Direct3D里面用于光照的材质，Shader也不同于OpenGL里面的Vertex/Fragment Program和Direct3D里面的Vertex/Pixel Shader。而是指封装了的显卡渲染图像需要的状态（也包括了OpenGL和Direct3D原来的Material和Shader）。 <br><br>　　从字面上看，Material（材质）更侧重于对象表面外观属性的描述，而Shader（这个词实在不好用中文表示）则有用程式控制对象表面外观的含义。由于显卡可编程管线的引入，渲染状态中包含了Vertex/Fragment Program，这些小程式能够控制物体的渲染，所以我觉得将封装的渲染状态称为Shader更合适。这篇文章也将称之为Shader。 <br><br>　　上面的代码段只是简单的演示了渲染状态管理的基本思路，实际上渲染状态的管理需要考虑很多问题。 <br>渲染状态管理的问题 <br>　 <br><br>　消耗时间问题 <br>　　改变渲染状态时，不同的状态消耗的时间并不相同，甚至在不同条件下改变渲染状态消耗的时间也不相同。比如绑定纹理是个很耗时的操作，而当纹理已在显卡的纹理缓存中时，速度就会很快。而且随着硬件和软件的发展，一些很耗时的渲染状态的消耗时间可能会有减少。因此并没有一个准确的消耗时间的数据。 <br><br>　　虽然消耗时间无法量化，情况不同消耗的时间也不相同，但一般来说下面这些状态转换是比较消耗时间的： <br><br>Vertex/Fragment Program模式和固定管线模式的转换（FF，Fixed Function Pipeline） <br><br>Vertex/Fragment Program本身程式的转换 <br><br>改变Vertex/Fragment Program常量 <br><br>纹理转换 <br><br>顶点和索引缓存（Vertex &amp; Index Buffers）转换 <br><br>　　有时需要根据消耗时间的多少来做折衷，下面将会碰到这种情况。 <br><br><br><br>　渲染状态分类 <br>　　实际场景中，往往会出现这样的情况，一类对象其他渲染状态都相同，只是纹理和顶点、索引数据不同。比如场景中的人，只是身材、长相、服装等不同，也就是说只有纹理、顶点、索引数据不同，而其他如Vertex/Fragment Program、深度测试等渲染状态都相同。相反，一般不会存在纹理和顶点、索引数据相同，而其他渲染状态不同的情况。我们能够把纹理、顶点、索引数据不归入到Shader中，这样场景中任何的人都能够用一个Shader来渲染，然后在这个Shader下对纹理进行分组排序，相同纹理的人放在一起渲染。 <br>　多道渲染（Multipass Rendering） <br>　　有些比较复杂的图像效果，在低档显卡上需要渲染多次，每次渲染一种效果，然后用GL_BLEND合成为最终效果。这种方法叫多道渲染Multipass Rendering，渲染一次就是个pass。比如做逐像素凹凸光照，需要计算环境光、漫射光凹凸效果、高光凹凸效果，在NV20显卡上只需要1个pass，而在NV10显卡上则需要3个pass。Shader应该支持多道渲染，即一个Shader应该分别包含每个pass的渲染状态。 </div>
<br>不同的pass往往渲染状态和纹理都不同，而顶点、索引数据是相同的。这带来一个问题：是以对象为单位渲染，一次渲染一个对象的任何pass，然后渲染下一个对象；还是以pass为单位渲染，第一次渲染任何对象的第一个pass，第二次渲染任何对象的第二个pass。下面的程式段演示了这两种方式： <br><br>以对象为单位渲染 <br><br>// 渲染状态组链表，由场景管理程式填充 <br>ShaderGroupList groupList; <br><br>&#8230;&#8230; <br><br>// 遍历链表中的每个组 <br>ShaderGroup *group = groupList.GetFirst(); <br>while ( group != NULL ) <br>{ <br>Shader *shader = group-&gt;GetShader(); <br><br>RenderableObjectList *objList = group-&gt;GetRenderableObjectList(); <br><br>// 遍历相同Shader的每个对象 <br>RenderableObject *obj = objList-&gt;GetFirst(); <br>while ( obj != NULL ) <br>{ <br>// 获取shader的pass数 <br>int iNumPasses = shader-&gt;GetPassNum(); <br>for ( int i = 0; i &lt; iNumPasses; i ) <br>{ <br>// 配置shader第i个pass的渲染状态 <br>shader-&gt;ApplyPass( i ); <br>// 渲染对象 <br>obj-&gt;Render(); <br>} <br><br>obj = objList-&gt;GetNext(); <br>} <br><br>group = groupList-&gt;GetNext(); <br>} <br><br><br>以pass为单位渲染 <br><br>// 渲染状态组链表，由场景管理程式填充 <br>ShaderGroupList groupList; <br><br>&#8230;&#8230; <br><br>for ( int i = 0; i &lt; MAX_PASSES_NUM; i ) <br>{ <br>// 遍历链表中的每个组 <br>ShaderGroup *group = groupList.GetFirst(); <br>while ( group != NULL ) <br>{ <br>Shader *shader = group-&gt;GetShader(); <br>int iNumPasses = shader-&gt;GetPassNum(); <br>// 假如shader的pass数小于循环次数，跳过此shader <br>if( i &gt;= iNumPasses ) <br>{ <br>group = groupList-&gt;GetNext(); <br>continue; <br>} <br><br>// 配置shader第i个pass的渲染状态 <br>shader-&gt;ApplyPass( i ); <br><br>RenderableObjectList *objList = <br>group-&gt;GetRenderableObjectList(); <br><br>// 遍历相同Shader的每个对象 <br>RenderableObject *obj = objList-&gt;GetFirst(); <br>while ( obj != NULL ) <br>{ <br>obj-&gt;Render(); <br><br>obj = objList-&gt;GetNext(); <br>} <br><br>group = groupList-&gt;GetNext(); <br>} <br>} <br><br><br><br>　　这两种方式各有什么优缺点呢？ <br><br>　　以对象为单位渲染，渲染一个对象的第一个pass后，马上紧接着渲染这个对象的第二个pass，而每个pass的顶点和索引数据是相同的，因此第一个pass将顶点和索引数据送入显卡后，显卡Cache中已有了这个对象顶点和索引数据，后续pass不必重新将顶点和索引数据拷到显卡，因此速度会很快。而问题是每个pass的渲染状态都不同，这使得实际上每次渲染都要配置新的渲染状态，会产生大量的多余渲染状态转换。 <br><br>　　以pass为单位渲染则正好相反，以Shader分组，相同Shader的对象一起渲染，能够只在这组开始时配置一次渲染状态，相比以对象为单位，大大减少了渲染状态转换。可是每次渲染的对象不同，因此每次都要将对象的顶点和索引数据拷贝到显卡，会消耗不少时间。 <br>　　可见想减少渲染状态转换就要频繁拷贝顶点索引数据，而想减少拷贝顶点索引数据又不得不增加渲染状态转换。鱼和熊掌不可兼得 :-( <br>　　由于硬件条件和场景数据的情况比较复杂，具体哪种方法效率较高并没有定式，两种方法都有人使用，具体选用那种方法需要在实际环境测试后才能知道。 <br><br><br>　多光源问题 <br>待续&#8230;&#8230; <br><br><br><br>　阴影问题 <br>待续&#8230;&#8230; <br><br><br>　 <br><br>渲染脚本 <br>　　现在很多图像程式都会自己定义一种脚本文档来描述Shader。 <br><br>　　比如较早的OGRE（Object-oriented Graphics Rendering Engine，面向对象图像渲染引擎）的Material脚本，Quake3的Shader脚本，连同刚问世不久的Direct3D的Effect File，nVIDIA的CgFX脚本（文档格式和Direct3D Effect File兼容），ATI RenderMonkey使用的xml格式的脚本。OGRE Material和Quake3 Shader这两种脚本比较有历史了，不支持可编程渲染管线。而后面三种比较新的脚本都支持可编程渲染管线。 <br><br><br><br>脚本 特性 范例 <br>OGRE Material 封装各种渲染状态，不支持可编程渲染管线 &gt;&gt;&gt;&gt; <br>Quake3 Shader 封装渲染状态，支持一些特效，不支持可编程渲染管线 &gt;&gt;&gt;&gt; <br>Direct3D Effect File 封装渲染状态，支持multipass，支持可编程渲染管线 &gt;&gt;&gt;&gt; <br>nVIDIA CgFX脚本 封装渲染状态，支持multipass，支持可编程渲染管线 &gt;&gt;&gt;&gt; <br>ATI RenderMonkey脚本 封装渲染状态，支持multipass，支持可编程渲染管线 &gt;&gt;&gt;&gt; <br><br><br><br>　　使用脚本来控制渲染有很多好处： <br><br>能够很方便的修改一个物体的外观而不需重新编写或编译程式 <br><br>能够用外围工具以所见即所得的方式来创建、修改脚本文档（类似ATI RenderMonkey的工作方式），便于美工、关卡设计人员设定对象外观，建立外围工具和图像引擎的联系 <br><br>能够在渲染时将相同外观属性及渲染状态的对象（也就是Shader相同的对象）归为一组，然后分组渲染，对每组对象只需要在渲染前配置一次渲染状态，大大减少了多余的状态转换 </span>
<img src ="http://www.cppblog.com/Leaf/aggbug/106723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-01-29 14:40 <a href="http://www.cppblog.com/Leaf/archive/2010/01/29/106723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化3D图形流水线</title><link>http://www.cppblog.com/Leaf/archive/2010/01/29/106721.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 29 Jan 2010 05:48:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/01/29/106721.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/106721.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/01/29/106721.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/106721.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/106721.html</trackback:ping><description><![CDATA[<p>转自：<a href="http://hi.baidu.com/freedomknightduzhi/blog/item/7e401a9b2521eeb3c9eaf4f1.html">http://hi.baidu.com/freedomknightduzhi/blog/item/7e401a9b2521eeb3c9eaf4f1.html</a><br>在使用NVIDIA PerfHUD 5 Launcher的时候，明显发现现在的CPU时间和GPU时间不均衡，于是考虑优化。<br>下面是参考NVIDIA的OGP开始总结。<br>优化代码通常是找出瓶颈，对瓶颈进行优化，这里暂不考虑CPU内部的优化方法，主要记录CPU-&gt;GPU的3D渲染流水线的瓶颈查出方法以及优化手段。<br>若仅希望进行CPU方面的优化，可使用一些辅助工具，如Inter的Intel(R) VTune(TM) Performance Analyzer，Intel(R) Thread Profiler 3.1，AMD的CodeAnalyst等。<br>进行优化的步骤如上面所说：1：找出瓶颈，2：对其优化。<br>最通用也最有效的找出瓶颈的方法当然是找到核心函数，降低它的时钟周期和负荷，看是否对程序性能有大的影响。优化的手段多是拆东补西而已，即，将影响性能的瓶颈中的任务分配给其他较空闲的部分进行处理，来平衡整体所消耗的时间。<br>那么来看一下图形渲染流水线大致过程。<br>1：系统CPU从内存中读取几何顶点 -&gt; 输送到GPU显存 -&gt; 输送到GPU高速顶点缓冲区 -&gt; GPU顶点着色 -&gt; GPU建立三角型 -&gt; GPU矩阵变换 -&gt; GPU光栅化 -&gt; 3<br>2：系统CPU从内存中读取纹理信息 -&gt; 输送到GPU显存 -&gt; 输送到GPU高速纹理缓冲区( DX10.0以后可与顶点缓冲共同，不再强制区分 ) -&gt; 3<br>3：片段着色光栅化 -&gt; 输出GPU后台缓冲进行渲染。<br>那么，很简单的有几大模块在其中可能存在着瓶颈的限制。</p>
<p>1：CPU本身逻辑计算能力的限制。<br><br>2：CPU到GPU显存AGP传输能力的限制<br>（1）顶点<br>（2）纹理<br>3：GPU显存到高速缓冲区的传输带宽限制<br>（1）纹理传输带宽限制&nbsp;&nbsp;&nbsp;&nbsp; （显存-&gt;高速缓冲区）<br>（2）光栅化完毕后的桢传输带宽限制 （高速缓冲区-&gt;显存）<br>注：这里不考虑 顶点 传输的带宽限制，因为这个限制极小<br>4：GPU高速缓冲区内部处理能力的限制。<br>（1）顶点变换着色处理能力限制。<br>（2）顶点最大数量支持限制。<br>（3）三角型建立限制。<br>（4）光栅化限制。<br>（5）象素着色限制。<br>5：内存过小限制。<br>6：显卡显存过小，以及其他硬件Caps限制。</p>
<p>上述就是常见3D图形渲染流水线中的瓶颈限制，那么我们下一步去一一确定，可能是哪方面的瓶颈。简单的方法是检测FPS。<br>注意1：许多瓶颈可能由于硬件更变而更变。<br>注意2：Debug模式和Release模式的瓶颈表现未必相同。<br>注意3：查看FPS时候一定关闭垂直同步。<br>1：改变色深，16bit,32bit，这个是直接影响 桢渲染缓冲 的大小的，若修改了此项之后，FPS有较大变化，则是由于3.2 桢传输带宽限制。<br>注：这里需要改变所有渲染对象的色深。<br>2：改变纹理大小尺寸，改变纹理过滤方式，若修改了此项之后，FPS有较大变化，则是由于3.1 纹理传输带宽的限制 或 2.2 纹理AGP传输能力限制。<br>注：纹理过滤方式中，点过滤速度 &gt; 线性过滤速度 &gt; 三角面过滤速度 &gt; 各向异性过滤速度 若改变纹理过滤方式就将FPS提高了，则是3.1 纹理传输带宽的限制。这步是将纹理数据从显存运输到GPU高速纹理缓冲区的过程。<br>3：改变桌面分辨率，若修改了此项之后，FPS有较大变化，则是由于 4.4 光栅化限制 或是 4.5 象素着色Shader限制。<br>此时减少 PixelShader指令数量，若修改了此项之后，FPS有较大变化，则是由于 4.5 象素着色Shader限制，若没有较大变化，则是由于 4.4 光栅化限制。<br>4：减少 VertexShader 指令数量，若修改了此项之后，FPS有较大变化，则是由于 4.1 顶点变换着色处理能力限制。<br>5：减少顶点数量和AGP传输速率，若修改了此项之后，FPS有较大变化，则是由于 4.2 顶点最大数量支持限制 或 2.1 顶点AGP传输能力限制。<br>6：若以上都不是，则是 1.0 CPU逻辑计算能力限制。<br>注：该项也可根据NVIDIA PerfHUD来检测CPU和GPU的空闲时间来判定，若GPU空闲时间过多，则说明是由于CPU计算能力或AGP传输能力导致。<br>该项也可用简单的更换CPU，而不更换GPU的方式来检测判定。<br>7：看资源管理器，CPU占用率，内存占用率，可以知道是否是由于1.0 CPU本身逻辑计算能力的限制 或是 5.0内存过小限制。<br>8：看DX SDK自带的CapsViewer可以知道显卡的支持性，以获得更多更准确的判定。<br>9：在BIOS中更变APGP为1X模式，若修改了此项之后，FPS有较大变化，则是由于2.1 或 2.2 AGP传输能力限制。<br>10：降低GPU配置进行检测判定，此时要注意两项，一是降低GPU的运行频率，一是降低GPU显存性能和大小，可以确定GPU方面的问题大致所在。<br>11：删除一些游戏中涉及的 物理，AI，逻辑 等占用大量CPU效率的代码以获得更强的针对性。<br>12：对角色，地形，静态模型，阴影 等设置渲染开关，以更明确的确定问题所在。</p>
<p>优化方法：<br>一：整体优化。<br>1：减少小批量作业<br>（1）让一个顶点缓冲中更多顶点。（1024点以上较适合）<br>（2）少Draw。（尽量一次性多渲染些三角形，减少渲染次数）<br>（3）尽量将多个尺寸小的纹理文件合并为一个尺寸大的纹理文件，减少零碎的小纹理文件数量。<br>（4）使用VertexShader将一些关系紧密的几何体打包在一起。（VS2.0就已经存在256个4D向量常数）<br>2：逻辑排序优化<br>（1）尽量在逻辑层将顶点进行一定的排序以减少在GPU高速缓冲区中的重新排布。<br>（2）尽量将渲染对象在逻辑层按照深度由屏幕-&gt;内部排序，减少不必要的深度拣选。<br>（3）尽量使用索引条带或索引列表<br>（4）根据渲染状态和渲染对象对纹理进行基本排序<br>3：减少不必要的渲染（CPU层的基本二分四叉八叉这里不再强调）<br>（1）在多Pass渲染时，在第一个渲染Pass上对每个渲染对象加以咨询，当第一个Pass中该渲染对象渲染象素量达不到指定标准，则后续Pass不再对其进行渲染。<br>（2）对一些重复渲染（如太阳眩光特效）需要进行计数，达到指定数量即停止渲染或进行分布式渲染。<br>（3）对一些复杂的模型设置基本的包围盒判定其渲染必要性。<br>4：减少线程锁定导致的不必要等待<br>（1）CPU Lock了一个资源，等待GPU进行渲染，此时常见做法有等待GPU渲染，中间期间CPU经常处于Idle空闲状态，建议此时给CPU其他的事情做，如为下一个资源做好基本准备或进行逻辑处理。<br>5：减少或平均分布CPU压力（实际上，大部分程序是CPU逻辑计算限制的）<br>（1）CPU压力重点在以下方面可能存在： AI，IO，网络，复杂逻辑，这些部分可进行CPU瓶颈测试以确定优化方向。<br>（2）优化方针：宁可GPU忙碌也要CPU减压。<br>（3）使用文章开始时我提到的一些工具去查找CPU中不必要的汇编空循环以及不必要的CPU空闲。<br>二：局部优化。<br>6：AGP传输瓶颈<br>（1）当过多数据通过AGP8X从CPU内存传递到GPU显存时，我们可以选择以下方式优化。<br>&nbsp;&nbsp; [1]减小顶点个数<br>&nbsp;&nbsp; [2]减少动态顶点个数，使用VertexShader动画替代。<br>&nbsp;&nbsp; [3]正确使用API，设置正确参数，避免动态顶点和纹理缓冲区的创建管理。<br>&nbsp;&nbsp; [4]根据硬件配置属性确定适合的 桢缓冲，纹理缓冲，静态顶点缓冲 的大小。<br>（2）避免使用无序或不规则数据传输。<br>&nbsp;&nbsp; [1]顶点数量尺寸应当是32的整数倍。（可使用顶点压缩，再在VertexShader中对顶点数据进行解压缩）<br>&nbsp;&nbsp; [2]确保顶点的有序性。（在CPU逻辑层对其进行排序后传输，NVTriStrip这个工具可以帮我们生成优化的高效的有序的Mesh顶点数据）<br>（3）具体到API层面的几何Mesh传输<br>&nbsp;&nbsp; [1]对于静态几何体，创建 只写的顶点缓冲，且，仅写入一次。<br>&nbsp;&nbsp; [2]对于动态几何体，在程序初始创建一个动态顶点缓冲，之后每桢初始锁定DISCARD，进行NOOVEWRITE而不要进行DISCARD，DISCARD的耗时不是NOOVEWRITE可比的。<br>&nbsp;&nbsp; [3]基本原则，少创建缓冲区，多对其进行重复使用，减少锁定次数。<br>7：顶点变换传输处理瓶颈（由于GPU有强大的顶点处理能力，一般在顶点变换方面不会有瓶颈出现，但假若出现了。。）<br>（1）顶点太多<br>&nbsp;&nbsp; [1]使用细节Lod，一般起用2-3级Lod就足够了。<br>（2）顶点处理过于复杂<br>&nbsp;&nbsp; [1]减少灯光数量，降低灯光复杂度（方向平行光效率 &gt; 点光源效率 &gt; 聚光灯效率 ）<br>&nbsp;&nbsp; [2]减少顶点着色器指令数量，避免128条以上指令，避免大量的分支指令<br>&nbsp;&nbsp; [3]对顶点进行CPU层逻辑排序<br>&nbsp;&nbsp; [4]能在CPU中进行计算的在CPU中进行计算，传递常量给GPU<br>&nbsp;&nbsp; [5]减少和避免CG/HLSL之中的 mov 指令。即使使用了，也要重点注意。<br>8：大部分情况下 4.3 三角形建立限制 以及 4.4 光栅化限制 是不会成为瓶颈的，但，当三角形数量过多或者光栅化时每个三角形顶点数据过于复杂时可能会出现这种瓶颈，此时减少三角形总数，使用VS或减少Z-cull三角都是有效的方法。<br>9：象素着色器的瓶颈（在DX7之前，全是固定渲染管道，一般来说传输量和着色器之间的计算是均衡的，但是DX8开始可编程流水管道开始，PixelShader的计算量开始增幅，数据传输量通常相对来说比较小了。）<br>（1）需处理的纹理片段过多过大<br>&nbsp;&nbsp; [1]在CPU层按照 屏幕-&gt;向内 Z-Buffer的顺序排序传入，并按照这个顺序进行渲染。<br>&nbsp;&nbsp; [2]多Pass渲染时，考虑在第一个渲染Pass中关闭特效并让第一个Pass负责Z-buffer的处理。这样的话，后续Pass中可以避免渲染不要的纹理片段。<br>（2）每个纹理片段的处理过于复杂<br>&nbsp;&nbsp; [1]大段的长着色器指令将会很大降低效率，尝试减少着色器指令长度<br>&nbsp;&nbsp; [2]使用向量操作，并行co-issuing来减少指令数量。<br>&nbsp;&nbsp; [3]混合使用配对的简单的texture和combiner组合指令。<br>&nbsp;&nbsp; [4]使用Alpha混合器提高性能。<br>&nbsp;&nbsp; [5]考虑对阴影也进行Lod计算。<br>&nbsp;&nbsp; [6]在DX10开始，考虑将顶点缓冲移做象素缓冲进行使用。<br>（3）额外的优化方法<br>&nbsp;&nbsp; [1]使用fx_12精度<br>&nbsp;&nbsp; [2]使用fp16指令<br>&nbsp;&nbsp; [3]使用Pixel_Shader2.0的时候开启ps_2_a描述开关<br>&nbsp;&nbsp; [4]减少寄存器的临时存取<br>&nbsp;&nbsp; [5]减少不必要的精度要求<br>&nbsp;&nbsp; [6]尽量使用低版本的Shader（但避免使用VS1.0，已经被VS3.0抛弃了）<br>10：纹理贴图导致的瓶颈<br>（1）优化方法。<br>&nbsp;&nbsp; [1]纹理过滤时避免使用 三角面性过滤 和 各相异性过滤，特殊需求除外，一般线性过滤已经可以做的很好。<br>&nbsp;&nbsp; [2]即使使用各相异性过滤，也要降低相异性比率。使用了各相异性过滤的话，则可以尽量减少三角面性过滤。<br>&nbsp;&nbsp; [3]降低纹理分辨率，避免使用不必要的高分辨率纹理。<br>&nbsp;&nbsp; [4]降低纹理色深，例如环境纹理，阴影纹理这些，尽量使用16位。<br>&nbsp;&nbsp; [5]建议进行纹理压缩，例如DXT格式就可以有效压缩纹理，并且GPU对DXT格式支持很好。<br>&nbsp;&nbsp; [6]避免使用非二次方的纹理资源。<br>&nbsp;&nbsp; [7]在进行纹理锐化的时候，避免使用负值的Lod进行锐化，会导致远处失真，尽量使用各相异性过滤进行锐化<br>&nbsp;&nbsp; [8]对于动态纹理，一般建议用 D3DUSAGE_DYNAMIC D3DPOOL_DEAFAULT 进行创建缓冲，使用 D3DLOCK_DISCARD 进行锁定，尽量做到一次锁定多次使用，不要频繁解锁，另外，永远不要读这样的纹理。<br>11：桢缓冲导致的瓶颈<br>（1）优化方法<br>&nbsp;&nbsp; [1]尽量关闭Z-write，一般来说，在一个渲染Pass中就可以进行完整的Z-buffer处理，在后续的Pass中就应当关闭Z-write，不用担心，即使需要Alpha混合的对象也不再需要开启Z-write了。<br>&nbsp;&nbsp; [2]尽量开始AlphaTest，实际上这个操作会提高效率，而非降低。<br>&nbsp;&nbsp; [3]避免使用浮点桢缓存。<br>&nbsp;&nbsp; [4]若没有启用模版深度缓冲的话，使用16位的Zbuffer就可以了。<br>&nbsp;&nbsp; [5]避免使用RendToTexture，或者可能的去减少Rend的尺寸。<br>对于现在可编程流水管线来说，这意味着我们有更大的自由度实现更多的特效，但也有了更多的瓶颈和更多的复杂度，我们遇到问题要正确的获取瓶颈所在，开动脑筋进行优化，平衡各环节间的负载。让各环节不过载不空闲。<br><br>更多信息希望您查看Nvidia的《GPU_Programming_Guide》，翻译成中文则是《GPU编程精粹》。以上。</p>
<img src ="http://www.cppblog.com/Leaf/aggbug/106721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-01-29 13:48 <a href="http://www.cppblog.com/Leaf/archive/2010/01/29/106721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化3D图形渲染通道负载</title><link>http://www.cppblog.com/Leaf/archive/2010/01/29/106720.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 29 Jan 2010 05:43:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2010/01/29/106720.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/106720.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2010/01/29/106720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/106720.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/106720.html</trackback:ping><description><![CDATA[<h1>优化3D图形渲染通道负载</h1>
<p><a href="http://www.itjiaocheng.com/jiaocheng/pingmiansheji/AutoCAD/texiaojiqiao/2009/0520/23435.html">http://www.itjiaocheng.com/jiaocheng/pingmiansheji/AutoCAD/texiaojiqiao/2009/0520/23435.html</a></p>
<div id=neirong class=word>
<div id=text class=14black>　　
<p>一般来说， 定位渲染通道瓶颈的方法就是改变渲染通道每个步骤的工作量, 如果吞吐量也改变了, 那个步骤就是瓶颈.。找到了瓶颈就要想办法消除瓶颈, 可以减少该步骤的工作量, 增加其他步骤的工作量。 <br><br>　　 一般在光栅化之前的瓶颈称作&#8221;transform bound&#8221;, 三角形设置处理后的瓶颈称作&#8221;fill bound&#8221;定位瓶颈的办法: <br><br>　　 1.改变帧缓冲或者渲染目标(Render Target)的颜色深度(16 到32 位), 如果帧速改变了, 那么瓶颈应该在帧缓冲(RenderTarget)的填充率上。 <br><br>　　 2.否则试试改变贴图大小和贴图过滤设置, 如果帧速变了,那么瓶颈应该是在贴图这里。 <br><br>　　 3.否则改变分辨率.如果帧速改变了, 那么改变一下pixel shader的指令数量, 如果帧速变了, 那么瓶颈应该就是pixel shader. 否则瓶颈就在光栅化过程中。 <br><br>　　 4.否则, 改变顶点格式的大小, 如果帧速改变了, 那么瓶颈应该在显卡带宽上。 <br><br>　　 5.如果以上都不是, 那么瓶颈就在CPU这一边。 <br><br>　　 优化方法36条: <br><br>　　 1.尽量减少无用的顶点数据, 比如贴图坐标, 如果有Object使用2组有的使用1组, 那么不 要将他们放在一个vertex buffer中, 这样可以减少传输的数据量。 <br><br>　　 2.使用多个streamsource, 比如SkinMesh渲染, 可以把顶点坐标和法线这些每一帧都要修改的数据放在一个动态VB中, 其它不需要修改的(如贴图坐标)放到一个静态VB中, 这样就减少了数据传输量。 <br><br>　　 3.尽量使用16位的索引缓冲,避免32位的. 一方面浪费带宽, 一方面也不是所有的显卡都支持32位的索引缓冲。 <br><br>　　 4.可以考虑使用vertex shader来计算静态VB中的数据.比如SkinMesh的顶点可以放到vectex shader中计算, 这样就可以避免每一帧都从AGP内存中向显存传送数据. 这样也可以使用静态VB了。 <br><br>　　 5.坚决避免使用Draw**UP一族的函数来绘制多边形。 <br><br>　　 6.在设计程序之前好好规划一下显卡内存的使用, 确保framebuffer, 贴图, 静态VB能够正好放入显卡的本地内存中。 <br><br>　　 7.尽量使顶点格式大小是32字节的倍数.可以考虑使用压缩过的顶点格式然后用vertex shader去解. 或者留下冗余的部分, 使顶点大小刚好使32字节的倍数。<br><br>　　 8.顶点在顶点缓冲中的顺序尽量符合绘制的顺序, 考虑使用strips来代替list。 <br><br>　　 9.如果可能尽量多的使用static vertex buffer代替dynamic vertex buffer。 <br><br>　　 10.动态VB使用DISCARD参数来lock更新, 使用NOOVERWR99vE来添加.尽量不要使用不带参数的lock调用(0)。 <br><br>　　 11.尽量减少lock的次数, 有些东西并不一定非要每一帧都更新VB, 比如人物动画一般每秒钟更新30次VB基本上就够了。 <br><br>　　 12.如果是因为需要绘制的顶点数据太多了可以考虑使用LOD, 但是现在的显卡的绘制能力都很强劲, 所以需要权衡一下LOD是否能够带来相应的好处, 如果过分的强化LOD很可能将瓶颈转移到CPU这边。 <br><br>　　 13.避免过多的顶点计算,比如过多的光源, 过于复杂的光照计算(复杂的光照模型), 纹理自动生成的开启也会增加顶点的计算量. 如果贴图坐标变换矩阵不是单位矩阵, 也会造成顶点计算量的增加, 所以如果纹理变换已经结束, 记得要将纹理变换矩阵设为单位矩阵同时调整贴图坐标。 <br><br>　　 14.避免Vertex shader指令数量太多或者分支过多, 尽量减少vertex shader的长度和复杂程度. 尽量使用swizzling代替mov。 <br><br>　　 15.如果图象质量方面的计算(pixel shader)范围很大, 并且很复杂, 可以考虑试试全屏反走样。说不定更快。 <br><br>　　 16.尽量按照front &#8211; back的顺序来绘制。 <br><br>　　 17.在shader中判断Z值可以避免绘制不可见的象素, 但是nvidia建议简单的shader不要这么做.(Don't do this in a simple shader)。 <br><br>　　 18.如果可能, 尽量使用vertex shader来代替pixel shader.将计算从逐象素变成逐顶点。 <br><br>　　 19.尽量降低贴图的大小.过大的贴图可能造成贴图cache过载, 从而导致贴图cache命中降低.过大的贴图会导致显存过载, 这时候贴图是从系统内存中取的。<br><br>　　 20.只要可能就用16位色的贴图, 如环境贴图或者shadow map.它们用32位色的贴图实在是浪费。 <br><br>　　 21.考虑使用DXT 贴图压缩。 <br><br>　　 22.如果可能,使用简单的贴图过滤或者mip map, 除非必要否则尽量不要使用三线过滤和各项异性过滤. light map 和环境贴图基本上都不需要使用它们。 <br><br>　　 23.只有真正需要修改的贴图才使用Dynamic, 并且使用DISCRAD和WR99vEONLY来lock。 <br><br>　　 24.太多的帧缓冲读写可以考虑关闭Z-Writes如有些多pass的渲染中的后续pass或者粒子系统等半透明几何物体（如果可以）。 <br><br>　　 25.可能的话尽量使用alpha test代替alpha blending。 <br><br>　　 26.如果不需要stencil buffer就尽量使用16位的Z buffer。 <br><br>　　 27.减小RenderTarget 贴图的大小, 如shadow map 环境贴图. 可能根本不需要那么大效果就很好。 <br><br>　　 28.Stencil 和Z buffer 尽量一起clear. 他们本来就是一块缓冲。 <br><br>　　 29.尽量减少渲染状态的切换, 尽量一次画尽可能多的多边形。（根据显卡性能决定最多画多少， 不过一般再多也不会多到哪里去。 除非你根本不需要贴图和渲染状态的切换）。 <br><br>　　 30.尽量使用shader来代替Fixed Pipeline。 <br><br>　　 31.尽量使用shader来实现来取代Multipass渲染效果。 <br><br>　　 32.尽量优先先建立重要的资源, 如Render target, shaders, 贴图, VB, IB等等.以免显存过载的时候它们被创建到系统内存中。 <br><br>　　 33.坚决不要在渲染循环中调用创建资源。 <br><br>　　 34.按照shader和贴图分组后再渲染.先按照shaders分组再按贴图。 <br><br>　　 35.Color Stencil Z buffer尽量在一次Clear调用中清除。 <br><br>　　 36.一个Vertex buffer 的大小在2M-4M之间最好。（中国软件）</p>
</div>
</div>
<img src ="http://www.cppblog.com/Leaf/aggbug/106720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2010-01-29 13:43 <a href="http://www.cppblog.com/Leaf/archive/2010/01/29/106720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Shader Model 4.0 全新架构</title><link>http://www.cppblog.com/Leaf/archive/2009/10/16/98781.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 16 Oct 2009 09:47:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2009/10/16/98781.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/98781.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2009/10/16/98781.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/98781.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/98781.html</trackback:ping><description><![CDATA[<br><a href="http://www.impresswatch.com.cn/itwatch/83/3007583.shtml" target=_self><span><font color=#ff7f00>Shader Model4.0统一渲染架构</font></span></a>&nbsp;&nbsp;<br>微软的DirectX 9.0c距今离它的诞生已经有2年的光景，DX9.0c给我们带来了全新的Shader Model3.0技术，也使得3D画面较以往了有了质的突破，DirectX 9.0c是截至至今微软历史上寿命最长的一代API，而图形技术的发展是不会停下脚步的，2006年微软发布了全新的DirectX 10.0，仅从版本上看比9.0c相差一级，但是DirectX 10.0带给我们的又将是一个全新的概念。
<p align=center>&nbsp;</p>
<p>　　在微软发布DX10.0后，NVIDIA积极响应，发布了完全符合DirectX 10.0的通用Shader架构图形处理器G80，也标志着DX9.0c将会逐步被DX10.0替代。相对DirectX 9.0c中的SM3.0，在Shader Model 4.0中微软引入了统一着色架构，这才是DX10最大的改变。我们都知道，微软在DirectX 9中引入的了2.0/2.X/3.0三个版本的Vertex Shader(顶点着色引擎)以及Pixel Shader(像素着色引擎)。其中支持2.0版的着色引擎是DirectX 9的GPU的最低标准，而当前主流的显卡已经都硬件支持加入了拥有更多高级处理功能的3.0版本着色引擎。</p>
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_7.shtml" target=_blank></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;不过，即便是DirectX 9.0c，对于功能相仿Vertex Shader、Pixel Shader来说，目前图形芯片厂商仍需要在GPU中划分两个区域来存放Vertex Shader阵列和Pixel Shader贴图流水线。这无疑是一种资源冗余，而且这也加重GPU的设计难度及成本。当DirectX 10把渲染流程更细分为Vertex Shader、Geometry Shader及Pixel Shader，这个情况将会更为明显。而DX10.0的诞生就将这2种渲染整合在了一起！<br></p>
<br><a href="http://www.impresswatch.com.cn/itwatch/83/3007583_1.shtml" target=_self><span><font color=#ff7f00>SM4.0较SM3.0的改进</font></span></a> <br>　而在DirectX 10中引入了统一渲染架，通过一个整合Vertex Shader、 Pixel Shader的可编程整合光影处理器来完成目前Vertex Shader、Pixel Shader所有的工作。所谓统一渲染架构，最容易的理解方式就是Shader单元不再分离，显示核心不再为Shader类型不同而配置不同类型的Shader单元，对于主流的显示核心，Pixel Shader单元以及vertex Shader单元的概念都应该已经非常熟悉了，而在统一渲染架构中这两种Shader单元将不再分离，转而所有的Shader单元都可以为需要处理的数据进行处理，不管和是Pixel Shader数据还是Vertex Shader数据。
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_3.shtml" target=_blank></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 而调配哪几组Shader单元负责处理什么数据或者进行什么样子类型的计算，则由一个被称为small sets of instructions(SSI)的部分来控制。这样在硬件上，设计者就无需为不同的着色引擎设计不同的执行单元，只要按照所对应的接口以及操作方式全部融为一体，仅设置一种独立的Shader执行单元。这意味着GPU厂家可以用更小的核心来实现现在需要用8000万甚至更多晶体管才能实现的功能！</p>
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_4.shtml" target=_blank></a></p>
<p>　　相比原先的Shader Model 3.0，Shader Model 4.0最大指令数从512条增加到了64000条;临时暂存器数量也从原先的32个增加到惊人的4096个;允许同时对128个Texture进行操作(Shader Model 3.0只允许16个);材质texture格式变为硬件支持的RGBE格式，其中的"E"是Exponent的省略，是RGB共同的说明，这在HDR的处理上有很大的作用，摒弃了以往需要专门decoding处理HDR渲染的流程。 另外，对于纹理的尺寸Shader Model4.0也有惊人的提升，8192x8192的最高纹理分辩率比原先最高2048x2048的分辩率要高出4倍。G80图形核心对以上规格都给予了完整的硬件支持。<br><br><a href="http://www.impresswatch.com.cn/itwatch/83/3007583_2.shtml" target=_self><span><font color=#ff7f00>Shader Model4.0新特性</font></span></a> <br>　Shader Model 4.0另一个重大变化就是在VS和PS之间引入了一个新的可编程图形层----几何着色器(Geometry Shader)。原来的Vertex Shader和Pixel Shader只是对逐个顶点或像素进行处理，而新的Geometry Shader可以批量进行几何处理，快速的把模型类似的顶点结合起来进行运算。虽然其操作不会象Vertex Shader那样完整，只是处理器单个顶点的相关函数操作，但是这种操作却可以确定整个模型的物理形状。这将大大加速处理器速度，因为其它Shader单元将不再去需要判定数据所存在的位置，而只是需要简单的为特定区域进行操作就可以了。</p>
<p align=center>&nbsp;</p>
<p>　　Geometry Shader可以把点、线、三角等多边形联系起来快速处理、同时创造新的多边形，在很短时间内直接分配给其他Shader和显存而无需经过CPU，烟雾、爆炸等复杂图象不再需要CPU来处理。从而极大的提高了CPU速度和显卡速度。游戏图象中可以出现许多精细场景，如不锈钢茶壶上清楚的反射出周围物体、超精细的人物皮肤等。</p>
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_7.shtml" target=_blank></a></p>
<p>　　为了最大程度的发挥Geometry Shader的威力，DX10硬件还专门设置了一个名为流输出层(Stream Output State)的部件来配合它使用。这个层的功能是将Vertex Shader和Pixel Shader处理完成的数据输出给用户，由用户进行处理后再反馈给流水线继续处理。我们可以通过Stream Out把GPU拆成两段，只利用前面的一段几何运算单元。对某些科学研究，也许可以通过stream out来利用GPU的数学运算能力，等于在CPU之外又平白多得了一个数学协处理器。举个例子，Doom3常用的Stencil shadow，因为CPU负担很重，广受批评。但是因为GS可以计算轮廓线, 还可以动态插入新的多边形，有了Stream out之后，Shadow volume的生成就可以放到GPU端进行，实现Stencil shadow的硬件化，这将大大降低CPU占用。<br><br><a href="http://www.impresswatch.com.cn/itwatch/83/3007583_3.shtml" target=_self><span><font color=#ff7f00>统一着色架构</font></span></a> <br>在以前的DirectX版本中，像素着色器因为受到常量寄存器、可用指令和总体流程可的限制总是运行在顶点着色器之后，因此程序员必须学会怎样分别去利用好顶点和像素着色器的权限。Shader model 4.0则带来了与以往不同的统一着色架构，在DirectX 10基础上进行游戏开发，程序员不需要在避免着色冲突限制上花费时间，所有的统一架构着色器都能够使用GPU可以用的全部资源。</p>
<p align=center>&nbsp;</p>
<p>　　Shader model 4.0在着色器程序可用资源的提升方面让人激动，在以往的DirectX下，开发者不得不仔细计算可用的寄存器资源，而在DirectX 10中，这些问题都不复存在，如上表所示，总体上DirectX 10提供了超过10倍的DirectX 9可用资源。</p>
<p><a href="http://www.impresswatch.com.cn/itwatch/83/3007583_4.shtml" target=_self><span><font color=#ff7f00>更多的纹理和渲染</font></span></a> <br>Shader Model 4.0支持纹理队列集，把开发者从繁重的拼接纹理图集的工作中解放出来，并能够在每个着色器上使用更多的特殊纹理实现更好的视觉效果。</p>
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_12.shtml" target=_blank></a></p>
<p>　　在Shader Model 4.0之前，过高的开销使在一个着色器操作上使用多个特殊纹理的操作基本无法实现。为了解决这个问题，开发把许多小的分散的纹理拼接成一个大的纹理;在运行层中，着色器也需要进行额外的地址运算以便在拼接纹理图集中找到特定的纹理。纹理图集方式存在两个明显的缺点:首先小纹理之间的分界线回导致过滤操作错误;然后，DirectX 9的4096*4096纹理尺寸限制也是纹理图集的总体规模受到局限。纹理队列集能够解决所有问题，它能够使用队列格式存储纹理，每个队列能存储512同尺寸个纹理，最大的可用纹理尺寸也提升到8192*8192。为了促进这种应用，每个着色器可以操作的最大纹理数也提高到了128个，8倍于DirectX 9。</p>
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_13.shtml" target=_blank></a><a href="http://pic.yesky.com/syscore/489/419989d_13.shtml" target=_blank></a><a href="http://www.impresswatch.com.cn/TLimages/picview/impresspic.htm?/imagelist/06/50/74491vb3n7vm.jpg" target=_blank></a></p>
<p>　　更多的渲染对象<br>　　多重渲染对象是DirectX 9时代的一个流行特性，它允许每个像素着色周期输出4个不同的渲染结果，从而高效率的在一个周期内渲染一个场景的4遍。在DirectX 10中，渲染对象的数目提高到8，着极大的提高了着色器能实现的场景复杂程度，延迟渲染和其它一些图像空间优化算法将广泛的从中受益。<br><br><a href="http://www.impresswatch.com.cn/itwatch/83/3007583_5.shtml" target=_self><span><font color=#ff7f00>两种新的HDR格式</font></span></a> <br>　两种新的HDR格式<br>　　HDR(High dynamic range rendering)从支持浮点色彩格式的DirectX 9时代开始流行。不幸的是浮点格式比整数格式占用更多的寄存器空间而限制了其性能的发挥。如典型的FP16格式的每个色彩数据需要占用16bits，这两倍于整数格式的空间占用。</p>
<p align=center>&nbsp;</p>
<p align=center>&nbsp;</p>
<p>　　DirectX 10的新HDR格式能够在和FP16实现同样动态范围的前提下只占用50%的存储空间。第一种格式为R11G11B10，它使用11-bits的红色和绿色以及10-bits的蓝色来优化存储空间;第二种格式是使用一个5-bits共享首位存储所有色彩然后每个色彩拥有9-bits尾址，这些简化的方法在HDR品质上和标准的FP16几乎没有差别。在最高级别的HDR方面，DirectX 10支持FP32的HDR，这可以用于科学计算等对计算精度较高的应用程序。</p>
<p align=center><a href="http://pic.yesky.com/syscore/489/419989d_17.shtml" target=_blank></a><a href="http://www.impresswatch.com.cn/TLimages/picview/impresspic.htm?/imagelist/06/50/826jjs8m3i17.jpg" target=_blank></a></p>
<p>　　很显然，DirectX 10.0全新的Shader Model4.0对于消费者来说是一场全新的视觉革命，更逼真的3D游戏画面、流畅的高清视频回放是微软、显卡厂商推动技术发展的动力之源，在不远的将来我们就会体会到全新的DX10、SM4.0给我们带来的饕餮大餐。<br><br><br><br><br><br></p>
<img src ="http://www.cppblog.com/Leaf/aggbug/98781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2009-10-16 17:47 <a href="http://www.cppblog.com/Leaf/archive/2009/10/16/98781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>近期在研究Skeletal Animation（骨骼动画）</title><link>http://www.cppblog.com/Leaf/archive/2009/10/10/98274.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Sat, 10 Oct 2009 13:17:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2009/10/10/98274.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/98274.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2009/10/10/98274.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/98274.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/98274.html</trackback:ping><description><![CDATA[<p>&nbsp;骨骼动画一直是我感兴趣的内容.虽然采用现成的CSkinMesh能够使用XFile的骨骼动画.但对自己来说总感觉缺少了点什么.于是,还是深入理解理解为好!!!<br></p>
<span>ZDNet软件频道</span><strong>时间</strong>：<span>2008-03-24</span><span class=qu_laiyuan><strong>作者</strong>：Skyman | CSDN</span><br><span class=qu_keyword><strong>本文关键词：</strong><a title=骨骼动画） href="http://soft.zdnet.com.cn/files/list-0-0-149306-1-1.htm"><u><font color=#0000ff>骨骼动画）</font></u></a> <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><u><font color=#0000ff>Animation</font></u></a> <a title=Skeletal href="http://soft.zdnet.com.cn/files/list-0-0-149304-1-1.htm"><u><font color=#0000ff>Skeletal</font></u></a> <a title=游戏 href="http://soft.zdnet.com.cn/files/list-0-0-70668-1-1.htm"><u><font color=#0000ff>游戏</font></u></a> <a title=Linux href="http://soft.zdnet.com.cn/files/list-0-0-154112-1-1.htm"><u><font color=#0000ff>Linux</font></u></a> <br><br>骨骼动画(<a title=Skeletal href="http://soft.zdnet.com.cn/files/list-0-0-149304-1-1.htm"><font color=#000000>Skeletal</font></a> <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><font color=#000000>Animation</font></a>)又叫Bone <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><font color=#000000>Animation</font></a>，它与关键帧动画(Key-frame <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><font color=#000000>Animation</font></a>)相比，占用空间小，因为它不需要象关键帧动画那样要存储每一帧的各个顶点的数据，而是只需要存储每一帧的骨骼，骨骼与顶点相比，当然要少得多。所以骨骼动画有很多优势，当然其技术难度也很高。我个人觉得动画在计算机图形学中是一个十分重要的内容，不管是在<a title=游戏 href="http://soft.zdnet.com.cn/files/list-0-0-70668-1-1.htm"><font color=#000000>游戏</font></a>、电影动画还是虚拟现实中，生动逼真的动画（人、动物等）会使之增色不少。所以我决定今后的研究方向就是计算机动画。目前在研究<a title=Skeletal href="http://soft.zdnet.com.cn/files/list-0-0-149304-1-1.htm"><font color=#000000>Skeletal</font></a> <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><font color=#000000>Animation</font></a>，这是目前动画技术中的主流。欢迎同好与我交流，共同提高！
<p>&nbsp;&nbsp;&nbsp; 骨骼动画的实现思路是从我们人的身体的运动方式而来的（所以VR就是对现实世界的虚拟嘛 :-)）。动画人物的身体（肉、皮肤）是一个网格(Mesh)模型，网格的内部是一个骨架结构。当人物的骨架运动时，身体就会跟着骨架一起运动。骨架是由一定数目的骨骼组成的层次结构，每一个骨骼的排列和连接关系对整个骨架的运动有很重要的影响。每一个骨骼数据都包含其自身的动画数据。和每个骨架相关联的是一个&#8220;蒙皮&#8221;(Skin)模型，它提供动画绘制所需要的几何模型(Vertex,Normal,etc)和纹理材质信息。每个顶点都有相应的权值(Weight)，这些权值定义了骨骼的运动对有关顶点的影响因子。当把动画人物的姿势和全局运动信息作用到骨架上时，这个&#8220;蒙皮&#8221;模型就会跟随骨架一起运动。如下图所示：</p>
<p><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/skyman_2001/bone.jpg"></p>
<p>&nbsp;&nbsp;&nbsp; 所以关键是对骨架进行动画生成，生成的方法也是用关键帧。关键帧动画是对人物的网格(Mesh)模型采用关键帧生成动画；而骨骼动画则是对人物的骨架采用关键帧生成动画，然后再让网格(Mesh)模型跟随骨架运动。关键帧动画实现的2个关键点是：关键帧的选取和中间帧的插补。</p>
<p>&nbsp;&nbsp;&nbsp; 关键帧的指定有2种基本的方法：前向动力学(FK)和逆向动力学(IK)。前向动力学用一组节点的角度来找到末端受动器的位置；而逆向动力学则是找到将末端受动器置于所要位置所需的一组节点角度。前向动力学的优点是：计算简单，运算速度快，缺点是：需指定每个关节的角度和位置，而由于骨架的各个节点之间有内在的关联性，直接指定各关节的值很容易产生不自然协调的动作；逆向动力学的优点是：只需指定主要关节点的位置，负担轻，缺点是：计算模型比较复杂，开发者需要机械运动和动力学、几何学以及向量数学等方面的相关知识。</p>
<p>&nbsp;&nbsp;&nbsp; 中间帧的插值分2步：(1) 根据当前时间，通过插值计算出每个骨骼的旋转、平移等值，形成中间帧的骨架。插值算法一般采用四元数(Quternion)的球面线性插值(Spherical linear interpolation)SLERP，SLERP特别适合在两个方位之间进行插值，不会出现像对欧拉角插值那样出现万象锁的现象，而且这种插值能产生更平滑和连续的旋转，表达方式也很简洁；(2) 根据骨架的变化情况，插值计算出骨架的&#8220;蒙皮&#8221;模型的各个顶点的位置变化。对于某个特定骨骼，&#8220;蒙皮&#8221;模型的顶点变换矩阵＝初始姿势的变换矩阵的逆&#215;姿势变换后的矩阵。另外还要考虑顶点可能受多个骨骼运动的影响。这时我们对每个与当前顶点相关联的骨骼，将其运动姿势变换矩阵&#215;当前顶点相对于该骨骼的偏移向量&#215;该骨骼对当前顶点的影响因子（即权重Weight），对所有与当前顶点相关联的骨骼都这么处理，然后相加，就得到当前顶点的新位置。</p>
<p>&nbsp;&nbsp;&nbsp; 由此看出，如何设置各关键帧的骨架的各节点的位置和骨骼的转向（也就是骨架的POSE）是其中的关键，有2种方法：一种是由动画师手工放置，这个对动画师的技术要求就比较高，要求动画师对现实生活中的人和动物等的动作有细心的观察。否则设置的骨架动作就会不自然、不协调；另外一种是基于运动捕捉(Motion Capture)的方法，就是在人的各个关节处安置运动捕捉传感器，当人做各种动作时，捕捉仪器就将各节点的位置数据记录下来，这样我们就可以根据这些节点数据进行骨架建模。由于这是捕捉的真实的人的动作，所以这种方式得到的动画就很自然、很真实，但捕捉仪器造价昂贵，国内估计只有很少几家有财力的<a title=游戏 href="http://soft.zdnet.com.cn/files/list-0-0-70668-1-1.htm"><font color=#000000>游戏</font></a>公司才购置了这些设备吧。</p>
<p>&nbsp;&nbsp;&nbsp; 目前有好多3D模型格式支持<a title=Skeletal href="http://soft.zdnet.com.cn/files/list-0-0-149304-1-1.htm"><font color=#000000>Skeletal</font></a> <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><font color=#000000>Animation</font></a>，像Microsoft的.X格式、MilkShape的MS3D格式、Half Life的MDL格式、ID Software的MD5格式等。我准备首先研究一下MS3D格式，因为它有公开的格式说明文档，阅读起来比较容易，而且应用很广。当然，首先要深入学习<a title=Skeletal href="http://soft.zdnet.com.cn/files/list-0-0-149304-1-1.htm"><font color=#000000>Skeletal</font></a> <a title=Animation href="http://soft.zdnet.com.cn/files/list-0-0-149305-1-1.htm"><font color=#000000>Animation</font></a>的底层技术，打好坚实的基础，呵呵！</p>
<br></span>
<img src ="http://www.cppblog.com/Leaf/aggbug/98274.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2009-10-10 21:17 <a href="http://www.cppblog.com/Leaf/archive/2009/10/10/98274.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GPU中的ps 1.x 寄存器</title><link>http://www.cppblog.com/Leaf/archive/2009/09/12/95997.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Sat, 12 Sep 2009 05:36:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2009/09/12/95997.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/95997.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2009/09/12/95997.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/95997.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/95997.html</trackback:ping><description><![CDATA[<p>将就看吧，有些单词我实在不知道怎么翻译，只可意会！<br><br>像素着色器需要依靠寄存器来取得顶点数据，输出像素数据，取得计算时的临时结果和关联纹理采样通道（stage)。有几种类型的寄存器，每一种都有特殊的功能和用途。</p>
<p>像素着色器需要的用到的数据由寄存器保管，下面是寄器存的所有介绍<br>寄存器类型：描述了四种可用的寄存器和他们各自的用途<br>读取端口限制：单指针使用多个寄存器时的限制<br>R/RW： 描述了哪些寄存器可以用来读，写或是读写。<br>范围：各个分量的范围的详细说明</p>
<p>Register Types&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Versions&nbsp;&nbsp;&nbsp; <br>Name &nbsp;Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1_1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1_2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1_3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1_4 <br>c# &nbsp;Constant register&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 8 <br>r# &nbsp;Temporary register&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;6 <br>t# &nbsp;Texture register&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 6 <br>v# &nbsp;Color register&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 2 in phase 2 </p>
<p>1，常量寄存器：常量寄存器容纳了常量数据。数据可以用IDirect3DDevice9::SetPixelShaderConstantF函数将一个常量装入常量寄存器中。也可以用def-ps来定义一个常量。 常量寄存器对纹理寻址指令来说是不可用的，唯一例外的是texm3x3spec-ps指令，这个指令使用一个常量寄存器来提供一个视线向量（eye-ray vector）</p>
<p>2，临时寄存器：临时寄存器用来存立即结果。r0用来作为PS的最终输出。shader的最后时刻r0中存放的是最后的像素颜色值<br>如果任何的着色器试图从一个没有被写入数据的临时寄存器中读取数据时，着色器激IDirect3DDevice9::CreatePixelShader将会失败（shader validation will fail）。假设激活（validation）是可用状态D3DXAssembleShader函数调用也会因为相同的原因而失败。（不要使用D3DXSHADER_SKIPVALIDATION）</p>
<p>纹理寄存器：<br>在ps 1_1 到1_3中，纹理寄存器容纳纹理数据或是纹理坐标。当一个纹理被采样时，纹理数据便被装载到一个纹理寄存器中。<br>当纹理通道状态属性被登记的时候纹理采样使用纹理坐标来查询（look up)或采样(sample)一个纹理坐标（u,v,w,q)标记的颜色值。纹理坐标数据会根据顶点纹理坐标数据进行插值，并关联到相关的纹理通道。纹理通道号与纹理坐标声明序列有一个一一对应关系。默认情况下，顶点格式中定义的第一个纹理坐标与纹理通道0关联。<br>&nbsp;在这些版本的像素着色器中，当纹理寄存器用来做算术运算的时候就和临时寄存器的效果一样了。<br>在ps_1_4中，纹理寄存器(t#)容纳的是只读纹理坐标信息。这意味着纹理坐标集和纹理通道编号是独立的。纹理通道编号由目的寄存器（r0 to r5)决定。对于texld指令来说，纹理坐标集由源寄存器t0 to t5决定。因此纹理坐标集可以映射到任何的纹理通道上。另外，对于texld的源寄存器（指定纹理坐标信息）也可以是临时寄存器(r#)。在这样的情况下，临时寄存器记录纹理坐标。<br>颜色寄存器容纳了每个像素的颜色值，这个值通过顶点数据中的漫反射和镜面光颜色值迭代而来。对于ps_1_4。颜色寄存器只有在phase2中可用。如果着色模式设置为D3DSHADE_FLAT,那么顶点颜色中的颜色迭代将不可用。如果雾化开启的话，那么渲染管线还是会忽略着色模式，对雾进行颜色迭代。记住雾化比像素着色器后应用。<br>通常我们会从v0加载顶点漫反射颜色数据。从v1加载顶点镜面光颜色数据。<br>输入颜色数据值将会被规范到0和1，因为这是像素着色器中的颜色寄存器的有效范围</p>
<p>像素着色器对颜色寄存器进行只读操作。颜色寄存器中存放的是迭代值，但是迭代可能会造成比纹理坐标低很多精度</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/Leaf/aggbug/95997.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2009-09-12 13:36 <a href="http://www.cppblog.com/Leaf/archive/2009/09/12/95997.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>per-pixel lighting 纹理空间坐标基的计算方法 </title><link>http://www.cppblog.com/Leaf/archive/2009/04/17/80299.html</link><dc:creator>Render Donkey</dc:creator><author>Render Donkey</author><pubDate>Fri, 17 Apr 2009 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/Leaf/archive/2009/04/17/80299.html</guid><wfw:comment>http://www.cppblog.com/Leaf/comments/80299.html</wfw:comment><comments>http://www.cppblog.com/Leaf/archive/2009/04/17/80299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Leaf/comments/commentRss/80299.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Leaf/services/trackbacks/80299.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p style="FONT-FAMILY: 方正姚体">&nbsp;</p>
<p style="FONT-FAMILY: 方正姚体">文章来源：<a href="http://www.freegames.com.cn/school/383/2007/27685.html">http://www.freegames.com.cn/school/383/2007/27685.html</a><br>Nemesis2k<br>per-pixel lighting 纹理空间坐标基的计算方法 </p>
<p style="FONT-FAMILY: 方正姚体">我知道的几种方法：</p>
<p style="FONT-FAMILY: 方正姚体">1. 对于参数化的表面，设其方程为 P = P (u, v)，其中 P 为向量，<br>三个分量分别为 x, y z。也可以表示为：<br>Px = Px (u ,v)<br>Py = Py (u ,v)<br>Pz = Pz (u ,v)<br>那在任意一个顶点<br>T = {dPx/du, dPy/du, dPz/du}<br>B = {dPx/dv, dPy/dv, dPz/dv}<br>N = T X B<br>然后把 T, B, N 归一化就行了。<br>这里的偏导数可以用差分计算。<br>这样计算出来的切空间是在每一个顶点的切空间。</p>
<p style="FONT-FAMILY: 方正姚体">2。对于由三角形面片组成的网格，在 MSDN 上的 Per-pixel lighting<br>文章里介绍了一种方法。<br>设三角形的三个顶点是 P0, P1, P2，其中每个顶点都有位置，法向量<br>和 2-D 纹理坐标。<br>Pi : {x, y, z}, {nx, ny, nz}, {s, t}<br>现在我们要计算在 P0 点的切空间。<br>这里要分辨两个切空间：<br>1）顶点上的切空间 <br>2）三角形面片上的切空间<br>两个切空间是相同的吗？我觉得是不同的。方法 2 和方法 3 计算出来的<br>实际上都是三角形面片的切空间，顶点的切空间还要通过平均顶点所在<br>各个三角形面片的切空间基向量来计算。（是这样的吗？高手指教一下！）</p>
<p style="FONT-FAMILY: 方正姚体">设三角形面片所在的切空间的基向量为 T, B, N，坐标原点在 P0。<br>那么三角形面片中的任意向量应该可以表示为：<br>Vec = x*T + y*B<br>因此，如果我们找到了两个向量 Vec1, Vec2 以及它们在 T, B 上的<br>分量，那么自然就可以解出 T, B 了。<br>令： <br>Vec1 = P1 - P0<br>Vec2 = P2 - P0<br>dS1 = P1.s - P0.s<br>dS2 = P2.s - P0.s<br>dT1 = P1.t - P0.t<br>dT2 = P2.t - p0.t<br>那么我们有<br>Vec1 = dS1*T + dT1*B (1)<br>Vec2 = dS2*T + dT2*B (2)<br>联立 (1), (2) 就可以解出<br>B*(dS2*dT1 - dS1*dT2) = (dS2*Vec1 - dS1*Vec2)<br>所以：<br>(dS2*dT1 - dS1*dT2) 是一个常数，反正我们之后要对 B 归一化，<br>可以不用管它。于是：<br>B = normalize(dS2*Vec1 - dS1*Vec2) 这就是 MSDN 里那篇文章里的方法。<br>B 可以通过解方程获得，但是 T 就不行了，因为这样解出来的 T 和<br>B 不一定垂直。怎么处理呢？<br>MSDN 中的方法是，利用顶点的 N 来求 T：<br>T = B X N<br>然后再求 N<br>N = T X B<br>但是这样可以吗？这里的 N 是顶点 P0 的 N，而不是三角形面片的 N。<br>是不是这样求出来的 T, N, B 恰好是顶点 P0 的切空间的坐标基，不需要<br>再平均了？（高手指教！）<br>我想的处理方法是这样的：<br>同样解出 T 来：<br>T = normalize(dT2*Vec1 - dT1*Vec2)<br>然后 N = T X B。这个 N 是三角形面片的 N。<br>然后 T = B X N。这样 T, N, B 构成正交基，而且是三角形面片的。<br>要计算 P0 顶点的切空间基，还需要平均多个面片。<br>这种方法到是比较复杂。</p>
<p style="FONT-FAMILY: 方正姚体">一个问题是，为什么有<br>Vec1 = dS1*T + dT1*B (1)<br>Vec2 = dS2*T + dT2*B (2)<br>这两个公式！<br>我想是因为在计算顶点的纹理坐标时，因为是从平面映射到平面，所以我们使用了<br>仿射变换：<br>s = as*x + bs*y + cs<br>t = as*x + bs*y + cs<br>反过来我们有<br>x = ax*s + bx*t + cx (3)<br>y = ay*s + by*t + cy (4)<br>z = az*s + bz*t + cz (5)<br>于是<br>Vec1.x = P1.x - P0.x = ax*(P1.s - P0.s) + bx*(P1.t - P0.t)<br>Vec1.y = P1.y - P0.y = ay*(P1.s - P0.s) + by*(P1.t - P0.t)<br>Vec1.z = P1.z - P0.z = az*(P1.s - P0.s) + bz*(P1.t - P0.t)<br>于是<br>Vec1 = {ax, ay, az}*dS1 + {bx, by, bz}*dT1<br>这和 (1) 已经很象了，那么 {ax, ay, az} 就是 T 吗？<br>答案是是的！事实上 (3), (4), (5) 就是三角形面片的参数表示，那么<br>T = {dx/ds, dy/ds, dz/ds} = {ax, ay, az}<br>B = {dx/dt, dy/dt, dz/dt} = {bx, by, bz}<br>也就是说，如果我们能直接把 ax, ay, az, bx, by, bz 求出来，T 和 B 就求出来了</p>
<p style="FONT-FAMILY: 方正姚体">（当然要把他们正交归一化）</p>
<p style="FONT-FAMILY: 方正姚体">3 nVidia 网站上的方法。<br>我们可以假设<br>x = ax*s + bx*t + cx <br>y = ay*s + by*t + cy <br>z = az*s + bz*t + cz <br>如何求解 (3) ？这里有 3 个未知数，那我们需要 3 个方程。<br>将 3 个顶点的属性 {x, y ,z}, {s, t} 带入，刚好有三个方程：<br>P0.x = ax*P0.s + bx*P0.t + cx (1)<br>P1.x = ax*P1.s + bx*P1.t + cx (2)<br>P2.x = ax*P2.s + bx*P2.t + cx (3)<br>解出来就得到 ax, bx, cx 了。<br>同理可得： ay, by, cy, az, bz, cz。<br>T = {ax, ay, az}<br>B = {bx, by, bz}<br>N = T X B<br>T = B X N<br>然后都归一化即可。</p>
<p style="FONT-FAMILY: 方正姚体">nVidia 网站上的方法呢，是建立三个平面方程<br>Ax*x + Bx*s + Cx*t + Dx = 0 (4)<br>Ay*y + By*s + Cy*t + Dy = 0 (5)<br>Az*z + Bz*s + Cz*t + Dz = 0 (6)</p>
<p style="FONT-FAMILY: 方正姚体">并且指出，三角形面片上的所有点的 (x, s, t) 都在 <br>方程 (4) 定义的平面中。那么<br>dx/ds = -Bx/Ax<br>dx/dt = -Cx/Ax</p>
<p style="FONT-FAMILY: 方正姚体">同理<br>dy/ds = -By/Ay<br>dy/dt = -Cy/Ay</p>
<p style="FONT-FAMILY: 方正姚体">dz/ds = -Bz/Az<br>dz/dt = -Cz/Az</p>
<p style="FONT-FAMILY: 方正姚体">那么这些 Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz 怎么求呢？<br>容易知道，{Ax, Bx, Cx} 其实是平面的法向量，那么可以<br>选平面中的三个点，计算出两个向量，然后叉乘。</p>
<p style="FONT-FAMILY: 方正姚体">{Ax, Bx, Cx} = {P1.x - P0.x, P1.s - P0.s, P1.t - P0.t} X<br>{P2.x - P0.x, P2.s - P0.s, P2.t - P0.t} </p>
<p style="FONT-FAMILY: 方正姚体">这两种方法是等价的。 <br></p>
<img src ="http://www.cppblog.com/Leaf/aggbug/80299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Leaf/" target="_blank">Render Donkey</a> 2009-04-17 21:45 <a href="http://www.cppblog.com/Leaf/archive/2009/04/17/80299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>