几何体
Microsoft® Direct3D®支持几种处理几何体的高级抽象。它们被分为以下主题。
顶点缓存,由IDirect3DVertexBuffer9接口表示,是包含顶点数据的内存缓冲区。顶点缓存可以包含任何顶点类型——经过变换的或未经变换的,经过光照处理或未经光照处理的——它们可以使用IDirect3DDevice9接口的渲染方法进行渲染。应用程序可以在顶点缓存中处理顶点,执行诸如变换、光照或生成裁剪标志的操作。变换操作总是被执行。
顶点缓存的灵活性使之成为重用经过变换的几何体的完美中转站。可以创建单个顶点缓存,在其中执行变换、光照和裁剪操作,并根据需要在场景中多次渲染该建模,即使在这之间渲染状态变了,无需重新进行变换。这在渲染使用多重纹理的建模时非常有用:几何体只被变换一次,然后可以根据需要渲染各个部分,如果有必要,期间可以改变纹理。顶点被处理后渲染状态的改变会在下一次顶点被处理时生效。
顶点缓存由它的能力描述:是否只能存在于系统内存中,是否只能用于写操作,以及所能包含的顶点的类型和数量。所有这些特性都保存在D3DVERTEXBUFFER_DESC结构中。
为了表明是一个顶点缓存,Format成员要被设为D3DFMT_VERTEXDATA。Type成员表示顶点缓存的资源类型。Usage成员包含了综合能力标志。D3DUSAGE_SOFTWAREPROCESSING标志表示顶点缓存被用于软件顶点处理。D3DUSAGE_WRITEONLY标志表示顶点缓存只用于写操作。这使驱动程序可以自由地将顶点数据放到最合适的内存位置并进行快速处理和渲染。如果没有使用D3DUSAGE_WRITEONLY标志,驱动程序不太可能将数据放在读操作效率很低的地方。这牺牲了一些处理时间和渲染速度。如果没有指定该标志,那么系统会假定应用程序将对顶点缓存中的数据执行读写操作。
Pool成员指定为顶点缓存分配内存的类型。D3DPOOL_SYSTEMMEM标志指示系统在系统内存中创建顶点缓存。
Size成员存储了顶点缓存数据的大小,以字节为单位。FVF成员包含了D3DFVF的组合,用来识别缓存包含顶点的类型。
应用程序可以使用IDirect3DDevice9::CreateVertexBuffer方法创建顶点缓存,该方法接收池(内存类型)和用途参数。IDirect3DDevice9::CreateVertexBuffer也可以用一个指定的FVF码创建顶点缓存,以用于固定功能顶点处理或作为顶点处理的输出。更多细节,请参阅FVF顶点缓存。
当在设备上启用了混合模式或软件顶点处理(D3DCREATE_MIXED_VERTEXPROCESSING / D3DCREATE_SOFTWARE_VERTEXPROCESSING)时,可以设置D3DUSAGE_SOFTWAREPROCESSING标志。在混合模式中,要进行软件顶点处理的缓存必须设置D3DUSAGE_SOFTWAREPRECESSING标志,但在使用硬件顶点处理(D3DCREATE_HARDWARE_VERTEXPROCESSING)时,为了得到尽可能好的性能,不应设置该标志。但是,当一个缓存要同时进行硬件和软件顶点处理时,设置D3DUSAGE_SOFTWAREPROCESSING是唯一的选择。和软件设备一样,混合设备也可以使用D3DUSAGE_SOFTWAREPROCESSING。
即使顶点处理是用硬件完成的,通过指定D3DPOOL_SYSTEMMEM,把顶点和索引缓存强制分配到系统内存中也是可以的。当驱动程序将这些缓存放在AGP内存中时,这种方法可以避免大量的页面锁定内存。
本节介绍了一些概念,这些概念是理解顶点缓存以及在Microsoft® Direct3D®应用程序中使用顶点缓存所必需了解的。信息被分为以下部分。
应用程序应该通过调用IDirect3DDevice9::CreateVertexBuffer方法创建一个顶点缓存对象,该方法接收五个参数。第一个参数指定缓存的长度,以字节为单位。可以用sizeof操作符确定某一顶点格式的大小。考虑以下自定义顶点格式。
struct CUSTOMVERTEX {
FLOAT x, y, z;
FLOAT rhw;
DWORD color;
FLOAT tu, tv; // 纹理坐标
};
// 自定义FVF,描述了自定义顶点的结构
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW |
D3DFVF_DIFFUSE | D3DFVF_TEX1)
要创建一个可以保存四个CUSTOMVERTEX结构的顶点缓存,应该把Length参数指定为[4*sizeof(CUSTOMVERTEX)]。
第二个参数是一组用途控制标志。该参数的值特别用来决定对那些位于视区外的顶点,顶点缓存是否能包含裁剪信息——以裁剪标志的形式。要创建一个不能包含裁剪标志的顶点缓存,应该在Usage参数中包含D3DUSAGE_DONOTCLIP标志。只有在应用程序指明顶点缓存将包含经过变换的顶点——FVF参数包含D3DFVF_XYZRHW标志——的同时,D3DUSAGE_DONOTCLIP标志才有用。如果应用程序指明缓存将包含未经变换的顶点(D3DFVF_XYZ标志),那么IDirect3DDevice9::CreateVertexBuffer方法会忽略D3DUSAGE_DONOTCLIP标志。裁剪标志会占用额外的内存,这使可裁剪的顶点缓存比不能包含裁剪标志的顶点缓存略大。因为这些资源是在创建顶点缓存时分配的,所以必须提前要求可裁剪的顶点缓存。
第三个参数,FVF,是描述顶点缓存的顶点格式的D3DFVF组合。如果把这个参数指定为0,那么顶点缓存就是一个非FVF顶点缓存。更多信息,请参阅FVF顶点缓存。第四个参数描述用来存放顶点缓存的内存类型。
IDirect3DDevice9::CreateVertexBuffer接收的最后一个参数是变量的地址,如果调用成功,它会把一个指向新的IDirect3DVertexBuffer9顶点缓存对象接口的指针填入该变量。
注意 如果应用程序在创建顶点缓存时不支持裁剪标志,那么就不能生成裁剪标志。
以下C++示例代码显示了如何在代码中创建一个顶点缓存。
// 根据本示例的目的,d3dDevice变量是一个由Direct3DDevice对象暴露的
//
IDirect3DDevice9接口的地址,g_pVB是一个LPDIRECT3DVERTEXBUFFER9类型的变量。
// 自定义顶点类型
struct CUSTOMVERTEX {
FLOAT x, y, z;
FLOAT rhw;
DWORD color;
FLOAT tu, tv; // 纹理坐标
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW |
D3DFVF_DIFFUSE | D3DFVF_TEX1)
// 创建一个可裁剪的顶点缓存。在默认的内存池中分配足够的内存
// 以保存三个CUSTOMVERTEX结构。
if( FAILED( d3dDevice->CreateVertexBuffer(
3*sizeof(CUSTOMVERTEX),
0 /* 用途 */, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB ) ) )
return E_FAIL;
顶点缓存对象使应用程序能直接存取为顶点数据分配的内存。应用程序可以通过调用IDirect3DVertexBuffer9::Lock方法得到一个指向顶点缓存内存的指针,然后根据需要存取内存并将新的顶点数据填入缓存,或读取已经包含的数据。IDirect3DVertexBuffer9::Lock方法接收四个参数。第一个参数OffsetToLock,是顶点数据中的偏移量。第二个参数是顶点数据的大小,以字节为单位。第三个参数ppbData,是一个字节指针的地址,如果调用成功的话,该指针将会指向顶点数据。
最后一个参数Flags,告诉系统如何锁定内存。应用程序应该根据顶点数据将被存取的方式给Flags参数指定相应的常量。应该确保D3DUSAGE的值与D3DLOCK的值相对应。例如,如果正在创建一个只写的顶点缓存,那么试图通过指定D3DLOCK_READONLY标志去读取数据就没有意义。根据要求的存取类型,合理地使用这些标志允许驱动程序锁定内存并提供最佳的性能。
完成写入或读取顶点数据后,应该调用IDirect3DVertexBuffer9::Unlock方法,如以下示例代码所示。
// 本示例代码假定g_pVB为LPDIRECT3DVERTEXBUFFER9类型的变量,
// 并且g_Vertices已经用顶点数据做了适当的初始化。
// 要填充顶点缓存,必须锁定缓存以取得对顶点的存取权。
// 这种机制是必要的,因为顶点缓存可能在设备内存中。
VOID* pVertices; if( FAILED( g_pVB->Lock( 0, // 从缓存的开始处填充。 sizeof(g_Vertices), // 要载入数据的大小。 (BYTE**)&pVertices, // 返回的顶点数据。 0 ) ) ) // 设置默认的锁定标志位。 return E_FAIL; memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );
g_pVB->Unlock();
注意 如果应用程序用D3DUSAGE_WRITEONLY标志创建一个顶点缓存,那么不要用D3DLOCK_READONLY锁定标志。如果应用程序只从顶点缓存中读取数据,那么应该使用D3DLOCK_READONLY标志。如果对内存的存取是只读的,那么包含这个标志使Microsoft® Direct3D®能够优化它的内部处理并提高效率。
有关把D3DLOCK_DISCARD或D3DLOCK_NOOVERWRITE标志作为IDirect3DVertexBuffer9::Lock方法的Flags参数的更多信息,请参阅使用动态顶点和索引缓存。
因为C++应用程序直接存取为顶点缓存分配的内存,所以要确保应用程序正确地存取分配的内存。否则,存在渲染无效内存的风险。应用程序在从分配的缓存中的一个顶点移到另一个时,应该使用顶点格式的步距(stride)。顶点缓存内存是一个在弹性顶点格式中指定的简单的顶点数组。对于应用程序定义的任何顶点格式结构,都应使用步距。应用程序可以通过在运行的时候检查顶点缓存描述中包含的D3DFVF来计算步距。下表显示了每个顶点成员(vertex component)的大小。
|
顶点格式标志 |
大小 |
|
D3DFVF_DIFFUSE |
sizeof(DWORD) |
|
D3DFVF_NORMAL |
sizeof(float)
× 3 |
|
D3DFVF_SPECULAR |
sizeof(DWORD) |
|
D3DFVF_TEXn |
sizeof(float)
× n × t |
|
D3DFVF_XYZ |
sizeof(float)
× 3 |
|
D3DFVF_XYZRHW |
sizeof(float)
× 4 |
顶点格式中出现的纹理坐标的数量由D3DFVF_TEXn标志描述(n为从0到8的值)。要计算某个数量的纹理坐标所需要的内存,应该将纹理坐标组的数量乘以每组纹理坐标的大小,每组纹理坐标的大小可以是一到四个浮点数。
要存取某个顶点,应该使用整个顶点的步距增大或减小内存指针。
应用程序可以通过调用IDirect3DVertexBuffer9::GetDesc方法取得关于一个顶点缓存的信息。这个方法会把关于顶点缓存的信息填入D3DVERTEXBUFFER_DESC结构的成员。
用顶点缓存渲染顶点数据需要几个步骤。首先,应用程序需要通过调用IDirect3DDevice9::SetStreamSource方法设置数据流的源,如下示例代码所示。
d3dDevice->SetStreamSource(
0, g_pVB, sizeof(CUSTOMVERTEX) );
IDirect3DDevice9::SetStreamSource方法的第一个参数告诉Microsoft® Direct3D®设备数据流的源。第二个参数是要绑定到数据流的顶点缓存。第三个参数是成员的大小,以字节为单位。在上面的示例代码中,使用了CUSTOMVERTEX的大小作为成员的大小。
下一步是通过调用IDirect3DDevice9::SetVertexShader方法告诉Direct3D使用哪个顶点着色器。以下示例代码给顶点着色器设置了一个弹性顶点格式(FVF)码。这告诉Direct3D正在处理的顶点类型。
d3dDevice->SetFVF(
D3DFVF_CUSTOMVERTEX );
在设置数据流的源和顶点着色器之后,任何绘制方法将使用设定的顶点缓存。以下示例代码显示了如何用IDirect3DDevice9::DrawPrimitive方法用顶点缓存渲染顶点。
d3dDevice->DrawPrimitive(
D3DPT_TRIANGLELIST, 0, 1 );
IDirect3DDevice9::DrawPrimitive方法接收的第二个参数是顶点缓存中要载入的第一个顶点的索引值。
把IDirect3DDevice9::CreateVertexBuffer方法的弹性顶点格式(FVF)参数设置为非零值,但必须是有效的FVF码,表示缓存的内容会通过FVF码描述。用一个FVF码创建的顶点缓存被称为FVF顶点缓存。一些IDirect3DDevice9的方法或用法需要FVF顶点缓存,而另一些需要非FVF顶点缓存。IDirect3DDevice9::ProcessVertices方法需要FVF顶点缓存作为目标顶点缓存参数。
FVF顶点缓存可以被绑定到任意一个编号的源数据流。但是,不允许把FVF顶点缓存用作可编程顶点着色器的输入。
FVF顶点缓存中存在D3DFVF_XYZRHW成员表示缓存中的顶点已经处理过了。用作IDirect3DDevice9::ProcessVertices目标顶点缓存的顶点缓存必须是处理后的。用作固定功能着色器的输入的顶点缓存既可以是处理前的也可以是处理后的。如果顶点缓存是处理后的,那么着色器实际上被略过,数据被直接送到图元裁剪和设置模块。
FVF顶点缓存可用于顶点着色器。同样,顶点流可以表示和非FVF顶点缓存相同的顶点格式。它们不一定要用于从单独的顶点缓存中输入数据。新的顶点流的额外灵活性使需要分散保存它们数据的应用程序工作得更好,但这不是必须的。如果应用程序可以预先维持交叉存取的数据,那么这会导致性能的提升。如果应用程序只会在每次渲染调用前交叉存取数据,那么它应该启用API或硬件,用多数据流完成这类操作。
就顶点性能而言,最重要的是要使用32字节顶点,并维持好的高速缓存排序。
在固定功能顶点流水线中,处理顶点缓存中的顶点会应用设备当前的变换矩阵。另外也可以有选择地执行诸如光照、生成裁剪标志及更新区域(extents)之类的操作。在使用固定功能顶点处理时,对目标顶点缓存中的元素的修改由D3DPV_DONOTCOPYDATA标志控制。这个标志仅用于固定功能顶点处理。IDirect3DDevice9接口暴露了用于处理顶点的IDirect3DDevice9::ProcessVertices接口。通过调用IDirect3DDevice9::ProcessVertices方法,应用程序可以将顶点从一个顶点着色器处理为一个输入数据的集合,并生成一个单独的交叉存取的顶点缓存到目标顶点缓存。该方法接收五个(译注:应该是六个)参数,分别描述要处理的顶点的位置和数量,目标顶点缓存,及处理选项。在调用该方法后,目标缓存会包含经过处理的顶点数据。
第一个参数SrcStartIndex,为要载入的第一个顶点的索引值,同时也指定了该方法应该从哪里开始处理顶点。第二个参数DestIndex, 为一个索引值,指定把顶点放在目标缓存中的何处。第三个参数VertexCount,为要处理并放在目标缓存中的顶点的全部数量。应该把第四个参数pDestBuffer设为IDirect3DVertexBuffer9顶点缓存对象接口的地址,该顶点缓存对象用来存放处理后的源顶点。
最后一个参数Flags,决定该方法的特殊处理选项。可以把这个参数设为0进行默认的顶点处理,或设为D3DPV_DONOTCOPYDATA以便在某种情况下对处理进行优化。当应用程序把Flags设为0时,目标顶点缓存的顶点格式中不受顶点处理影响的顶点成员仍然会从顶点着色器中复制或设为0。但是,当使用了D3DPV_DONOTCOPYDATA时,IDirect3DDevice0::ProcessVertices不会覆盖目标缓存中的颜色和纹理坐标信息,除非数据是由Microsoft® Direct3D®生成的。漫反射色在光照被启用时产生,也就是说,D3DRS_LIGHTING被设为TRUE。镜面反射色在光照被启用且镜面反射也被启用时产生,也就是说,D3DRS_SPECULARENABLE和D3DRS_LIGHTING被设为TRUE。镜面反射色也在雾被启用时产生。纹理坐标在纹理变换和纹理生成被启用时产生。IDirect3DDevice9::ProcessVertices使用当前的渲染状态决定应该进行哪些顶点处理。
IDirect3DDevice9::ProcessVertices方法需要对目标顶点缓存的D3DFVF进行特殊设置。弹性顶点格式(FVF)用途设置与当前顶点处理的设置必须不能相矛盾。
对于固定功能顶点处理,IDirect3DDevice9::ProcessVertices需要以下FVF设置。
另外,纹理坐标的数量必须按以下方式设置。
因此,对每一纹理层来说,如果有一个纹理被绑定到该层且以下任一条件为真,那么会产生一组新的纹理坐标。
当Direct3D生成纹理坐标时,要求应用程序执行以下操作。
最后,纹理坐标的维度(从D3DFVF_TEX0到D3DFVF_TEX8)必须按以下方式设置。
当IDirect3DDevice9::ProcessVertices因为与目标顶点缓存的FVF码不兼容而失败时,Direct3D会把希望得到的FVF码打印到调试输出(仅限于调试版)。
当使用可编程顶点着色器时,对目标顶点缓存中元素的更新由着色器程序控制。当应用程序写入目标顶点寄存器之一时,目标顶点缓存中每个顶点对应的元素被更新。目标顶点缓存中未经应用程序写入的元素不会被修改。若应用程序试图写入目标顶点缓存中不存在的元素,则IDirect3DDevice9::ProcessVertices方法会失败。
顶点处理操作的性能,包括变换和光照,很大程度上取决于顶点缓存在内存中的位置以及正在使用的渲染设备的类型。在创建顶点缓存时,应用程序控制它们的内存分配。如果设置了D3DPOOL_SYSTEMMEM内存标志,那么顶点缓存会被创建在系统内存中。如果使用了D3DPOOL_DEFAULT内存标志,那么驱动程序会决定最好把顶点缓存分配在哪里,这通常被称为驱动程序最优(driver-optimal)内存。驱动程序最优内存可以是本地显存,非本地显存,或系统内存。
在调用IDirect3DDevice9::CreateVertexBuffer时设置D3DUSAGE_SOFTWAREPROCESSING常量会启用对顶点缓存数据的软件顶点处理。在混合模式下,这个标志是软件顶点处理必需的。这个标志不能用于硬件顶点处理模式。用于软件顶点处理的顶点缓存包括以下几种:
应用程序用来决定顶点缓存所在的位置——系统内存或驱动程序最优内存——的原因与纹理相同。硬件顶点处理,包括变换和光照,最好与分配在驱动程序最优内存中顶点缓存一起使用,而软件顶点处理则最好与分配在系统内存中的顶点缓存一起使用。对纹理来说,分配在驱动程序最优内存中的纹理最好与硬件光栅化一起使用,而软件光栅化则最好与系统内存纹理一起使用。
注意 Microsoft DirectX® 9.0的Microsoft®
Direct3D®由IDirect3DDevice9::ProcessVertices支持独立的顶点处理,而不需要渲染任何图元。这个独立的顶点处理总是以软件方式在主处理器上执行。由于这个原因,用IDirect3DDevice9::SetStreamSource设置的源顶点缓存必须是用D3DUSAGE_SOFTWAREPROCESSING标志创建的。在使用软件顶点处理时,IDirect3DDevice9::ProcessVertices提供的功能与IDirect3DDevice9::DrawPrimitive和IDirect3DDevice9::DrawIndexedPrimitive方法提供的功能完全一样。
如果应用执行自己的顶点处理并传递经过变换、光照和裁剪的顶点给渲染方法,那么应用程序可以直接把顶点写入到分配在驱动程序最优内存中的顶点缓存。这项技术避免了以后一个冗余的复制操作。注意如果应用程序要从顶点缓存中读回数据,那么这项技术不会很有效,因为从主机到驱动程序最优内存的读操作可能非常慢。因此,如果应用程序需要在处理过程中读取数据或不规律地写入数据,那么系统内存顶点缓存是一个更好的选择。
在使用Direct3D的顶点处理特性时(通过传递未经变换的顶点到顶点缓存渲染方法),根据设备类型和设备创建标志,处理既可用硬件也可用软件执行。实际上在所有情况下,为得到最佳性能,最好在D3DPOOL_DEFAULT池中分配顶点缓存。当设备使用硬件顶点处理时,根据D3DUSAGE_DYNAMIC和D3DUSAGE_WRITEONLY标志,还可以进行许多其它的优化。更多有关使用这些标志的信息,请参阅IDirect3DDevice9::CreateVertexBuffer。
索引缓存,由IDirect3DIndexBuffer9接口表示,是包含索引数据的内存缓存。索引数据,或索引,是顶点缓存中的整型偏移量,在用IDirect3DDevice9::DrawIndexedPrimitive方法渲染图元时使用。
顶点缓存和索引缓存是不相关的概念,也就是说,用索引表示的图元可以与顶点缓存一起或不一起使用,或者顶点缓存可以与用索引表示的图元一起或不一起使用。
索引缓存由它的能力表示:是否只能存在于系统内存中,是否只能用于写操作,及类型和能包含的索引的数量。这些特性包含在D3DINDEXBUFFER_DESC结构中。
索引缓存描述告诉应用程序一个已有的缓存是如何创建的。只要应用程序给系统提供一个空的描述结构,系统会在结构中填入先前创建的索引缓存的能力。有关此任务的更多信息,请参阅存取索引缓存的内容。
Format成员描述索引缓存数据的表面格式。
Type标识索引缓存的资源类型。
Usage结构成员包含了综合的能力标志。D3DUSAGE_SOFTWAREPROCESSING标志表示索引缓存要被用于软件顶点处理。Usage中存在D3DUSAGE_WRITEONLY标志表示索引缓存只能用于写操作。这使驱动程序可以自由地将索引数据放在最佳的内存位置以进行快速处理和渲染。如果没有使用D3DUSAGE_WRITEONLY标志,驱动程序不太可能把数据放在一个读操作的效率很低的地方。这牺牲了一些处理时间和渲染速度。如果没有指定该标志,那么系统会假定应用程序对索引缓存中的数据执行读写操作。
Pool指定为索引缓存分配的内存的类型。D3DPOOL_SYSTEMMEM标志指示系统在系统内存中创建索引缓存。
Size成员存储索引缓存的大小,以字节为单位。
更多信息包含在以下主题中。
调用IDirect3DDevice9::CreateIndexBuffer方法创建一个索引缓存,该方法接收五个参数。第一个参数指定索引缓存的长度,以字节为单位。
第二个参数是一组用途控制标志。其中,它的值决定由索引引用的顶点是否能包含裁剪信息。要提高性能,应该在不需要裁剪时指定D3DUSAGE_DONOTCLIP标志。
当在设备上启用了混合模式或软件顶点处理(D3DCREATE_MIXED_VERTEXPROCESSING / D3DCREATE_SOFTWARE_VERTEXPROCESSING)时,可以设置D3DUSAGE_SOFTWAREPROCESSING标志。在混合模式中,要进行软件顶点处理的缓存必须设置D3DUSAGE_SOFTWAREPRECESSING标志,但在使用硬件顶点处理(D3DCREATE_HARDWARE_VERTEXPROCESSING)时,为了得到尽可能好的性能,不应设置该标志。但是,当一个缓存要同时进行硬件和软件顶点处理时,设置D3DUSAGE_SOFTWAREPROCESSING是唯一的选择。和软件设备一样,混合设备也可以使用D3DUSAGE_SOFTWAREPROCESSING。
即使顶点处理是用硬件完成的,通过指定D3DPOOL_SYSTEMMEM,把顶点和索引缓存强制分配到系统内存中也是可以的。当驱动程序将这些缓存放在AGP内存中时,这种方法可以避免大量的页面锁定内存。
第三个参数是D3DFORMAT枚举类型的成员,D3DFMT_INDEX16或D3DFMT_INDEX32,它用来指定每个索引的大小。
第四个参数是D3DPOOL枚举类型的成员,告诉系统把新的索引缓存放在内存中的何处。
IDirect3DDevice9::CreateIndexBuffer接收的最后一个参数是变量的地址,如果调用成功的话,它会把一个指向新的IDirect3DIndexBuffer9索引缓存对象的指针填入该变量。
以下C++示例代码显示了如何在代码中创建一个索引缓存。
/*
* 根据本示例的目的,d3dDevice变量是一个由Direct3DDevice对象暴露的 * IDirect3DDevice9接口的地址,g_IB是LPDIRECT3DINDEXBUFFER9类型的变量。*/
if( FAILED( d3dDevice->CreateIndexBuffer( 16384 *sizeof(WORD),
D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_IB ) ) ) return E_FAIL;
索引处理操作的性能很大程度上取决于索引缓存位于内存的何处以及正在使用的渲染设备的类型。在创建索引缓存时,应用程序控制它们的内存分配。如果设置了D3DPOOL_SYSTEMMEM内存标志,那么索引缓存会被创建在系统内存中。如果设置了D3DPOOL_DEFAULT内存标志,那么设备驱动程序会决定最好把索引缓存的内存分配在哪里,这通常被称为驱动程序最优内存。驱动程序最优内存可以是本地显存,非本地显存,或系统内存。
在调用IDirect3DDevice9::CreateIndexBuffer方法时设置D3DUSAGE_SOFTWAREPROCESSING行为标志说明索引要被用于软件顶点处理。在混合模式顶点处理中,在使用软件顶点处理时必需要设这个标志。
应用程序可以直接把索引写入到位于驱动程序最优内存中的索引缓存。这项技术避免了以后一个冗余的复制操作。如果应用程序要从索引缓存中读回数据的话,那么这项技术不会很有效,因为从主机到驱动程序最优内存的读操作可能非常慢。因此,如果应用程序需要在处理过程中读取数据或不规律地写入缓存,那么系统内存索引缓存是一个更好的选择。
注意 除非不想消耗显存,或当驱动程序把顶点或索引缓存放在AGP内存中时不想增加大量的页面锁定内存,否则应该总是使用D3DPOOL_DEFAULT标志。
索引缓存对象使应用程序能直接存取为索引数据分配的内存。应用程序可以通过调用IDirect3DIndexBuffer9::Lock方法得到一个指向索引缓存的内存指针,然后根据需要存取内存并填入新的索引数据或读取其中包含的任何数据。IDirect3DIndexBuffer9::Lock方法接收四个参数。第一个参数OffsetToLock,是索引数据中的偏移量。第二个参数SizeToLock,是索引数据的大小,以字节为单位。第三个参数ppbData,是一个字节指针的地址,如果调用成功的话,会在该地址中填入指向索引数据的指针。
最后一个参数Flags,告诉系统怎样锁定内存。应用程序可以用它表示应用程序如何存取缓存中的数据。应该根据应用程序存取索引数据的方法指定Flags参数的常量。这允许驱动程序根据给定的存取类型,锁定内存并提供最佳性能。如果应用程序只从索引缓存中读取数据,那么应该使用D3DLOCK_READONLY标志。假设对内存的存取是只读的,包含这个标志使Microsoft® Direct3D®能够优化它的内部处理以提高效率。
在填入或读取索引数据后,应该调用IDirect3DIndexBuffer9::Unlock方法,如以下示例代码所示。
// 本示例代码假设IB是一个LPDIRECT3DINDEXBUFFER9类型的变量
// 并且g_Indices已经用索引值进行了适当地初始化。
// 要填入索引缓存,必须先锁定缓存取得对索引的存取权,
// 这个机制是必要的因为索引缓存可能在设备内存中。
VOID* pIndices; if( FAILED( IB->Lock( 0, // 从缓存开始处填充 sizeof(g_Indices), // 要载入数据的大小 (BYTE**)&pIndices, // 返回的索引数据 0 ) ) ) // 默认的锁定标志 return E_FAIL; memcpy( pIndices, g_Indices, sizeof(g_Indices) );
IB->Unlock();
注意
如果应用程序用D3DUSAGE_WRITEONLY标志创建一个索引缓存,那么不应该用D3DLOCK_READONLY锁定标志。如果应用程序只从索引缓存的内存中读取数据,那么应该用D3DLOCK_READONLY标志。假设对内存的存取为只读,包含这个标志使Direct3D能够优化它的内部处理以提高效率。
有关在IDirect3DIndexBuffer9::Lock方法的Flags参数中使用D3DLOCK_DISCARD或D3DLOCK_NOOVERWRITE标志的信息,请参阅使用动态顶点和索引缓存。
因为C++程序直接存取分配给索引缓存的内存,所以要确保应用程序正确地存取内存。否则,存在渲染无效内存的风险。在应用程序中从缓存中的一个索引移动到另一个时,应该使用索引格式的步距。
通过调用IDirect3DIndexBuffer9::GetDesc方法可以取得关于一个索引缓存的信息。这个方法把有关索引缓存的信息填入D3DINDEXBUFFER_DESC结构的成员。
用索引缓存渲染索引数据需要几个步骤。首先,应用程序需要通过调用IDirect3DDevice9::SetStreamSource方法设置数据流的源。
d3dDevice->SetStreamSource(
0, VB, 0, sizeof(CUSTOMVERTEX) );