首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

学习目标

1.掌握深度缓冲、Alpha混合和Alpha测试

2.掌握多边形填充模式和渲染模式,图形反锯齿

3.掌握多纹理混合、雾化效果

4.掌握2D文字和图形、公告板技术

5.掌握粒子系统

知识背景

1.熟练掌握Windows编程

2.掌握D3D程序的基本框架

3.掌握如何在D3D环境下显示模型和场景

本章要点

1.Alpha混合和Alpha测试

2.多纹理混合,雾化效果

3.2D文字和图形显示

4.粒子系统

引    言

游戏中逼真的场景、漂亮的人物和华美的服装,都是通过在程序中组合一个个基本图元,经过变换后渲染出来的。单纯的渲染并不能生成游戏中的各种特效,比如雾效、爆炸的火焰效果等。要实现这些特效,就要在基本图形渲染的基础上,采用一些特殊的技术。本章将学习如何在D3D环境下实现一些简单的游戏特效。

6.1  基本渲染属性

6.1.1  深度缓冲

深度缓冲区是Direct3D用来存储绘制到屏幕上的每一个像素点的深度信息的一块内存缓冲区。Direct3D通过比较当前绘制的像素点的深度和对应深度缓冲区的点的深度值来决定是否绘制当前像素。如果深度测试为TRUE,则绘制当前像素,并用当前像素点深度值更新深度缓冲区,反之则不予绘制。通常情况下,深度缓冲区对应于屏幕大小的一块二维区域。

深度缓冲(又称Z-buffer)的作用是确保多边形能够正确地显示在它们本来的深度(相对于摄像机)上。例如在场景中有两个矩形,一个是蓝色的而另一个是绿色的。蓝色的Z值为10,绿色的Z值为20(摄像机在原点)。这就意味着蓝色的在绿色的前面(如图6-1所示)。深度缓冲能确定哪个对象在另一个对象的前面,正确地渲染对象。DirectX会测试对象在屏幕上的像素点到摄像机的远近,并把得出的值保存在深度缓冲中;接着,DirectX会测试同一位置另一对象的像素点,并和刚才的像素进行比较,如果更近,就刷新刚才的记录,否则就不理睬(有东西在它前面挡着它),这会决定此位置像素点的颜色到底是蓝色的还是绿色的。

图6-1  深度测试

下面的程序片断开启了深度测试,以便得到物体正确的前后关系:

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory( &d3dpp, sizeof(d3dpp) );

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

d3dpp.EnableAutoDepthStencil = TRUE;

d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

// g_pD3D为有效的Direct3D设备

if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,

&d3dpp, &g_pd3dDevice ) ) )

{

    return E_FAIL;

}

在显示模式中,设定了d3dpp.EnableAutoDepthStencil的值为TRUE,表示打开深度测试。接着,d3dpp.AutoDepthStencilFormat的值设为D3DFMT_D16,表示深度缓冲区的每一个像素由16位的整数值表示。

接下来,调用Direct3D渲染状态设置函数IDirect3DDevice9∷SetRenderState()激活深度缓冲区,将第一个参数设为D3DRS_ZENABLE,表示设置深度缓冲的状态,将第二个参数设为TRUE,打开深度缓冲。

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

接下来,仍然调用IDirect3DDevice9∷SetRenderState()设置深度测试函数,将第一个参数设为D3DRS_ZFUNC,将第二个参数设为想要设置的深度测试函数,它属于D3DCMPFUNC枚举类型,定义如下:

typedef enum _D3DCMPFUNC {

    D3DCMP_NEVER = 1,        //深度测试函数总是返回FALSE

    D3DCMP_LESS = 2,         //测试点深度值小于深度缓冲的值时返回TRUE

    D3DCMP_EQUAL = 3,        //测试点深度值等于深度缓冲的值时返回TRUE

    D3DCMP_LESSEQUAL = 4,    //测试点深度值小于等于深度缓冲的值时返回TRUE

    D3DCMP_GREATER = 5,      //测试点深度值大于深度缓冲的值时返回TRUE

    D3DCMP_NOTEQUAL = 6,     //测试点深度值不等于深度缓冲的值时返回TRUE

    D3DCMP_GREATEREQUAL = 7,//测试点深度值大于等于深度缓冲的值时返回TRUE

    D3DCMP_ALWAYS = 8,       //深度测试函数总是返回TRUE

    D3DCMP_FORCE_DWORD = 0x7fffffff

} D3DCMPFUNC;

通常情况下,深度测试函数总是设置为D3DCMP_LESS,表示当测试点深度值小于深度缓冲中的相应值时返回TRUE,通过深度测试并绘制相应的像素点。

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESS );

最后,还要调用IDirect3DDevice9∷SetRenderState(),将第一个参数设为D3DRS_ ZWRITEENABLE,将第二个参数设为TRUE,允许应用程序在绘制像素时更新深度缓冲区:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE );

6.1.2  Alpha混合

在前面章节的介绍中,已经遇到了Alpha值,如D3DCOLORVALUE数据结构中的A,它并没有被使用,因为在程序中没有激活Alpha混合(Alpha Blending),并且Alpha总是被赋值为浮点值1.0f(在默认渲染状态下,Alpha为1.0f表示不透明)。本节将讨论Alpha值的使用和半透明物体的绘制。

前面介绍的程序范例中,绘制图形的颜色总是替换当前颜色缓冲区中存在的颜色值,这样,后画的物体总是覆盖在原有物体上。但是,当想要绘制类似于玻璃、水等具有透明效果的物体时,这种方法显然不能满足要求。通过定义一个表示物体半透明度的Alpha值和一个半透明计算公式,可以把要绘制的物体的颜色与颜色缓冲区中存在的颜色相混合,从而绘制出具有半透明效果的物体。Direct3D计算Alpha混合的颜色方法如下:

在上面的公式中,Color表示Alpha混合后的颜色值;RGBsrc表示源颜色值,即将要绘制的图元颜色值;Ksrc表示源混合系数,通常赋值为表示半透明度的Alpha值,也可以是属于枚举D3DBLEND的任意值,用来和RGBsrc相乘;RGBdst表示目标颜色,即当前颜色缓冲区中的颜色值;Kdst表示目标系数,可以是属于枚举D3DBLEND的任意值,用来和RGBdst相乘;OP表示源计算结果与颜色缓冲区计算结果(目标计算结果)的混合方法,默认状态下OP为D3DBLENDOP_ADD,即源计算结果与颜色缓冲区计算结果相加。

图形显示中,对Alpha混合最普遍的使用方法是:把Ksrc赋值为D3DBLEND_ SRCALPHA,即当前绘制像素的Alpha值;把Kdst赋值为D3DBLEND_INVSRCALPHA,即1减去当前绘制像素的Alpha值;把OP赋值为D3DBLENDOP_ADD,使源计算结果与颜色缓冲区计算结果相加。上面的公式转化为:

要想绘制半透明物体,首先需要激活Direct3D的Alpha混合计算,设置IDirect3DDevice9∷SetRenderState()的第一个参数为D3DRS_ALPHABLENDENABLE,第二个参数为TRUE:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );

然后,设置Alpha混合的系数:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );

g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA );

由于Alpha混合是当前绘制的像素颜色与颜色缓冲区中存在的颜色的混合运算,因此,在绘制半透明物体之前,位于半透明物体之后被它遮挡的物体必须保证先于半透明物体绘制。所以,必须打开深度缓冲。

Direct3D支持多种Alpha混合方法,Alpha混合系数KsrcKdst可以设为枚举常量D3DBLEND的任意值,如表6-1所示。

表6-1  Alpha混合方法

D3DBLEND的值

   

D3DBLEND_ZERO

Alpha混合系数为0

续表 

D3DBLEND的值

   

D3DBLEND_ONE

Alpha混合系数为1

D3DBLEND_SRCCOLOR

Alpha混合系数为当前绘制像素的Color值(RGBA

D3DBLEND_INVSRCCOLOR

Alpha混合系数为1—当前绘制像素的Color值(RGBA

D3DBLEND_SRCALPHA

Alpha混合系数为当前绘制像素的Alpha

D3DBLEND_INVSRCALPHA

Alpha混合系数为1—当前绘制像素的Alpha

D3DBLEND_DESTALPHA

Alpha混合系数为颜色缓冲区中的Alpha

D3DBLEND_INVDESTALPHA

Alpha混合系数为1—颜色缓冲区中的Alpha

D3DBLEND_DESTCOLOR

Alpha混合系数为颜色缓冲区中像素的Color值(RGBA

D3DBLEND_INVDESTCOLOR

Alpha混合系数为1——颜色缓冲区中像素的Color值(RGBA

源计算结果与颜色缓冲区计算结果的混合方法OP属于枚举常量D3DBLENDOP,根据计算机硬件的不同可以取不同的值,如表6-2所示。

表6-2  目标与源的混合方法

D3DBLENDOP的值

   

D3DBLENDOP_ADD

源计算结果与颜色缓冲区计算结果相加

D3DBLENDOP_SUBTRACT

源计算结果减去颜色缓冲区计算结果

D3DBLENDOP_REVSUBTRACT

颜色缓冲区计算结果减去源计算结果

D3DBLENDOP_MIN

取两者的最小值

D3DBLENDOP_MAX

取两者的最大值

需要注意的是,由于功能的限制,有些计算机硬件可能不支持某些混合方法,这时Direct3D会自动使用D3DBLENDOP_ADD。

使用Alpha混合后的效果如图6-2所示。

图6-2  Alpha混合效果

6.1.3  Alpha测试

Alpha测试可控制Direct3D程序是否绘制当前像素(根据是否满足Alpha测试条件),图形程序应用Alpha测试可以有效地屏蔽某些像素颜色。与Alpha混合相比,Alpha测试不能将绘制像素颜色与颜色缓冲区像素混合,像素要么完全不透明,要么完全透明。由于无须进行颜色缓冲区的读操作,因此Alpha测试在速度上要优于Alpha混合。

Alpha测试通过渲染状态D3DRS_ALPHATSTEABLE设置,下列代码激活Direct3D的Alpha测试状态:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );

渲染状态D3DRS_ALPHAREF用来设置进行Alpha测试的参考值AlphaReference。Alpha测试函数比较当前绘制的像素的Alpha值和AlphaReference值,如果返回TRUE,则通过测试并绘制像素,反之不予绘制。AlphaReference的取值范围从0×00000000~0×000000ff。下列代码设置Alpha测试的参考值为0×00000001:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0×00000001 );

渲染状态D3DRS ALPHAFUNC用来设置Alpha测试函数。Alpha测试函数属于D3DCMPFUNC枚举类型,其取值可以参考深度缓冲中的取值。下列代码设置Alpha测试函数如大于参考值则返回TRUE:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );

可以修改上面的Alpha混合的代码,使用Alpha测试:

// g_pd3dDevice为有效的Direct3D设备

g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,   TRUE );   

g_pd3dDevice->SetRenderState(D3DRS_ALPHAREF,   0x00000000);    

g_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC,  D3DCMP_GREATER);

使用Alpha测试后,第一个三角锥完全透明,因此在重叠部分完全绘制后一个三角锥的像素,如图6-3所示。

图6-3  Alpha测试效果

6.1.4  多边形填充和渲染

1.多边形填充模式

默认状态下,Direct3D会把渲染的多边形面的图像绘制出来,这种方法适合于绝大多数情况,然而,有时为了调试程序的目的,可能只需要绘制出多边形的顶点或边,不同的填充效果如图6-4、图6-5、图6-6所示。可以利用渲染状态D3DRS FILLMODE,并指定枚举类型D3DFILLMODE中的一个数值,来选择填充图元模式。D3DFILLMODE定义如下:

typedef enum _D3DFILLMODE {

    //渲染点模式,Direct3D在多边形的每个顶点绘制一个像素点

    D3DFILL_POINT = 1,

    // 渲染线模式,Direct3D在多边形的每个边绘制一条线

    D3DFILL_WIREFRAME = 2,

    // 渲染面模式,为Direct3D默认的填充模式,Direct3D对多边形面进行填充

    D3DFILL_SOLID = 3,

    D3DFILL_FORCE_DWORD = 0x7fffffff

} D3DFILLMODE

       

图6-4  渲染点模式                        

图6-5  渲染线框模式

图6-6  默认渲染面模式

2.渲染模式

三维图形的渲染是对完成坐标转换和光照处理后的多边形进行着色的过程,这一步骤通常在显示内存中由图形显示卡控制完成。Direct3D支持两种类型的渲染方法:Flat渲染和Gouraud渲染。

1)Flat渲染

Direct3D使用多边形面的第一个顶点颜色作为整个多边形的颜色进行渲染,因此每一个多边形只有一种颜色值。Flat渲染速度较快,利用Flat渲染的物体在多边形连接处有比较明显的颜色差别。

2)Gouraud渲染

Direct3D计算多边形每一个顶点的光照颜色值,并对每一个多边形的面上的像素按照它的各个顶点颜色进行线性插值,这是Direct3D默认的渲染方式。

可以用渲染状态设置函数IDirect3DDevice9∷SetRenderState()改变当前的渲染方法。它的第一个参数赋值为D3DRS SHADEMODE,第二个参数是一个D3DSHADEMODE枚举常量,赋值为想要设置的渲染方法,定义如下:

typedef enum _D3DSHADEMODE {

    D3DSHADE_FLAT = 1,

    D3DSHADE_GOURAUD = 2,

    D3DSHADE_PHONG = 3,

    D3DSHADE_FORCE_DWORD = 0x7fffffff

} D3DSHADEMODE;

D3DSHADE_PHONG:使用Phong渲染,这是一种更真实的渲染方法,但目前Direct3D不支持这种渲染模式。

6.1.5  图形反锯齿

图形像素在颜色缓冲区或屏幕中以一组整数类型的二维坐标(xy)表示当前位置,如果实际计算的像素坐标是浮点数值,将被转换为整数坐标。显然,这种光栅化处理方法将使生成的图形具有锯齿形外观,图形学称这种由于采样频率不足而造成的失真为锯齿(Aliasing)。Direct3D采用图形反锯齿(Antialinasing)来改善图形锯齿效果,增加图形边缘线条的平滑度。

一种常见的图形反锯齿方法是全景反锯齿(Full-scene Antialiasing),它通过图形光栅化处理过程中的多重采样(Multsampling)实现。当启用多重采样方法时,每一个绘制到颜色缓冲区的像素不仅仅具有当前整数坐标位置的纹理元素的颜色,还具有一定程度的相邻纹理元素的颜色,实际绘制的颜色是当前整数坐标位置的纹理元素和相邻纹理元素的颜色的混合。采用多重采样方法绘制的图形的边缘更模糊一些,锯齿情况将得到较大的改善。为了得到较好的反锯齿效果,可以使用不同的多重采样方法实现图形反锯齿。

1.查询设备是否支持多重采样

可以使用IDirect3D9∷CheckDeviceMultiSampleType()函数检查当前设备是否支持图形多重采样:

HRESULT CheckDeviceMultiSampleType(         

    UINT Adapter,

    D3DDEVTYPE DeviceType,

    D3DFORMAT SurfaceFormat,

    BOOL Windowed,

    D3DMULTISAMPLE_TYPE MultiSampleType,

    DWORD* pQualityLevels

);

— 参数Adapter表示当前查询的显示硬件的序号,通常以D3DADAPTER_ DEFAULT表示对系统当前默认使用的图形显示硬件进行查询。

— 参数DeviceType表示当前查询的设备类型,它属于D3DDEVTYPE类型。

— 参数SurfaceFormat表示需要查询的渲染表面像素显示格式,它属于D3DFORMAT类型。

— 参数Windowed表示是否使用窗口显示。

— 参数MultiSampleType表示需要查询的多重采样方法,它属于D3DMULTISAMPL _TYPE类型。我们可以指定为D3DMULTISAMPLE_NONE,以禁用多重采样;或者指定为D3DMULTISAMPLE_2_SAMPLES∼D3DMULTISAMPLE_16_SAMPLES之间的值,以启用2点采样、3点采样,直到16点采样。

— 参数pQualityLevels存储返回的图形质量数值,可设为NULL,表示无须返回。

下列代码查询当前显示硬件的硬件抽象层设备是否支持D3DFMT_X8R8G8B8像素格式的4点采样。

【例6-1】判断设备是否支持多重采样:

D3DDEVTYPE MultisampleDevtype=(D3DDEVTYPE )-1;

DWORD numq=0;

if( SUCCEEDED(g_pD3D->CheckDeviceMultiSampleType(

                 D3DADAPTER_DEFAULT,

                 D3DDEVTYPE_REF , D3DFMT_X8R8G8B8, FALSE,

                 D3DMULTISAMPLE_4_SAMPLES, &numq ) ) )

{

    MultisampleDevtype=D3DDEVTYPE_REF;

}

if( SUCCEEDED(g_pD3D->CheckDeviceMultiSampleType(

                 D3DADAPTER_DEFAULT,

                 D3DDEVTYPE_HAL , D3DFMT_X8R8G8B8, FALSE,

                 D3DMULTISAMPLE_4_SAMPLES, NULL ) ) )

{

    MultisampleDevtype=D3DDEVTYPE_HAL;

}

if(MultisampleDevtype==(D3DDEVTYPE )-1)

    return E_FAIL;

2.创建使用多重采样的Direct3D设备

函数IDirect3D9∷CreateDevice()的第5个参数D3DPRESENT_PARAMETERS结构的MultiSampleType成员为将要设置的多重采样类型,SwapEffect成员为D3DWAPEFFECT _DISCARD,对参数赋值后创建Direct3D设备。下列代码创建Direct3D设备,并使用9点采样:

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory( &d3dpp, sizeof(d3dpp) );

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

d3dpp.EnableAutoDepthStencil = TRUE;

d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

d3dpp.MultiSampleType=D3DMULTISAMPLE_4_SAMPLES;

if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, MultisampleDevtype, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,

            &d3dpp, &g_pd3dDevice ) ) )

{

    return E_FAIL;

}

3.启用多重采样的全景图形反锯齿

调用函数IDirect3DDevice9∷SetRenderState(),设置第一个参数为D3DRS_ MULTISAMPLEANTIALIAS,第二个参数为bool类型的TRUE,激活多重采样:

g_pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS ,TRUE);

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论