﻿<?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++博客-学习一下-记录一下-随笔分类-D3D</title><link>http://www.cppblog.com/hello8706/category/14209.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 26 Feb 2011 00:21:00 GMT</lastBuildDate><pubDate>Sat, 26 Feb 2011 00:21:00 GMT</pubDate><ttl>60</ttl><item><title>渲染到纹理（转）</title><link>http://www.cppblog.com/hello8706/archive/2011/02/24/140574.html</link><dc:creator>小火球</dc:creator><author>小火球</author><pubDate>Thu, 24 Feb 2011 02:39:00 GMT</pubDate><guid>http://www.cppblog.com/hello8706/archive/2011/02/24/140574.html</guid><wfw:comment>http://www.cppblog.com/hello8706/comments/140574.html</wfw:comment><comments>http://www.cppblog.com/hello8706/archive/2011/02/24/140574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hello8706/comments/commentRss/140574.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hello8706/services/trackbacks/140574.html</trackback:ping><description><![CDATA[<div>RTT是现在很多特效里面都会用到的一项很基本的技术，实现起来很简单，也很重要。但是让人不解的是网上搜索了半天只找到很少的文章说这个事儿，不知道是因为太简单还是因为这项技术已经出现很长时间了。总之我是在摸索这个东西的时候绕了不少弯子。现在把具体的实现方法写下来。<br><br>渲染到纹理，顾名思义就是把渲染目标从帧缓存变成一个纹理。这样就可以把一个场景渲染后在进行Post Process，做出现在流行的各种特效。另外在利用GPU做通用计算的时候程序也是通过RTT和GPU交换数据的。<br><br>实现步骤：<br>
<ol>
    <li>声明变量<br><font size=2>LPDIRECT3DTEXTURE9 pRenderTexture = NULL; // 目标纹理<br>LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL, pTempSurface;<br>// pRenderSurface是pRenderTexture 对应的Surface<br>// pBackBuffer用于保存原来的Render Target</font><br>
    <li><font size=2>创建一个纹理作为渲染目标(Render Target)<br>//注意这里的第三个参数必须为</font><font size=2>D3DUSAGE_RENDERTARGET<br>//第四个参数决定纹理的格式，不同的场景会要求不同的格式</font><br><font size=2>pd3dDevice-&gt;CreateTexture(TEX_WIDTH,TEX_HEIGHT,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&amp;pRenderTexture,NULL);<br><br>//获得</font><font size=2>pRenderTexture对应的Surface</font><br><font size=2>pRenderTexture-&gt;GetSurfaceLevel(0,&amp;pRenderSurface);<br></font>
    <li><font size=2>渲染场景<br></font><font size=2>//这里保存下原来的Render target，在做完RTT后再恢复</font><br><font size=2>pd3dDevice-&gt;GetRenderTarget(0,&amp;pBackBuffer);<br>if( SUCCEEDED( pd3dDevice-&gt;BeginScene() ) )<br>{<br>//设置我们的纹理为render target<br>pd3dDevice-&gt;SetRenderTarget(0, pRenderSurface);<br>pd3dDevice-&gt;Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DXCOLOR(0.0f,0.00f,0.00f,1.00f), 1.0f, 0);<br><br><br>//重新将render target设置为帧缓存<br>pd3dDevice-&gt;SetRenderTarget(0, pBackBuffer);<br><br>pd3dDevice-&gt;EndScene();<br>pBackBuffer-&gt;Release();<br>}</font>
    <li><font size=2>善后<br>SAFE_RELEASE(pRenderSurface);<br>SAFE_RELEASE(pRenderTexture);</font> </li>
</ol>
这里需要注意的几点：<br>
<ul>
    <li>渲染的时候要选择正确的纹理格式。如果你要在纹理里面保存高精度浮点数的话。通常所用的A8R8G8B8格式每一个颜色分量只有8位，只能表示0-255。详情可以参考DirectX SDK Help中关于D3DFORMAT的说明。
    <li>如果你的纹理长宽比和帧缓存的不同的话，那么你需要在切换RenderTarget以后重新设置投影矩阵。否则渲染出来的图像会被拉伸。
    <li>纹理的大小不能太大。经过试验发现是在窗口模式下面窗口和纹理的大小不能超过屏幕减去任务栏的大小。如果超过的话似乎对纹理的任何操作都不会有效果。
    <li>如果想要验证自己渲染出来的纹理是否正确，可以用D3DXSaveTextureToFile把纹理保存为图像。
    <li>如果想要直接访问纹理中的值则要麻烦一些。按照SDK文档里面的说法，作为RenderTarget的纹理是保存在显存上面的，无法lock与unlock。要向访问其中的值需要做如下操作：<br>LPDIRECT3DTEXTURE9 text;<br>LPDIRECT3DSURFACE9 surf;<br>D3DLOCKED_RECT lockbits;<br>pd3dDevice-&gt;CreateTexture(TEX_WIDTH,TEX_HEIGHT,1,0,D3DFMT_R5G6B5, D3DPOOL_SYSTEMMEM, &amp;text, NULL);<br>text-&gt;GetSurfaceLevel(0,&amp;surf);<br>if (pd3dDevice-&gt;GetRenderTargetData(pRenderSurface, surf) == D3D_OK)<br>if (surf-&gt;LockRect(&amp;lockbits, NULL, D3DLOCK_READONLY) == D3D_OK)<br>{<br>pRenderSurface-&gt;UnlockRect();<br>float* bits=(float*)(lockbits.pBits);<br>// SAVE BITS TO TEXT FILE<br>FILE* ofile = fopen("output.txt", "w");<br>for (int i=0; i&lt;64; i++)<br>{<br>for (int j=0; j&lt;64; j++)<br>fprintf(ofile, "(%2.2f,%2.2f,%2.2f) ", bits[i*64*4+j*4], bits[i*64*4+j*4+1], bits[i*64*4+j*4+2]);<br>fprintf(ofile, "\n");<br>}<br>fclose(ofile);<br>}<br>text-&gt;Release();<br>surf-&gt;Release(); </li>
</ul>
<br>这个技术可以用来在多通道渲染中传递渲染结果。比如可以把RTT出来的结果用来作为第二编渲染中的纹理来使用，这样可以实现水面反射等效果。另外在通用计算中可以用来保存数据。例如可以把GPU数值计算以后的结果保存在纹理中，再用上面所说的方法把数字读出来（如果真要这么做的话别忘了把纹理格式设置为足够大精度的格式，比如说A32B32G32R32F)。<br><br>文章引用自：<a href="http://ping.csdn.net/tag/hlsl/" target=_blank>http://ping.csdn.net/tag/hlsl</a><a href="http://ping.csdn.net/tag/hlsl/" target=_blank>/</a><br></div>
<img src ="http://www.cppblog.com/hello8706/aggbug/140574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hello8706/" target="_blank">小火球</a> 2011-02-24 10:39 <a href="http://www.cppblog.com/hello8706/archive/2011/02/24/140574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>d3d资源管理（转）</title><link>http://www.cppblog.com/hello8706/archive/2011/02/22/140468.html</link><dc:creator>小火球</dc:creator><author>小火球</author><pubDate>Tue, 22 Feb 2011 14:06:00 GMT</pubDate><guid>http://www.cppblog.com/hello8706/archive/2011/02/22/140468.html</guid><wfw:comment>http://www.cppblog.com/hello8706/comments/140468.html</wfw:comment><comments>http://www.cppblog.com/hello8706/archive/2011/02/22/140468.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hello8706/comments/commentRss/140468.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hello8706/services/trackbacks/140468.html</trackback:ping><description><![CDATA[<p>资源锁定意味着能通过CPU来访问该资源。锁定选项有以下几种：</p>
<p>D3DLOCK_DISCARD, D3DLOCK_READONLY, and D3DLOCK_NOOVERWRITE 等，但是只有这三种是经常使用的。运行时并不会</p>
<p>检查应用程序是否遵循了制定的锁定标记所规定的访问方式。也就是说，当指定了D3DLOCK_READONLY后，再去写资源操作，会得到意外的结果，但不会提示是由于写操作导致出错。所以，如果在实际资源访问时的操作与锁定选项相矛盾的话，则无法保证以后的释放操作会成功或发生显著的性能损失。</p>
<p>同时只能对纹理资源加一把锁。在对表面进行锁操作时，不能对该表面进行任何其他的加速操作。</p>
<p>对顶点 buffer&nbsp; 和 索引 buffer资源可以同时加几把锁，但是必须保证加解锁数配对。</p>
<p>资源管理就是把系统内存中的内容提交到显存或者把显存中的内容剔除掉的过程。</p>
<p>Direct3D run time 有自己的管理算法 least-recently-used priority 技术。当检测到在一帧中需要同时共存的资源要多与显存限制时，</p>
<p>d3d就会切换到 most-recently-used priority 技术。</p>
<p>创建资源时使用&nbsp; D3DPOOL_DEFAULT&nbsp; 标记，意味着资源被放在最合适该资源的存储区。经常会被放在显存或AGP中。在defalut pool</p>
<p>中的资源在设备丢失后要被全部释放，在设备重建后要全部恢复。</p>
<p>创建资源时使用D3DPOOL_MANAGED 标记，即该资源是托管资源，该资源在设备丢失后还继续存在，该资源同时存在于内存和显存中，当需要显示时，由内存拷贝到显存中。但是当设备被销毁或重新create 时，所有的资源都会被释放和重建。</p>
<p>d3d所谓的资源管理，是针对 D3DPOOL_MANAGED&nbsp; 来说的。对于顶点buffer和索引buffer不建议使用 D3DPOOL_MANAGED&nbsp; ，即不建议使用d3d默认的资源管理，因为 D3DPOOL_MANAGED&nbsp; 标记的资源会在系统内存中存在备份，而顶点buffer和索引buffer如果使用D3DPOOL_MANAGED&nbsp; 来创建，该类缓冲的特点要求会在系统内存和显存之间进行大量频繁的数据拷贝，会极大的影响性能。所以这两种buffer建议使用&nbsp; D3DPOOL_DEFAULT&nbsp; 结合&nbsp; D3DUSAGE_DYNAMIC 来使用。</p>
<p>另外还有一种情况是不能使用 D3DPOOL_MANAGED&nbsp; 的，那就是创建作为 RenderTarget 的纹理时，如果该种纹理被标记为了托管，意味着该纹理在内存中存在了备份，在渲染期间，它的内容就会在系统内存和显存之间产生大量的数据交换，造成极大的性能损失。因此，renderTarget 的纹理资源必须被创建在&nbsp; D3DPOOL_DEFAULT&nbsp; 中。如果CPU需要存取该内容，则数据可以通过下面两种方法拷贝到D3DPOOL_SYSTEMMEM 定义的资源中，IDirect3DDevice9::UpdateTexture, or IDirect3DDevice9::UpdateSurface。</p>
<p>正如前面所提到的，当时使用托管方式创建资源时，就不能使用动态方式，如果同时使用这两种标记会引起性能极大损失。动态顶点buffer是被设计用来绘制动态的数据的，这些数据可能由BSP树或者其他的空间划分算法获取到的。根据应用程序自身的资源管理方式而不是d3d的，这些资源被打包，以支持应用程序的需要。动态顶点buffer的数量会很少，因为应用程序同时只允许少量的不同的顶点步长，而只有当步长不同时才有必要创建新的顶点buffer。当我们以这种方式管理动态资源时，才能保证性能不会损失。</p>
<p>当创建资源时，尽量使用D3DPOOL_DEFAULT方式，这使我们能对系统内存和显存的使用情况能有准确的把握。</p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/cainiao_liu/archive/2010/02/07/5295808.aspx">http://blog.csdn.net/cainiao_liu/archive/2010/02/07/5295808.aspx</a></p>
<img src ="http://www.cppblog.com/hello8706/aggbug/140468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hello8706/" target="_blank">小火球</a> 2011-02-22 22:06 <a href="http://www.cppblog.com/hello8706/archive/2011/02/22/140468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>纹理过滤</title><link>http://www.cppblog.com/hello8706/archive/2010/12/10/136107.html</link><dc:creator>小火球</dc:creator><author>小火球</author><pubDate>Fri, 10 Dec 2010 14:14:00 GMT</pubDate><guid>http://www.cppblog.com/hello8706/archive/2010/12/10/136107.html</guid><wfw:comment>http://www.cppblog.com/hello8706/comments/136107.html</wfw:comment><comments>http://www.cppblog.com/hello8706/archive/2010/12/10/136107.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hello8706/comments/commentRss/136107.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hello8706/services/trackbacks/136107.html</trackback:ping><description><![CDATA[<p><font face=Arial>纹理过滤</font></p>
<p><font face=Arial>　　Direct3D渲染一个图元时，会将三维图元映射到二维屏幕上。如果图元有纹理，Direct3D就必须用纹理来产生图元的二维渲染图象上每个像素的颜色。对于图元在二维屏幕上图象的每个像素来说，都必须从纹理中获得一个颜色值。我们把这一过程称为纹理过滤（texture filtering）。</font></p>
<p><font face=Arial>　　进行纹理过滤时，正在使用的纹理通常也正在被进行放大或缩小。换句话说，这个纹理将被映射到一个比它大或小的图元的图象上。纹理的放大会导致许多像素被映射到同一个纹理像素上。那么结果看起来就会使矮矮胖胖的。纹理的缩小会导致一个像素被映射到许多纹理像素上。其结果将会变得模糊或发生变化。要解决这些问题，我们可以将一些纹理像素颜色融合到一个像素颜色上。</font></p>
<p><font face=Arial>　　Direct3D提供了一些方法来简化纹理过滤的过程。它提供了三种类型的纹理过滤：线性过滤（linear filtering）、各向异性过滤（anisotropic filtering）和mipmap过滤（mipmap filtering）。如果不选择纹理过滤，Direct3D还会使用一种叫做最近点采样（nearest point sampling）的技术。</font></p>
<p><font face=Arial>　　每种类型的纹理过滤都有各自的优缺点。例如，线性过滤会产生锯齿状的边缘和矮胖的效果。但是，它对系统的消耗却是最小的。另一方面，mipmap过滤的效果通常是最好的，特别是和各项异性过滤混合使用时。但是它却需要很大的内存消耗。</font></p>
<p><font face=Arial>　　如果程序使用纹理句柄，可以调用IDirect3DDevice3::SetRenderState方法来设置当前的纹理过滤方法，同时要将第一个参数设置为D3DRENDERSTATE_TEXTUREMAG或D3DRENDERSTATE_TEXTUREMIN，第二个参数要设置为D3DTEXTUREFILTER枚举类型的一个成员。</font></p>
<p><font face=Arial>　　程序也可以使用纹理接口指针来设置纹理过滤方法，这是要调用IDirect3DDevice3::SetTexture平台State方法，并将第一个参数设置为要进行纹理过滤的那个纹理的整数索引号（0-7），将第二个参数设置为D3DTSS_MAGFILTER、D3DTSS_MINFILTER或D3DTSS_MIPFILTER，将第三个参数设置为D3DTEXTUREMAGFILTER、D3DTEXTUREMINFILTER或D3DTEXTUREMIPFILTER枚举类型的一个成员。</font></p>
<p><font face=Arial>　　下面我们来分别讨论几种纹理过滤方法：</font></p>
<p><font face=Arial>4.1 最近点采样 <br>4.2 线性纹理过滤 <br>4.3 各向异性纹理过滤 <br>4.4 mipmap纹理过滤 <br>　</font></p>
<p><font face=Arial>4.1 最近点采样</font></p>
<p><font face=Arial>　　在程序中，我们并不是必须要使用纹理过滤。Direct3D可以被设置来计算纹理像素的地址，这个地址通常不是一个整数值，这时，可以简单的取一个与它最接近的整数地址来代替原地址，并使用这个整数地址上的纹理像素颜色。我们把这一过程称为最近点采样（nearest point sampling）。当纹理的大小与图元图象的大小差不多时，这种方法非常有效和快捷。如果大小不同，纹理就需要进行放大或缩小，这样，结果就会变得矮胖、变形或模糊。</font></p>
<p><font face=Arial>　　调用IDirect3DDevice3::SetTexture平台State方法可以来选择最近点采样方法，将它的第一个参数设置为纹理的整数平台索引号(0-7)，第二个参数设置为D3DTEXTUREMAGFILTER、D3DTEXTUREMIPFILTER或D3DTEXTUREMIPFILTER，将第三个参数设置为D3DTFG_POINT（设置放大过滤时）、D3DTFN_POINT（缩小时）或D3DTFP_POINT（mipmap时）。</font></p>
<p><font face=Arial>　　使用最近点采样是要特别小心，因为在两个纹理像素的分界线上进行采样时，可能产生图象失真（graphic artifacts）。在进行采样时，系统会选择这个采样纹理像素或者是那个采样纹理像素，在穿越分界线时，得到的结果将会产生很大的变化，也许会得到我们不想要的结果。（在使用线性过滤时，当纹理索引穿越两个纹理像素的边界时，最终的纹理像素将会是这两个纹理像素的融合结果。）</font></p>
<p><font face=Arial>　　当我们将一个很小的纹理映射到一个很大的多边形上——这被称为&#8220;放大（magnification）&#8221;——时，我们会看到这种效果。例如，当我们使用一个看起来象西洋跳棋盘一样的纹理时，最近顶采样会得到一个更大的西洋跳棋盘，并带有明显的边界；而采用线性过滤时，最后在多边形上，跳棋格颜色会平滑的进行过渡，不会有明显的边界出现。</font></p>
<p><font face=Arial>　　大多数时候，不使用最近点采样往往能得到最好的结果。并且在现在，大部分的硬件都是针对线性过滤进行优化的。如果你确实想得到最近顶采样那样的效果——比如要清晰的显示一些文本特征——那么就要尽量避免在纹理像素分界处进行采样，否则，就会产生图象的失真。下图中向我们展示了一种图象的失真： </font></p>
<p><font face=Arial></font>&nbsp;</p>
<p><font face=Arial>　　注意上面的两个靠右的方格，它们就产生了失真。要避免这样的失真，我们首先要了解Direct3D最近点采样的规则。Direct3D是将一个浮点纹理坐标，范围为[0.0, 1.0]（包括它们），映射到一个整数的纹理像素空间，范围为[&#8211;0.5, n&#8211;0.5]，n是一个给定大小的纹理中纹理像素的数量。最终的纹理索引是最近的整数。这样的映射会导致在纹理像素分界处进行采样。</font></p>
<p><font face=Arial>　　下面我们来看一个例子，我们使用D3DTADDRESS_WRAP纹理寻址模式来对多边形进行渲染，使用Direct3D提供的映射对一个有4个纹理像素宽度的纹理进行映射，u纹理索引如下： </font></p>
<p><font face=Arial></font>&nbsp;</p>
<p><font face=Arial>　　注意图中的纹理坐标0.0和1.0，它们正好在两个纹理像素的分界处。更具最近点采样法的规则，纹理坐标的范围为[&#8211;0.5, 4&#8211;0.5]，4是纹理的宽度。这样，被采样的纹理像素就是第0个纹理像素，它的纹理索引值就为1.0。但是，如果纹理坐标只比1.0小一点，那么被采样的纹理像素就应该是第n个而不是第0个。</font></p>
<p><font face=Arial>　　这也就表示在将一个小的纹理使用最近点采样方法放大映射到屏幕空间时，会产生在纹理像素分界处采样的情况，这样就会产生失真。</font></p>
<p><font face=Arial>　　要将浮点纹理坐标映射到整数纹理像素上是很困难的，并且通常也没有必要这样做。大多数硬件在执行时使用一种迭代的方法来计算每个像素位置上的纹理坐标。这种方法往往会隐藏这些错误，因为它们在迭代过程中会逐渐积累起来。 </font></p>
<p><font face=Arial>　　Direct3D参考光栅使用直接估计（direct-evaluation）的方法来计算每个像素位置上的纹理索引。与迭代法不同，直接估计过程中的一些错误会比较自由的表现出来。这样，在使用最近点采样时出现的错误就会比较明显。</font></p>
<p><font face=Arial>　　我们最好只在必需时再使用最近点采样法。在使用它时，最好能使纹理坐标明显的偏离纹理像素的分界处。</font></p>
<p><font face=Arial>　</font></p>
<p><font face=Arial>4.2 线性纹理过滤</font></p>
<p><font face=Arial>　　Direct3D使用的线性过滤方法是双线性过滤（bilinear filtering）。和最近点采样一样，双线性过滤首先要计算一个纹理像素的地址，这个地址通常不是整数地址。然后，找到一个地址最接近的整数地址纹理像素。另外，Direct3D渲染模块还要计算与最近采样的点相邻的四个纹理像素的加权平均（weighted average）。</font></p>
<p><font face=Arial>　　可以调用IDirect3DDevice3::SetTexture平台State方法来选择双线性纹理过滤，并将第一个参数设置为纹理的整数索引号(0-7)，将第二个参数设置为D3DTEXTUREMAGFILTER、D3DTEXTUREMIPFILTER或D3DTEXTUREMIPFILTER，将第三个参数设置为D3DTFG_LINEAR（放大）、D3DTFN_LINEAR（缩小）或D3DTFP_LINEAR（mipmap）。</font></p>
<p><font face=Arial>　</font></p>
<p><font face=Arial>4.3 各向异性纹理过滤</font></p>
<p><font face=Arial>　　各向异性是对一个三维物体纹理像素的可见的变形，这个物体的表面朝向屏幕平面，并与之有一定的角度。各向异性图元的像素在映射到纹理像素时，它的形状会发生变形。Direct3D用反映射到纹理空间的屏幕像素的延伸率（长度/宽度）来度量一个像素的各向异性（anisotropy）。</font></p>
<p><font face=Arial>　　各向异性纹理过滤可以和线性过滤或mipmap过滤联合使用。调用IDirect3DDevice3::SetTexture平台State方法可以使各项异性过滤有效，同时要将第一个参数设置为纹理的整数索引值(0-7)，将第二个参数设置为D3DTEXTUREMAGFILTER、D3DTEXTUREMINFILTER，将第三个参数设置为D3DTFG_ANISOTROPIC（放大）或D3DTFN_ANISOTROPIC（缩小）。</font></p>
<p><font face=Arial>　　程序还要调用IDirect3DDevice3::SetTexture平台State方法将各向异性度（degree of anisotropy）设置在0到1之间（不包含它们），同时将诶一个参数设置为纹理的整数索引值(0-7)，将第二个参数设置为D3DTSS_MAXANISOTROPY，最后一个参数就是各向同性度（degree of isotropy）。</font></p>
<p><font face=Arial>　　将各向同性度（degree of isotropy）设置为1将使各向同性过滤无效（设置为任何比1大的值将会使它有效）。检查D3DPRIMCAPS结构中的D3DPRASTERCAPS_ANISOTROPY标志，以确定各向异性度的可能的范围。</font></p>
<p><font face=Arial>　</font></p>
<p><font face=Arial>4.4 Mipmap纹理过滤</font></p>
<p><font face=Arial>　　Mipmap纹理技术用来降低场景渲染的时间消耗。同时也提高了场景的真实感。但它的缺点是要占用大量的内存空间。</font></p>
<p><font face=Arial>　　下面我们来讨论mipmap纹理技术的有关内容： </font></p>
<p><font face=Arial>4.4.1 什么是mipmap <br>4.4.2 创建一系列mipmap <br>4.4.3 选择和显示Mipmap <br>　</font></p>
<p><font face=Arial>4.4.1 什么是mipmap？</font></p>
<p><font face=Arial>　　一个mipmap就是一系列的纹理，每一幅纹理都与前一幅是相同的图样，但是分辨率都要比前一幅有所降低。mipmap中的每一幅或者每一级图象的高和宽都比前一级小二分之一。Mipmap并不一定必须是正方形。</font></p>
<p><font face=Arial>　　高分辨率的mipmap图象用于接近观察者的物体。当物体逐渐远离观察者时，使用低分辨率的图象。Mipmap可以提高场景渲染的质量，但是它的内存消耗却很大。</font></p>
<p><font face=Arial>　　Direct3D将mipmap描绘成一系列相互联系的表面。高分辨率的纹理位于开始处，并与下一级纹理相互联系。以此类推，纹理相互联系，逐渐排列到分辨率最小的一级。</font></p>
<p><font face=Arial>　　下面这套插图显示了这样的一个例子。这套纹理是一个三维场景中一个集装箱的标签。当我们创建了一个mipmap时，分辨率最高的一幅纹理就是这一套纹理的第一个。这套mipmap中的每一个纹理宽高都是前一个纹理宽高的二分之一。这样，最大分辨率的纹理是256x256，接下来的纹理就是128x128，最后一个纹理就是64x64。</font></p>
<p><font face=Arial>　　我们有一个能看到这个标签的最大距离。如果观察者从远处向标签走近，那么场景中首先会显示最小的一幅纹理，它的大小是64x64的。</font></p>
<p><font face=Arial></font>&nbsp;</p>
<p><font face=Arial>　　当观察者走进标签时，我们就使用更高分辨率一幅纹理： </font></p>
<p><font face=Arial></font>&nbsp;</p>
<p><font face=Arial>　　当观察者走到允许的最近距离时，我们使用分辨率最高的那幅纹理：</font></p>
<p><font face=Arial></font>&nbsp;</p>
<p><font face=Arial>　　这是方法能够模拟纹理的透视效果并能够减少处理时的计算量。与将一幅纹理用于不同的分辨率相比，这种方法更加快速。</font></p>
<p><font face=Arial>　　Direct3D能够访问mipmap中与我们想要输出的分辨率最接近的那个纹理设置，并将像素映射到它的纹理像素空间中。如果最终图象的分辨率在mipmap纹理的分辨率的中间，那么Direct3D会对两幅纹理中的纹理像素进行检查，并将它们的颜色值进行融合。</font></p>
<p><font face=Arial>　　如果要使用mipmap，首先要创建一套mipmap。详细内容见&#8220;创建一系列mipmap&#8221;。如果程序使用的使纹理句柄，那么就必须将mipmap选择作为当前纹理。如果使用纹理接口指针，那么就要将mipmap选择作为当前纹理设置中的第一个纹理。详细内容见&#8220;多纹理融合&#8221;。 </font></p>
<p><font face=Arial>接下来，程序要设置用来对纹理像素采样的过滤方法。Mipmap过滤最快的方法就是让Direct3D选择最近的纹理像素。我们用D3DTFP_POINT枚举值来选择这一方法。如果程序使用D3DTFP_LINEAR枚举值，可以得到更好的过滤效果。它会选择最近的mipmap，然后找到当前像素映射在纹理中的位置，计算这个位置周围纹理像素的加权平均。</font></p>
<p><font face=Arial>　</font></p>
<p><font face=Arial>4.4.2 创建一系列Mipmap</font></p>
<p><font face=Arial>　　要创建一个表示mipmap中某一级的表面，需要在DDSURFACEDESC结构中声明DDSCAPS_MIPMAP和DDSCAPS_COMPLEX标志，并将这个结构传递给IDirectDraw4::CreateSurface方法。由于所有的mipmap也是纹理，因此也要声明DDSCAPS_TEXTURE标志。</font></p>
<p><font face=Arial>　　我们也可以自己来创建mipmap中的每一级，然后使用IDirectDrawSurface4::AddAttachedSurface方法将它们链接在一起。但是我们并不推荐使用这样的方法。许多3-D硬件都对IDirectDraw4::CreateSurface方法优化了它们的驱动程序。因此，通过调用IDirectDrawSurface4::AddAttachedSurface来建立mipmap链接的程序可能会发现mipmapping没有想象中的那么快捷。</font></p>
<p><font face=Arial>　　下面的例子向我们展示了如何使用IDirectDraw4::CreateSurface方法来创建一个mipmap链接，这个mipmap分为5级，大小分别为256&#215;256、128&#215;128、64&#215;64、32&#215;32和16&#215;16：</font></p>
<font face=Arial>
<p><br>// This code fragment assumes that the variable lpDD is a<br>// valid pointer to a DirectDraw interface.</p>
<p>DDSURFACEDESC ddsd; <br>LPDIRECTDRAWSURFACE4 lpDDMipMap; <br>ZeroMemory(&amp;ddsd, sizeof(ddsd)); <br>ddsd.dwSize = sizeof(ddsd); <br>ddsd.dwFlags = DDSD_CAPS | DDSD_MIPMAPCOUNT; <br>ddsd.dwMipMapCount = 5; <br>ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; <br>ddsd.dwWidth = 256UL; <br>ddsd.dwHeight = 256UL; </p>
<p>ddres = lpDD-&gt;CreateSurface(&amp;ddsd, &amp;lpDDMipMap); <br>if (FAILED(ddres)) <br>　&#8230;&#8230;　&#8230;&#8230;　</p>
<p>&nbsp;</p>
<p>　　在用IDirectDraw4::CreateSurface方法创建一系列表面时，我们可以忽略mipmap的级数，这样每一级都是前一级大小的二分之一，直到最小的尺寸大小为止。我们也可以忽略高和宽，这样IDirectDraw4::CreateSurface就会创建我们所声明的级数，并将最小一级的大小设为1&#215;1。</p>
<p>注：一个mipmap链接中的每一个表面的大小都是链接中前一个表面大小的二分之一。如果一mipmap中最顶端一级的大小为256&#215;128，那么第二级的大小就是128&#215;64，第三级为64&#215;32，直到2&#215;1为止。如果你声明了dwWidth和dwHeight成员的大小，就要注意一些限制条件。也就是要注意，在dwMipMapCount中声明的级数大小不能使任何一级mipmap的高或宽的值小于1。我们来看一个简单的最顶端一级大小为4&#215;2的mipmap表面：dwMipMapCount所允许的最大值为2。任何大于2的值都会使高或宽变成小数，这是不允许的。</p>
<p>　　创建了mipmap表面之后，需要将表面与一个纹理相互联系起来。如果使用纹理句柄，就可以使用前面在&#8220;创建一个纹理句柄&#8221;中介绍的方法。如果使用的是纹理接口指针，请看&#8220;获得一个纹理接口指针&#8221;部分。</p>
<p>　</p>
<p>4.4.3 选择并显示Mipmap</p>
<p>　　如果程序使用纹理句柄，就要将mipmap纹理的句柄指派为当前纹理。详细内容见&#8220;当前纹理&#8221;部分。</p>
<p>　　如果程序使用纹理接口指针，就要将mipmap纹理设置作为当前纹理列表的第一个纹理。详细内容见&#8220;多纹理融合&#8221;部分。</p>
<p>　　程序选择了mipmap纹理设置之后，it must assign values from the D3DTEXTUREFILTER enumerated type to the D3DRENDERSTATE_TEXTUREMAG and D3DRENDERSTATE_TEXTUREMIN render states.然后，Direct3D会自动执行mipmap纹理过滤。</p>
<p>　　程序也可以自己来设置mipmap表面的链接，这是要使用IDirectDrawSurface4::GetAttachedSurface方法，并要在DDSCAPS结构中声明DDSCAPS_MIPMAP和DDSCAPS_TEXTURE标志。下面的例子中展示了这一过程：</p>
<p><br>LPDIRECTDRAWSURFACE lpDDLevel, lpDDNextLevel; <br>DDSCAPS ddsCaps; <br>HRESULT ddres;</p>
<p>lpDDLevel = lpDDMipMap; <br>lpDDLevel-&gt;AddRef(); <br>ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; <br>ddres = DD_OK; <br>while (ddres == DD_OK) <br>{ <br>　// Process this level. <br>　ddres = lpDDLevel-&gt;GetAttachedSurface( &amp;ddsCaps, &amp;lpDDNextLevel); <br>　lpDDLevel-&gt;Release(); <br>　lpDDLevel = lpDDNextLevel; <br>} </p>
<p>if ((ddres != DD_OK) &amp;&amp; (ddres != DDERR_NOTFOUND)) <br>{<br>　// Code to handle the error goes here<br>}</p>
<p>&nbsp;</p>
<p>　　程序还需要自己实现一个mipmap链接来将位图数据加载到链接中的每一个表面。</p>
<p>　　Direct3D会明确保存一个mipmap链接中的级数。当程序获得一个mipmap的表面描述时（调用IDirectDrawSurface4::Lock或IDirectDrawSurface4::GetSurfaceDesc方法），DDSURFACEDESC结构的dwMipMapCount成员就获得了mipmap的级数，包括最顶端一级。对于mipmap中的那些不是最顶端的级来说，dwMipMapCount成员详细说明了链接中的级数。</p>
<p></font><font size=3 face=Arial>&nbsp;</p>
<p align=justify><font size=3 face=宋体></font></p>
</font>
<img src ="http://www.cppblog.com/hello8706/aggbug/136107.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hello8706/" target="_blank">小火球</a> 2010-12-10 22:14 <a href="http://www.cppblog.com/hello8706/archive/2010/12/10/136107.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>旋转：矩阵，四元数和欧拉角向量 </title><link>http://www.cppblog.com/hello8706/archive/2010/07/22/121032.html</link><dc:creator>小火球</dc:creator><author>小火球</author><pubDate>Thu, 22 Jul 2010 06:49:00 GMT</pubDate><guid>http://www.cppblog.com/hello8706/archive/2010/07/22/121032.html</guid><wfw:comment>http://www.cppblog.com/hello8706/comments/121032.html</wfw:comment><comments>http://www.cppblog.com/hello8706/archive/2010/07/22/121032.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hello8706/comments/commentRss/121032.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hello8706/services/trackbacks/121032.html</trackback:ping><description><![CDATA[<h2>旋转：矩阵，四元数和欧拉角向量 </h2>
<p>3D引擎中最常见坐标变换是旋转。有几种方式可以实现旋转：矩阵，四元数和角度向量（角度或弧度）。最精确和限制最小的方式是将他们存储在矩阵中。矩阵是一个数学概念，它是一个以行和列形式组织的矩形数学块。当这些数字以正确的顺序与另一个矩阵或数字或引擎中最常见的点进行计算时，就可以改变对应的值。</p>
<p>例如，一个变换矩阵只是将一个点移动到三维空间，这很简单。其他更为复杂的矩阵，比如旋转矩阵可以通过将一个点的坐标设置为新位置使点旋转。当然这只在与一个平移矩阵组合时有用，因为旋转一个（0，0，0）的是不会平移的。如果我们在旋转后再平移，我们将向正确的方向移动。最后一个常见矩阵是缩放矩阵，它只是将缩放到一个特定的尺寸。</p>
<p>现在我们知道了矩阵的工作原理，但我们如何使用它们？好吧，如果你一直在看我写的游戏引擎教程，那么你已经在使用矩阵了。I3DComponent有一个旋转矩阵存储了旋转量，在绘制模型时会计算另外两个位置和缩放向量。这可能是存储位置和缩放的最简单的方法。Vector的三个分量能储存点的三个坐标信息（即点的位置），同理也适用于缩放，我们可以为每个坐标轴存储一个标量。但如何处理旋转？</p>
<p>那么，现在的问题是用一个向量的三个分量存储旋转是错误的做法。这里我不会讨论细节，你只需知道这通常是一个非常不好的主意。</p>
<p>不幸的是，虽然&#8220;最好&#8221;的方法是用矩阵表示旋转，但这对普通人来说比较抽象。没有人愿意在更新对象的旋转量时计算矩阵中的16个值。最简单的方法是用一个Vector3表示围绕每根坐标轴的旋转量，然后在转化为矩阵（我们将这种Vector3称为欧拉角矢量）。显然我们不想一直做这件事，但如果只用于手工地设置一个变量（如在一个游戏编辑器中）它还是工作良好的。有许多方法可以在矩阵和欧拉角之间转换，但它们并不完美。下面我将详细讲述最可靠的方式。这个想法来自与XNA官方网站的论坛上：<a href="http://forums.xna.com/forums/p/4574/23763.aspx"><u><font color=#0000ff>http://forums.xna.com/forums/p/4574/23763.aspx</font></u></a> </p>
<h3>矩阵和欧拉角之间的相互转换</h3>
<p>从欧拉角矢量转换很容易，困难的部分是转换回来。XNA提供了一个方法可以创建旋转矩阵，但它并没有提供转换回来的方法，因此我们将不得不自己实现。</p>
<p>首先，我们转换为旋转矩阵，Matrix.CreateFromYawPitchRoll()方法可以做到这一点。如果这里使用欧拉角，我们需要以以下顺序提供坐标：</p>
<ul>
    <li>Yaw（偏航）：欧拉角向量的y轴
    <li>Pitch（俯仰）：欧拉角向量的x轴
    <li>Roll（翻滚）： 欧拉角向量的z轴 </li>
</ul>
<p>想象一下飞机，yaw指水平方向的机头指向，它绕y轴旋转。Pitch指与水平方向的夹角，绕x轴旋转。Roll指飞机的翻滚，绕z轴旋转。下面的代码演示了这一过程：</p>
<pre><span>// Converts a rotation vector into a rotation matrix</span>
Matrix Vector3ToMatrix<span>(</span>Vector3 Rotation<span>)</span>
<span>{</span>
<span>return</span> Matrix.<span>CreateFromYawPitchRoll(</span>Rotation.<span>Y</span>, Rotation.<span>X</span>, Rotation.<span>Z)</span>;
<span>}</span></pre>
<p>这种方法可以提供一个表示旋转的矩阵。下面是最难的部分：将矩阵转换为欧拉角。</p>
<p>这个过程是将矩阵拆散：一个表示位置的Vecto3，另一个表示缩放，而四元数表示旋转。然后，我们必须将这个四元数转换为一个欧拉角矢量。我不打算详细讨论代码背后的数学原理，但如果你有兴趣，可以到前面链接中的网址上去看看。</p>
<p>下面是将旋转矩阵转换为欧拉角的代码。</p>
<pre><span>// Returns Euler angles that point from one point to another</span>
Vector3 AngleTo<span>(</span>Vector3 from, Vector3 location<span>)</span>
<span>{</span>
Vector3 angle <span>=</span> <span>new</span> Vector3<span>()</span>;
Vector3 v3 <span>=</span> Vector3.<span>Normalize(</span>location <span>-</span> from<span>)</span>;
angle.<span>X</span> <span>=</span> <span>(float)</span>Math.<span>Asin(</span>v3.<span>Y)</span>;
angle.<span>Y</span> <span>=</span> <span>(float)</span>Math.<span>Atan2((double)-</span>v3.<span>X</span>, <span>(double)-</span>v3.<span>Z)</span>;
<span>return</span> angle;
<span>}</span>
<span>// Converts a Quaternion to Euler angles (X = Yaw, Y = Pitch, Z = Roll)</span>
Vector3 QuaternionToEulerAngleVector3<span>(</span>Quaternion rotation<span>)</span>
<span>{</span>
Vector3 rotationaxes <span>=</span> <span>new</span> Vector3<span>()</span>;
Vector3 forward <span>=</span> Vector3.<span>Transform(</span>Vector3.<span>Forward</span>, rotation<span>)</span>;
Vector3 up <span>=</span> Vector3.<span>Transform(</span>Vector3.<span>Up</span>, rotation<span>)</span>;
rotationaxes <span>=</span> AngleTo<span>(new</span> Vector3<span>()</span>, forward<span>)</span>;
<span>if</span> <span>(</span>rotationaxes.<span>X</span> <span>==</span> MathHelper.<span>PiOver2)</span>
<span>{</span>
rotationaxes.<span>Y</span> <span>=</span> <span>(float)</span>Math.<span>Atan2((double)</span>up.<span>X</span>, <span>(double)</span>up.<span>Z)</span>;
rotationaxes.<span>Z</span> <span>=</span> 0;
<span>}</span>
<span>else</span> <span>if</span> <span>(</span>rotationaxes.<span>X</span> <span>==</span> <span>-</span>MathHelper.<span>PiOver2)</span>
<span>{</span>
rotationaxes.<span>Y</span> <span>=</span> <span>(float)</span>Math.<span>Atan2((double)-</span>up.<span>X</span>, <span>(double)-</span>up.<span>Z)</span>;
rotationaxes.<span>Z</span> <span>=</span> 0;
<span>}</span>
<span>else</span>
<span>{</span>
up <span>=</span> Vector3.<span>Transform(</span>up, Matrix.<span>CreateRotationY(-</span>rotationaxes.<span>Y))</span>;
up <span>=</span> Vector3.<span>Transform(</span>up, Matrix.<span>CreateRotationX(-</span>rotationaxes.<span>X))</span>;
rotationaxes.<span>Z</span> <span>=</span> <span>(float)</span>Math.<span>Atan2((double)-</span>up.<span>Z</span>, <span>(double)</span>up.<span>Y)</span>;
<span>}</span>
<span>return</span> rotationaxes;
<span>}</span>
<span>// Converts a Rotation Matrix to a quaternion, then into a Vector3 containing</span>
<span>// Euler angles (X: Pitch, Y: Yaw, Z: Roll)</span>
Vector3 MatrixToEulerAngleVector3<span>(</span>Matrix Rotation<span>)</span>
<span>{</span>
Vector3 translation, scale;
Quaternion rotation;
Rotation.<span>Decompose(out</span> scale, <span>out</span> rotation, <span>out</span> translation<span>)</span>;
Vector3 eulerVec <span>=</span> QuaternionToEulerAngleVector3<span>(</span>rotation<span>)</span>;
<span>return</span> eulerVec;
<span>}</span></pre>
<p>应当指出的是，所有的旋转信息都使用弧度。要获得角度（如果与你共事的人不习惯于弧度：比如他不是一个程序员或数学家）可以使用MathHelper.ToDegrees()方法，角度到弧度可使用MathHelper.ToRadians()方法。当处理旋转时请不要忘了转换： </p>
<pre>Vector3 RadiansToDegrees<span>(</span>Vector3 Vector<span>)</span>
<span>{</span>
<span>return</span> <span>new</span> Vector3<span>(</span>
MathHelper.<span>ToDegrees(</span>Vector.<span>X)</span>,
MathHelper.<span>ToDegrees(</span>Vector.<span>Y)</span>,
MathHelper.<span>ToDegrees(</span>Vector.<span>Z))</span>;
<span>}</span>
Vector3 DegreesToRadians<span>(</span>Vector3 Vector<span>)</span>
<span>{</span>
<span>return</span> <span>new</span> Vector3<span>(</span>
MathHelper.<span>ToRadians(</span>Vector.<span>X)</span>,
MathHelper.<span>ToRadians(</span>Vector.<span>Y)</span>,
MathHelper.<span>ToRadians(</span>Vector.<span>Z))</span>;
<span>}</span></pre>
<p>您可以通过在对象中设置属性使用这些旋转矩阵的功能，可以使处理起来更简单：</p>
<pre><span>public</span> Vector3 EulerRotation
<span>{</span>
get <span>{</span> <span>return</span> RadiansToDegrees<span>(</span>MatrixToEulerAngleVector3<span>(</span>Rotation<span>))</span>; <span>}</span>
set <span>{</span> Rotation <span>=</span> Vector3ToMatrix<span>(</span>DegreesToRadians<span>(</span>value<span>))</span>; <span>}</span>
<span>}</span></pre>
<img src ="http://www.cppblog.com/hello8706/aggbug/121032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hello8706/" target="_blank">小火球</a> 2010-07-22 14:49 <a href="http://www.cppblog.com/hello8706/archive/2010/07/22/121032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>D3DPRESENT_PARAMETERS结构</title><link>http://www.cppblog.com/hello8706/archive/2010/07/09/119829.html</link><dc:creator>小火球</dc:creator><author>小火球</author><pubDate>Fri, 09 Jul 2010 02:03:00 GMT</pubDate><guid>http://www.cppblog.com/hello8706/archive/2010/07/09/119829.html</guid><wfw:comment>http://www.cppblog.com/hello8706/comments/119829.html</wfw:comment><comments>http://www.cppblog.com/hello8706/archive/2010/07/09/119829.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hello8706/comments/commentRss/119829.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hello8706/services/trackbacks/119829.html</trackback:ping><description><![CDATA[<p><font color=#0000ff>BackBufferWidth：全屏幕式后备缓冲的宽度<br>BackBufferHeight ：全屏幕式后备缓冲的高度 <br>BackBufferFormat： 后备缓冲的格式<br>BackBufferCount： 后备缓冲数目<br>MultiSampleType： 全屏抗锯齿类型<br>MultiSampleQuality： 全屏抗锯齿质量等级<br>SwapEffect： 交换缓冲类型<br>hDeviceWindow： 设备窗口句柄<br>Windowed： 全屏或窗口<br>EnableAutoDepthStencil： 激活深度缓冲<br>AutoDepthStencilFormat： 深度缓冲格式<br>FullScreen_RefreshRateInHz： 显示器刷新率<br>PresentationInterval： 图像最大刷新速度</font></p>
<p>&#160;</p>
<div class=cnt>
<p><font color=#0000ff>typedef struct _D3DPRESENT_PARAMETERS_ {<br>&nbsp;&nbsp;&nbsp; UINT BackBufferWidth, BackBufferHeight;<br>&nbsp;&nbsp;&nbsp; D3DFORMAT BackBufferFormat;<br>&nbsp;&nbsp;&nbsp; UINT BackBufferCount;<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_TYPE MultiSampleType;<br>&nbsp;&nbsp;&nbsp; DWORD MultiSampleQuality;<br>&nbsp;&nbsp;&nbsp; D3DSWAPEFFECT SwapEffect;<br>&nbsp;&nbsp;&nbsp; HWND hDeviceWindow;<br>&nbsp;&nbsp;&nbsp; BOOL Windowed;<br>&nbsp;&nbsp;&nbsp; BOOL EnableAutoDepthStencil;<br>&nbsp;&nbsp;&nbsp; D3DFORMAT AutoDepthStencilFormat;<br>&nbsp;&nbsp;&nbsp; DWORD Flags;<br>&nbsp;&nbsp;&nbsp; UINT FullScreen_RefreshRateInHz;<br>&nbsp;&nbsp;&nbsp; UINT PresentationInterval;<br>} D3DPRESENT_PARAMETERS;</font></p>
<p><font color=#0000ff>BackBufferWidth：全屏幕式后备缓冲的宽度<br>BackBufferHeight ：全屏幕式后备缓冲的高度<br>BackBufferFormat： 后备缓冲的格式<br>BackBufferCount： 后备缓冲数目<br>MultiSampleType： 全屏抗锯齿类型<br>MultiSampleQuality： 全屏抗锯齿质量等级<br>SwapEffect： 交换缓冲类型<br>hDeviceWindow： 设备窗口句柄<br>Windowed： 全屏或窗口<br>EnableAutoDepthStencil： 激活深度缓冲<br>AutoDepthStencilFormat： 深度缓冲格式<br>FullScreen_RefreshRateInHz： 显示器刷新率<br>PresentationInterval： 图像最大刷新速度</font></p>
<p><font color=#0000ff>BackBufferWidth和BackBufferHeight：后备缓冲的宽度和高度。在全屏模式下，这两者的值必需符合显卡所支持的分辨率。例如（800，600），（640，480）。<br>BackBufferFormat：后备缓冲的格式。这个参数是一个D3DFORMAT枚举类型，它的值有很多种，例如D3DFMT_R5G6B5、D3DFMT_X8R8G8B8为游戏后备缓冲常用格式，这说明后备缓冲的格式是每个像素16位，其实红色（R）占5位，绿色（G）占6位，蓝色（B）占5位，为什么绿色会多一位呢？据说是因为人的眼睛对绿色比较敏感。DX9只支持16位和32位的后备缓冲格式，24位并不支持。如果对这D3DFORMAT不熟悉的话，可以把它设为D3DFMT_UNKNOWN，这时候它将使用桌面的格式。</font></p>
<p><font color=#0000ff>BackBufferCount：后备缓冲的数目，范围是从0到3，如果为0，那就当成1来处理。大多数情况我们只使用一个后备缓冲。使用多个后备缓冲可以使画面很流畅，但是却会造成输入设备响应过慢，还会消耗很多内存。<br>MultiSampleType 和MultiSampleQuality：前者指的是全屏抗锯齿的类型，后者指的是全屏抗锯齿的质量等级。这两个参数可以使你的渲染场景变得更好看，但是却消耗你很多内存资源，而且，并不是所有的显卡都支持这两者的所设定的功能的。在这里我们分别把它们设为D3DMULTISAMPLE_NONE和0。<br>可以通过CheckDeviceMultiSampleType 来检测当前装置是否支持某个抗锯齿类型<br>typedef enum _D3DMULTISAMPLE_TYPE<br>{<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_NONE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_2_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 2,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_3_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 3,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_4_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_5_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 5,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_6_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 6,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_7_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 7,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_8_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 8,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_9_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 9,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_10_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 10,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_11_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 11,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_12_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 12,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_13_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 13,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_14_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 14,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_15_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 15,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_16_SAMPLES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 16,<br>&nbsp;&nbsp;&nbsp; D3DMULTISAMPLE_FORCE_DWORD&nbsp;&nbsp;&nbsp;&nbsp; = 0x7fffffff<br>} D3DMULTISAMPLE_TYPE;<br>//type 为以上的枚举值<br>D3DMULTISAMPLE_TYPE type;<br>int quality; //获取相对于type的最大质量等级（设置type抗拒值类型时，设置的质量等级只能小于这个数）<br>//m_d3dBackFmt 为后备缓冲格式,m_bWindowed 是否为窗口模式,<br>m_pD3D9-&gt;CheckDeviceMultiSampleType( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,m_d3dBackFmt, m_bWindowed,type,&amp;quality );</font></p>
<p><font color=#0000ff>SwapEffect：交换缓冲支持的效果类型，指定表面在交换链中是如何被交换的。它是D3DSWAPEFFECT枚举类型，可以设定为以下三者之一：D3DSWAPEFFECT_DISCARD，D3DSWAPEFFECT_FLIP，D3DSWAPEFFECT_COPY。<br>如果设定为D3DSWAPEFFECT_DISCARD，则后备缓冲区的东西被复制到屏幕上后,后备缓冲区的东西就没有什么用了,可以丢弃（discard 是否丢弃由显卡决定，但不再等待）了。<br>如果设定为D3DSWAPEFFECT_FLIP，后备缓冲拷贝到前台缓冲，保持后备缓冲内容不变。当后备缓冲大于1个时使用<br>设定D3DSWAPEFFECT_COPY的话， 后备缓冲拷贝到前台缓冲，保持后备缓冲内容不变。当后备缓冲等于1个时使用<br>一般我们是把这个参数设为D3DSWAPEFFECT_DISCARD。如果想使用GetBackBuffer 获得后备缓冲内容打印屏幕画面。则不能使用DISCARD.<br>很怀疑用DISCARD效率会好的说法。在我的8600GT 上_COPY 明显好于DISCARD. discard 做法是再次使用后备缓冲时 new 一个新的缓冲，旧的缓冲内容遗弃，如果还有使用旧的缓冲地方，不会影响新的内容，如使用抗锯齿必须是DISCARD。这样不用等待硬件同步。不过大部分是一次Present操作。用COPY在新机器上面反倒效率好些。毕竟new 一个 1440*900 的后台缓冲也是有消耗的。（对于DISCARD 做法仅仅是猜测。不同显卡可能不同。）<br>hDeviceWindow：显示设备输出窗口的句柄<br>Windowed：如果为FALSE，表示要渲染全屏。如果为TRUE，表示要渲染窗口。渲染全屏的时候，BackBufferWidth和BackBufferHeight的值就得符合显示模式中所设定的值。<br>EnableAutoDepthStencil：如果要使用Z缓冲或模板缓冲，则把它设为TRUE。<br>AutoDepthStencilFormat：如果不使用深度缓冲，那么这个参数将没有用。如果启动了深度缓冲，那么这个参数将为深度缓冲设定缓冲格式。常用值D3DFMT_24S8 (24 深度缓冲，8模板缓冲),D3DFMT_24X8(24 深度缓冲),D3DFMT_16（16深度缓冲）等等。<br>//深度缓存和模板缓存的象素格式,如 D3DFMT_D24S8 , 24 位表示深度，8位为模板缓存。一般不会用到32位深度：D3DFMT_32<br>//注意如果设置模板缓冲在Clear() 函数中也要清楚模板缓冲：设置参数 D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL</font></p>
<p><font color=#0000ff>Flags：通常为0 或D3DPRESENTFLAG_LOCKABLE_BACKBUFFER。不太清楚是用来做什么的，看字面好像是一个能否锁定后备缓冲区的标记。D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL 丢弃模板缓冲区<br>FullScreen_RefreshRateInHz：显示器的刷新率，单位是HZ，如果设定了一个显示器不支持的刷新率，将会不能创建设备或发出警告信息。为了方便，一般设为D3DPRESENT_RATE_DEFAULT就行了。<br>PresentationInterval：如果设置为D3DPRENSENT_INTERVAL_DEFAULT，则说明在显示一个渲染画面的时候必要等候显示器刷新完一次屏幕。例如你的显示器刷新率设为80HZ的话，则一秒内你最多可以显示80个渲染画面。另外你也可以设置在显示器刷新一次屏幕的时间内显示1到4个画面。如果设置为 D3DPRENSENT_INTERVAL_IMMEDIATE，则表示可以以实时的方式来显示渲染画面，虽然这样可以提高帧速（FPS），如果速度过快却会产生图像撕裂的情况，但当游戏完成时，帧速度一般不会过快。</font></p>
</div>
<img src ="http://www.cppblog.com/hello8706/aggbug/119829.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hello8706/" target="_blank">小火球</a> 2010-07-09 10:03 <a href="http://www.cppblog.com/hello8706/archive/2010/07/09/119829.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>