3.1顶点/索引缓存
顶点和索引缓存有相似的接口并且共享相似的方法;因此我们把它们合在一起讲解。一个顶点缓存是一块连续的存储了顶点数据的内存。同样的,一个索引缓存是一块连续的存储了索引数据的内存。我们使用顶点和索引缓存保存我们的数据是因为它们能被放置在显存中。渲染显存中的数据要比渲染系统内存中的数据快的多。
在代码中,一个顶点缓存是通过IDirect3DVertexBuffer9接口来定义的。类似的,一个索引缓存是通过IDirect3DIndexBuffer9接口来定义。
3.1.1创建一个顶点和索引缓存
我们能使用下面两个方法创建一个顶点缓存和索引缓存:
HRESULT
IDirect3DDevice9::CreateVertexBuffer(
UINT Length,
DWORD Usage,
DWORD FVF,
D3DPOOL Pool
IDirect3DVertexBuffer9** ppVertexBuffer,
HANDLE*
pSharedHandle
);
HRESULT
IDirect3DDevice9::CreateIndexBuffer(
UINT Length,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DIndexBuffer9** ppIndexBuffer,
HANDLE*
pSharedHandle
);
|
这两个方法大部分参数是相同的,因此我们一起介绍它们。
Length ——
分配给缓存的字节大小。假如想得到一个能存储8个顶点的顶点缓存,那么我们就要在顶点结构中设置这个参数为
8 * sizeof ( Vertex ) 。
Usage
—— 指定关于怎样使用缓存的额外信息。这个值可以是0,没有标记,或者是下面标记的一个或多个的组合:
D3DUSAGE_DYNAMIC——设置这个参数可以使缓存是动态的。
D3DUSAGE_POINTS——这个参数指定缓存存储原始点。这个参数仅仅用在顶点缓冲中。
D3DUSAGE_SOFTWAREPROCESSING——使用软件顶点处理
D3DUSAGE_WRITEONLY——指定应用程序只能写缓存。它允许驱动程序分配最适合的内存地址作为写缓存。注意如果从创建好的这种缓存中读数据,将会返回错误信息。
FVF ——
存储在缓存中的顶点格式
Pool
—— 缓存放置在哪一个内存池中
ppVertexBuffer
——返回创建好的顶点缓存的指针。
pSharedHandle
——没有使用;设置为0。
Format
——指定索引的大小;使用D3DFMT_INDEX16设置16位索引,使用D3DFMT_INDEX32设置32位索引。注意并非所有设备都支持32位索引;请检查设备能力。
ppIndexBuffer
——返回创建好的索引缓存的指针。
注意:不使用D3DUSAGE_DYNAMIC参数创建的缓存被叫做静态缓存。静态缓存通常被放置在显存中,在其中的数据能被很有效的处理。然而,对于静态缓存,从中读取和写入数据是很慢的,因为访问显存是很慢的。因为这个原因我们用静态缓存存储静态数据(不需要被经常改变的数据)。地形和建筑物是很好的候选例子,因为在应用程序中他们通常不需要被改变。静态缓存应该在应用程序初始化的时候就被填充好,而不是在运行时才做。
注意:使用D3DUSAGE_DYNAMIC参数创建的缓存被叫做动态缓存。动态缓存通常被放在AGP内存中,这种内存中的数据能被很快的更新。处理动态缓存中的数据不会比处理静态缓存中的数据快,因为这些数据必须在渲染前被转移到显存中,动态缓存的好处是它们能够被稍微快点地被更新(比CPU写快)。因此,假如你需要经常更新缓存中的数据,那么你就应该使用动态缓存。粒子系统是很好的一个应用,因为它们是动态的,并且他们通常每一帧都会被更新。
注意:在程序中读取显存和AGP内存都是非常慢的。因此,假如你在运行时需要读取你的几何物体,最好的方案是指定一块系统内存,往其中拷贝并且读取数据。
下边是创建一个静态顶点缓存的例子,该缓存能存储8个顶点。
IDirect3DVertexBuffer9* vb;
device->CreateVertexBuffer(
8 * sizeof( Vertex ), 0,
D3DFVF_XYZ, D3DPOOL_MANAGED, &vb, 0);
|
3.1.2
访问缓冲内存
为了访问一个顶点/索引缓存,我们需要得到一个指针。我们通过一个指针获得缓存数据必须使用Lock方法。当我们访问完缓存后必须对它解锁。一旦有一个指向内存的指针,我们就能对它进行读写。
HRESULT
IDirect3DVertexBuffer9::Lock(
UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags
);
HRESULT
IDirect3DIndexBuffer9::Lock(
UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags
);
|
这两个方法的参数都是完全相同的。
OffsetToLock
—— 偏移量,以字节为单位,从缓存开始位置到锁定开始位置的距离。如图3.1。
SizeToLock
——
锁定的字节数。
ppbData
——
一个指向锁定内存开始位置的指针。
Flags
—— 标记描述怎样锁定内存。它可能是0或者是下面参数中的1个或多个的组合:
D3DLOCK_DISCARD——这个参数仅仅会在动态缓存时被使用。它指示硬件丢弃缓存并返回一个指向新分配的缓存的指针。这是很有用,因为当我们存取一个新分配的缓存时它允许硬件继续从丢弃的缓存渲染。这防止了硬件延迟。
D3DLOCK_NOOVERWRITE——这个参数仅仅会在动态缓存时被使用。它声明你将向缓存中添加数据。即你不能向已经渲染的内存中写数据。这是有好处的因为他允许你在添加新数据到缓存的同时让硬件继续渲染。
D3DLOCK_READONLY——这个参数声明你锁定的缓存只能从中读取数据而不能写数据。这允许一些内在的优化。
用参数D3DLOCK_DISCARD和D3DLOCK_NOOVERWRITE表明缓存的一部分被锁定之后能继续被使用。假如硬件配置允许这些标记被使用,则在对缓存进行锁定时,其他的显示操作就不会中断。
下边的例子展示了通常怎样使用Lock方法。注意当我们使用完以后要调用Unlock方法。
Vertex* vertices;
_vb->Lock(0, 0, (void**)&vertices,
0); //
锁定整个缓存
vertices[0] = Vertex(-1.0f,
0.0f, 2.0f); //
向缓存里写顶点
vertices[1] = Vertex( 0.0f,
1.0f, 2.0f);
vertices[2] = Vertex( 1.0f,
0.0f, 2.0f);
_vb->Unlock();
//
当你访问完缓存时,解锁缓存
|
3.1.3
找回顶点和索引缓存信息
有时我们需要得到顶点/索引缓存信息。下面的例子示范了用于获得这些信息的方法:
D3DVERTEXBUFFER_DESC
vbDescription;
_vertexBuffer->GetDesc(&vbDescription);
//
取得顶点缓存信息
D3DINDEXBUFFER_DESC
ibDescription;
_indexBuffer->GetDesc(&ibDescription);
//取得索引缓存信息
|
D3DVERTEXBUFFER_DESC和D3DINDEXBUFFER_DESC结构的定义如下:
Describes a vertex buffer.
typedef struct D3DVERTEXBUFFER_DESC {
D3DFORMAT Format;
D3DRESOURCETYPE Type;
DWORD Usage;
D3DPOOL Pool;
UINT Size;
DWORD FVF;
} D3DVERTEXBUFFER_DESC, *LPD3DVERTEXBUFFER_DESC;
Members
- Format
- Member of the D3DFORMAT enumerated type,
describing the surface format of the vertex buffer data.
- Type
- Member of the D3DRESOURCETYPE enumerated type,
identifying this resource as a vertex buffer.
- Usage
- Combination of one or more D3DUSAGE flags.
- Pool
- Member of the D3DPOOL enumerated type, specifying
the class of memory allocated for this vertex buffer.
- Size
- Size of the vertex buffer, in bytes.
- FVF
- Combination of D3DFVF that describes the vertex
format of the vertices in this buffer.
Defines resource types.
typedef enum D3DRESOURCETYPE
{
D3DRTYPE_SURFACE = 1,
D3DRTYPE_VOLUME = 2,
D3DRTYPE_TEXTURE = 3,
D3DRTYPE_VOLUMETEXTURE = 4,
D3DRTYPE_CubeTexture = 5,
D3DRTYPE_VERTEXBUFFER = 6,
D3DRTYPE_INDEXBUFFER = 7,
D3DRTYPE_FORCE_DWORD = 0x7fffffff,
} D3DRESOURCETYPE, *LPD3DRESOURCETYPE;
Constants
- D3DRTYPE_SURFACE
- Surface resource.
- D3DRTYPE_VOLUME
- Volume resource.
- D3DRTYPE_TEXTURE
- Texture resource.
- D3DRTYPE_VOLUMETEXTURE
- Volume texture resource.
- D3DRTYPE_CubeTexture
- Cube texture resource.
- D3DRTYPE_VERTEXBUFFER
- Vertex buffer resource.
- D3DRTYPE_INDEXBUFFER
- Index buffer resource.
- D3DRTYPE_FORCE_DWORD
- Forces this enumeration to compile to 32 bits in
size. Without this value, some compilers would allow this enumeration to
compile to a size other than 32 bits. This value is not used.
Describes an index buffer.
typedef struct D3DINDEXBUFFER_DESC {
D3DFORMAT Format;
D3DRESOURCETYPE Type;
DWORD Usage;
D3DPOOL Pool;
UINT Size;
} D3DINDEXBUFFER_DESC, *LPD3DINDEXBUFFER_DESC;
Members
- Format
- Member of the D3DFORMAT enumerated type,
describing the surface format of the index buffer data.
- Type
- Member of the D3DRESOURCETYPE enumerated type,
identifying this resource as an index buffer.
- Usage
- Combination of one or more of the following flags,
specifying the usage for this resource.
- D3DUSAGE_DONOTCLIP
- Set to indicate that the index buffer content
will never require clipping.
- D3DUSAGE_DYNAMIC
- Set to indicate that the index buffer requires
dynamic memory use. This is useful for drivers because it enables them
to decide where to place the buffer. In general, static index buffers
are placed in video memory and dynamic index buffers are placed in AGP
memory. Note that there is no separate static usage; if you do not
specify D3DUSAGE_DYNAMIC the index buffer is made static.
D3DUSAGE_DYNAMIC is strictly enforced through the D3DLOCK_DISCARD and
D3DLOCK_NOOVERWRITE locking flags. As a result, D3DLOCK_DISCARD and
D3DLOCK_NOOVERWRITE are only valid on index buffers created with
D3DUSAGE_DYNAMIC; they are not valid flags on static vertex buffers.
For more information about using dynamic index
buffers, see Using Dynamic Vertex and Index Buffers.
Note that D3DUSAGE_DYNAMIC cannot be specified
on managed index buffers. For more information, see Managing Resources
(Direct3D 9).
- D3DUSAGE_RTPATCHES
- Set to indicate when the index buffer is to be
used for drawing high-order primitives.
- D3DUSAGE_NPATCHES
- Set to indicate when the index buffer is to be
used for drawing N patches.
- D3DUSAGE_POINTS
- Set to indicate when the index buffer is to be
used for drawing point sprites or indexed point lists.
- D3DUSAGE_SOFTWAREPROCESSING
- Set to indicate that the buffer is to be used
with software processing.
- D3DUSAGE_WRITEONLY
- Informs the system that the application writes
only to the index buffer. Using this flag enables the driver to choose
the best memory location for efficient write operations and rendering.
Attempts to read from an index buffer that is created with this
capability can result in degraded performance.
- Pool
- Member of the D3DPOOL enumerated type, specifying
the class of memory allocated for this index buffer.
- Size
- Size of the index buffer, in bytes.