坐标系与基本图元(5)

坐标系与基本图元(5)

使用索引缓冲区绘制图形

当绘制一个比较复杂的图形时,需要使用许多相互邻接的三角形。如果为每个三角形准备三个顶点数据,显然有许多数据是重复的,这样会浪费大量的内存和系统带宽。为了解决这一问题,可以先创建一个顶点缓冲区,将不重复的顶点数据写入顶点缓冲区,然后创建一个顶点索引缓冲区(index buffer),存放各个三角形的顶点索引信息,最后通过顶点索引和顶点数据共同完成图形绘制。

在Direct3D中一个顶点的索引只需要用一个16位或32位的整数表示,因此当多边形的顶点有较多重复使用时,使用索引数组通常能够比直接绘制顶点序列节省一部分内存空间和系统带宽。同时,Direct3D渲染流水线避免了对相同顶点进行重复计算,从而可以相应地提高图形程序的整体性能。

首先定义顶点结构和灵活顶点格式:

struct sCustomVertex{	float x, y, z, rhw;	DWORD color;};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE) 

接着创建顶点缓冲区和索引缓冲区,各顶点位置如下图所示:

void init_vertices(){	sCustomVertex vertices[9];    
	vertices[0].x	  = 300.0f;	vertices[0].y	  = 250.0f;	vertices[0].z	  = 0.5f;	vertices[0].rhw	  = 1.0f;	vertices[0].color = 0xffff0000;
	for(int i = 0; i < 8; i++)	{		vertices[i+1].x		=  (200 * sin(i * 3.14159f / 4.0f)) + 300;		vertices[i+1].y		= -(200 * cos(i * 3.14159f / 4.0f)) + 250;		vertices[i+1].z		= 0.5f;		vertices[i+1].rhw	= 1.0f;		vertices[i+1].color = 0xff00ff00;	}
	WORD indices[] = { 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, 0,7,8, 0,8,1 };
	// push vertex data into vertex buffer
	g_device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT, &g_vertex_buffer, NULL);
	void* ptr;
	g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);	memcpy(ptr, vertices, sizeof(vertices));	g_vertex_buffer->Unlock();
	// push vertex index into index buffer
	g_device->CreateIndexBuffer(sizeof(indices), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_index_buffer, NULL);
	void* index_ptr;	
	g_index_buffer->Lock(0, sizeof(indices), (void**)&index_ptr, 0);	memcpy(index_ptr, indices, sizeof(indices));	g_index_buffer->Unlock();}

在上面的代码段中,使用IDirect3DDevice9::CreateIndexBuffer()函数创建所需要的索引缓冲区,该函数的声明如下:

Creates an index buffer.

HRESULT CreateIndexBuffer(  UINT Length,  DWORD Usage,  D3DFORMAT Format,  D3DPOOL Pool,  IDirect3DIndexBuffer9** ppIndexBuffer,  HANDLE* pSharedHandle);

Parameters

Length
[in] Size of the index buffer, in bytes.
Usage
[in] Usage can be 0, which indicates no usage value. However, if usage is desired, use a combination of one or more D3DUSAGE constants. It is good practice to match the usage parameter in CreateIndexBuffer with the behavior flags in IDirect3D9::CreateDevice. For more information, see Remarks.
Format
[in] Member of the D3DFORMAT enumerated type, describing the format of the index buffer. For more information, see Remarks. The valid settings are the following:

D3DFMT_INDEX16
Indices are 16 bits each.
D3DFMT_INDEX32
Indices are 32 bits each.
Pool
[in] Member of the D3DPOOL enumerated type, describing a valid memory class into which to place the resource.
ppIndexBuffer
[out, retval] Address of a pointer to an IDirect3DIndexBuffer9 interface, representing the created index buffer resource.
pSharedHandle
[in] Reserved. Set this parameter to NULL.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be one of the following: D3DERR_INVALIDCALL, D3DERR_OUTOFVIDEOMEMORY, D3DXERR_INVALIDDATA, E_OUTOFMEMORY.

Remarks

Index buffers are memory resources used to hold indices, they are similar to both surfaces and vertex buffers. The use of index buffers enables Direct3D to avoid unnecessary data copying and to place the buffer in the optimal memory type for the expected usage.

To use index buffers, create an index buffer, lock it, fill it with indices, unlock it, pass it to IDirect3DDevice9::SetIndices, set up the vertices, set up the vertex shader, and call IDirect3DDevice9::DrawIndexedPrimitive for rendering.

The MaxVertexIndex member of the D3DCAPS9 structure indicates the types of index buffers that are valid for rendering.

接着使用索引缓冲区绘制图形:

void render(){	g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_X#050505, 1.0f, 0);
	g_device->BeginScene();
	g_device->SetRenderState(D3DRS_FILLMODE, g_fill_mode);	g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));	g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);	g_device->SetIndices(g_index_buffer);	g_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 9, 0, 8);		
	g_device->EndScene();
	g_device->Present(NULL, NULL, NULL, NULL);}

函数IDirect3DDevice9::DrawIndexedPrimitive()使用当前设置的索引缓冲区绘制图形:

Based on indexing, renders the specified geometric primitive into an array of vertices.

HRESULT DrawIndexedPrimitive(  D3DPRIMITIVETYPE Type,  INT BaseVertexIndex,  UINT MinIndex,  UINT NumVertices,  UINT StartIndex,  UINT PrimitiveCount);

Parameters

Type
[in] Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method. See Remarks.
BaseVertexIndex
[in] Offset from the start of the vertex buffer to the first vertex. See Scenario 4.
MinIndex
[in] Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
NumVertices
[in] Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
StartIndex
[in] Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
PrimitiveCount
[in] Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type. The maximum number of primitives allowed is determined by checking the MaxPrimitiveCount member of the D3DCAPS9 structure.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be the following: D3DERR_INVALIDCALL.

Remarks

This method draws indexed primitives from the current set of data input streams. MinIndex and all the indices in the index stream are relative to the BaseVertexIndex.

The MinIndex and NumVertices parameters specify the range of vertex indices used for each IDirect3DDevice9::DrawIndexedPrimitive call. These are used to optimize vertex processing of indexed primitives by processing a sequential range of vertices prior to indexing into these vertices. It is invalid for any indices used during this call to reference any vertices outside of this range.

IDirect3DDevice9::DrawIndexedPrimitive fails if no index array is set.

The D3DPT_POINTLIST member of the D3DPRIMITIVETYPE enumerated type is not supported and is not a valid type for this method.

When converting a legacy application to Direct3D 9, you must add a call to either IDirect3DDevice9::SetFVF to use the fixed function pipeline, or IDirect3DDevice9::SetVertexDeclaration to use a vertex shader before you make any Draw calls.

完整源码如下:

#include <d3d9.h>
#include <math.h>

#define CLASS_NAME    "GameApp"

#define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

IDirect3D9*                g_d3d;
IDirect3DDevice9*        g_device;
IDirect3DVertexBuffer9* g_vertex_buffer;
IDirect3DIndexBuffer9*    g_index_buffer;

DWORD                    g_fill_mode = D3DFILL_SOLID;

struct sCustomVertex
{
    float x, y, z, rhw;
    DWORD color;
};

#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)

void init_vertices()
{
    sCustomVertex vertices[9];
    
    vertices[0].x      = 300.0f;
    vertices[0].y      = 250.0f;
    vertices[0].z      = 0.5f;
    vertices[0].rhw      = 1.0f;
    vertices[0].color = 0xffff0000;

for(int i = 0; i < 8; i++)
    {
        vertices[i+1].x        =  (200 * sin(i * 3.14159f / 4.0f)) + 300;
        vertices[i+1].y        = -(200 * cos(i * 3.14159f / 4.0f)) + 250;
        vertices[i+1].z        = 0.5f;
        vertices[i+1].rhw    = 1.0f;
        vertices[i+1].color = 0xff00ff00;
    }

WORD indices[] = { 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, 0,7,8, 0,8,1 };

// push vertex data into vertex buffer

g_device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT, &g_vertex_buffer, NULL);

void* ptr;

g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);
    memcpy(ptr, vertices, sizeof(vertices));
    g_vertex_buffer->Unlock();

// push vertex index into index buffer

g_device->CreateIndexBuffer(sizeof(indices), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_index_buffer, NULL);

void* index_ptr;
    
    g_index_buffer->Lock(0, sizeof(indices), (void**)&index_ptr, 0);
    memcpy(index_ptr, indices, sizeof(indices));
    g_index_buffer->Unlock();
}

bool init_d3d(HWND hwnd)
{
    g_d3d = Direct3DCreate9(D3D_SDK_VERSION);

if(g_d3d == NULL)
        return false;

D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));

d3dpp.Windowed            = TRUE;
    d3dpp.SwapEffect        = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat    = D3DFMT_UNKNOWN;

if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                  &d3dpp, &g_device)))
    {
        return false;
    }

init_vertices();
    
    g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

return true;
}

void cleanup()
{
    release_com(g_index_buffer);
    release_com(g_vertex_buffer);
    release_com(g_device);
    release_com(g_d3d);
}

void render()
{
    g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(5, 5, 5), 1.0f, 0);

g_device->BeginScene();

g_device->SetRenderState(D3DRS_FILLMODE, g_fill_mode);
    g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
    g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);
    g_device->SetIndices(g_index_buffer);
    g_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 9, 0, 8);

g_device->EndScene();

g_device->Present(NULL, NULL, NULL, NULL);
}

LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_KEYDOWN:
        switch(wParam)
        {    
        case VK_SPACE:
            g_fill_mode = (g_fill_mode == D3DFILL_WIREFRAME) ? D3DFILL_SOLID : D3DFILL_WIREFRAME;
            break;
        case VK_ESCAPE:
            DestroyWindow(hwnd);
            break;
        }    
        break;

case WM_DESTROY:        
        PostQuitMessage(0);
        return 0;
    }

return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
    WNDCLASSEX wc;

wc.cbSize            = sizeof(WNDCLASSEX);
    wc.style            = CS_CLASSDC;
    wc.lpfnWndProc        = WinProc;
    wc.cbClsExtra        = 0;
    wc.cbWndExtra        = 0;
    wc.hInstance        = inst;
    wc.hIcon            = NULL;
    wc.hCursor            = NULL;
    wc.hbrBackground    = NULL;
    wc.lpszMenuName        = NULL;
    wc.lpszClassName    = CLASS_NAME;
    wc.hIconSm            = NULL;

if(! RegisterClassEx(&wc))
        return -1;

HWND hwnd = CreateWindow(CLASS_NAME, "Direct3D App", WS_OVERLAPPEDWINDOW, 200, 100, 600, 500,
                             NULL, NULL, wc.hInstance, NULL);

if(hwnd == NULL)
        return -1;

if(init_d3d(hwnd))
    {
        ShowWindow(hwnd, SW_SHOWDEFAULT);
        UpdateWindow(hwnd);

MSG msg;
        ZeroMemory(&msg, sizeof(msg));

while(msg.message != WM_QUIT)
        {
            if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
                
            render();
        }
    }

cleanup();

UnregisterClass(CLASS_NAME, wc.hInstance);

return 0;
}

运行截图:

实体模式

线框模式

也可以只使用顶点缓冲区通过三角扇形图元来绘制,改动init_vertices()和render()即可,需要增加一个顶点使多边形封闭(即,使v9==v1)。

void init_vertices(){	sCustomVertex vertices[10];    
	vertices[0].x	  = 300.0f;	vertices[0].y	  = 250.0f;	vertices[0].z	  = 0.5f;	vertices[0].rhw	  = 1.0f;	vertices[0].color = 0xffff0000;
	for(int i = 0; i < 9; i++)	{		vertices[i+1].x		=  (200 * sin(i * 3.14159f / 4.0f)) + 300;		vertices[i+1].y		= -(200 * cos(i * 3.14159f / 4.0f)) + 250;		vertices[i+1].z		= 0.5f;		vertices[i+1].rhw	= 1.0f;		vertices[i+1].color = 0xff00ff00;	}
	// push vertex data into vertex buffer
	g_device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT, &g_vertex_buffer, NULL);
	void* ptr;
	g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);	memcpy(ptr, vertices, sizeof(vertices));	g_vertex_buffer->Unlock();}
void render(){	g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_X#050505, 1.0f, 0);
	g_device->BeginScene();
	g_device->SetRenderState(D3DRS_FILLMODE, g_fill_mode);	g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));	g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);
	g_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 8);	
	g_device->EndScene();
	g_device->Present(NULL, NULL, NULL, NULL);}
时间: 2024-10-01 11:04:06

坐标系与基本图元(5)的相关文章

坐标系与基本图元~转载天行健 君子当自强而不息

坐标系与基本图元 坐标系与基本图元(8)      摘要: 游戏程序通常都是运行在全屏幕模式下,进行全屏显示的关键是使用全屏显示的渲染设备.创建全屏显示模式渲染设备同窗口模式渲染设备基本相同,区别是将 d3dpp.Windowed设置为FALSE,告诉Direct3D系统,将要创建的是全屏模式渲染设备.此外,还需要明确指定后台缓冲区的大小和格式,这和创建窗口模式渲染设备是不相同的,在创建窗口模式渲染设备时可将后台缓冲区格式设置为D3DFMT_UNKNOWN,后台缓冲区大小也可取默认值,而在创建全

坐标系与基本图元(3)

坐标系与基本图元(3) 渲染顶点缓冲区图形 void render(){ g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_X#050505, 1.0f, 0); g_device->BeginScene(); g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex)); g_device->SetFVF(D3DFVF_CUSTOM_VERTEX)

坐标系与基本图元(7)

坐标系与基本图元(7) 场景提交概述 场景提交即将在后台缓冲区绘制好的场景提交到前台缓冲区,从而在屏幕上显示出来.提交接口函数是一组控制特定的渲染设备状态的方法,这些设备影响显示器的显示. (1)前台缓冲区:这是一块由显卡转换来的矩形存储区,这块矩形存储区的内容显示在显示器或其他输出设备上. (2)后台缓冲区:后台缓冲区是一个表面,其内容可以提交到前台缓冲区. (3)交换链:一组后台缓冲区集合,它们被顺序地提交到前台缓冲区.一般情况下,一个全屏交换链通过翻转设备驱动接口(DDI)来提交随后的显示

坐标系与基本图元(8)

坐标系与基本图元(8) 全屏幕显示 游戏程序通常都是运行在全屏幕模式下,进行全屏显示的关键是使用全屏显示的渲染设备.创建全屏显示模式渲染设备同窗口模式渲染设备基本相同,区别是将d3dpp.Windowed设置为FALSE,告诉Direct3D系统,将要创建的是全屏模式渲染设备.此外,还需要明确指定后台缓冲区的大小和格式,这和创建窗口模式渲染设备是不相同的,在创建窗口模式渲染设备时可将后台缓冲区格式设置为D3DFMT_UNKNOWN,后台缓冲区大小也可取默认值,而在创建全屏模式渲染设备时这些都需要

坐标系与基本图元(1) ~转载天行健 君子当自强而不息

坐标系与基本图元(1) Direct3D基本图元 图元(primitives)是Direct3D中定义的基本图形表示,它是组成一个单一实体的一组顶点.最简单的图元是三维坐标系中多个点的集合,称为点列表(point list).通常,图元是多边形(polygon),一个多边形是由至少三条边组成的封闭图形.最简单的多边形是三角形,Direct3D使用三角形来构成大多数其他多边形,这是因为三角形的三个顶点肯定是共面的,而渲染不共面的顶点效率比较低.通过组合三角形可以形成更大.更复杂的多边形和网格(me

坐标系与基本图元(4)

坐标系与基本图元(4) 各种基本图元的绘制 上面使用顶点缓冲区绘制的是三角形列表图元,前面介绍过Direct3D支持点列表,线段列表.线段条带.三角形列表.三角形条带.三角扇形6种基本图元.下面通过示例程序BasicPrimitive演示各种基本图元的绘制.该示例程序使用同一个顶点缓冲区绘制不同类型的图元,程序中通过一个全局变量标识当前绘制的图元类型,通过单击键盘上的"1" ~ "6"数字键可以在各图元类型之间进行切换,单击空格键可以在线框模式和实体模式之间切换.

坐标系与基本图元(2)

坐标系与基本图元(2) 创建顶点缓冲区 在创建顶点缓冲区之前,需要先定义一个表示顶点的结构类型,描述顶点保存格式的FVF和一个保存顶点的结构数组. struct sCustomVertex{ float x, y, z, rhw; DWORD color;}; #define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE) sCustomVertex vertices[] ={ { 100.0f, 400.0f, 1.0f, 1.0f,

坐标系与基本图元(6)

坐标系与基本图元(6) 灵活顶点格式 灵活顶点格式(Flexible Vertex Format, FVF)用来描述在顶点缓冲区中的顶点存储格式中包含了哪些属性.Direct3D应用程序可以用几种不同的方式定义灵活顶点格式.灵活顶点格式使应用程序只使用它需要的顶点数据,排除那些它不需要的组成成分.这样,应用程序可以节省内存空间,减少系统带宽.通过D3DFVF的组合,可以描述图元顶点的格式.灵活顶点格式指定的格式包括点的大小,用D3DFVF_PSIZE指定,该大小在投影机空间用来表示未经变换的顶点

Qt5图形视图框架之概念篇(1)

本章将主要简述Graphics View框架结构的特点.主要包含的元素及坐标系统. 1.Graphics View框架结构的特点: (1)系统可以利用Qt绘图系统的反锯齿.OpenGL工具来改善绘图性能. (2)其支持事件传播结构,可以使图元在场景中的交互能力提高一倍,凸缘可以处理键盘事件和鼠标事件. (3)通过BSP提供快速的图元查找,可以实现实时显示包含数百万图元的大场景. 2.Graphics View的三元素: (1)场景类(QGraphicsScene):本身不可见,是一个放置图元的容