DirectX 9.0c游戏开发手记之RPG编程自学日志之13: Drawing with DirectX Graphics (用DirectX图形绘图)(第6节)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]

 

这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第6节:Alpha Blending,也就是alpha混合。这一节的内容不多,所以就一次性讲完吧!

我们先将这一节的各小节的标题列在下面,以供大家参考:

1、 Enabling Alpha Blending (开启alpha混合)

2、 Drawing with Alpha Blending (用alpha混合进行绘图)

3、 Transparent Blitting with Alpha Testing (用alpha测试进行透明的blitting)

4、 Loading Textures with Color Keying (载入带颜色关键字的纹理)

5、 Enabling Alpha Testing (开启alpha测试)

6、 A Transparent Blitting Example (一个透明的blitting示例)

注意:原书这一节还包括几个小节关于光照的内容,不过我觉得还是把它们作为第7节内容讲述比较好。当然,这也就意味后面的章节号都有相应的延迟。

原文翻译:

===============================================================================

2.6 Alpha混合

想象着站在世界上最高的建筑之一上面,走向一个窗口,然后凝视着下面的广阔的城市。窗户玻璃的浅蓝色色调给了所有东西一种类似于早晨的天空的平静的着色。

想象着同样的场景,但是这次是用3-D图形的语言。整个世界都是由多边形构造的,这些多边形对于所有的实际应用来说都是实心的物体。你不能够看穿它们。那么如果你想在你的游戏中看透一扇窗户呢?刚才的那个窗户给予所有物体一种漂亮的色调的效果呢?

你想要的酷炫的效果不仅仅是刚才提到过的, 还有一些叫做透明blits(transparent blits)(也就是,你想要绘制一个一部分是完全透明的多边形)的东西。

将绘制一个部分透明(部分透明,是指图片的一部分是完全透明的,而不是指整个图片是半透明的)的物体用这样的术语描述,就是绘制一个中间有洞的墙。这个洞是完全透明的,尽管这墙是实心的;你穿过洞的视线不会受到阻碍。

这些效果通过使用一种叫做alpha混合(alpha blending)的技术是可能实现的。使用alpha混合,你可以改变一个多边形的透明度,使得你可以将它看穿。如果多边形是上了色的,那么其颜色将会与该多边形后面的所有东西进行混合。更奇妙的是,你还可以在这个多边形上运用纹理来创建一些很牛的效果!

一个物体的透明度叫做alpha值(alpha value)。你也许已经注意到了,Direct3D有好几种方式来使用alpha值。例如,使用纹理时,你可以设定一个使用alpha值的格式。alpha值被储存在一个叫做alpha通道(alpha
channel)的地方。

        注意

===============================================================================

        alpha通道是一个很像颜色成分(红、绿、蓝)的值。它设定要运用的透明度,表面上的每一个像素都有自己的一个alpha通道。

        这个alpha通道可以在1位和8位之间变动。如果你有一个8位的alpha通道,你可以设定256个alpha值(从0变动到255)。一个4位的alpha通道使用16个alpha值(0-15)。

===============================================================================

2.6.1 EnablingAlpha Blending (启用alpha混合)

启用Direct3D 的alpha混合函数很简单,只要使用IDirect3DDevice9::SetRenderState 函数并设定适当的渲染状态(render states)就OK了。第一个渲染状态是D3DRS_ALPHABLENDENABLE,它实际上启用了alpha混合:

// g_pD3DDevice =pre-initialized 3-D device object

// To enablealpha-blending, use:
g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENBALE,TRUE);

// Set the type ofalpha blending
g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND,                                                                 D3DBLEND_SRCALPHA);
g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND,                                                                 D3DBLEND_INVSRCALPHA);

// To disablealpha-blending, use:
g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENBALE,FALSE);

注意到在前面的代码中还有另外两个渲染状态(D3DRS_SRCBLEND和D3DRS_DESTBLEND)。这两个状态告诉Direct3D你想要在渲染的时候想要使用alpha的值。有时候,你会看到D3DRS_DESTBLEND值被设为D3DBLEND_ONE而不是D3DBLEND_INVSRCALPHA。我会在它们出现的时候向你指出来的。

2.6.2 Drawing withAlpha Blending (用alpha混合进行绘制)

为了使用alpha混合,你唯一需要的额外的信息是如何将alpha值添加到你的自定义顶点信息之中。你通过增加漫反射颜色成分到自定义顶点结构体和描述器中而实现这一点。当你定义漫反射颜色的时候,你必须设定alpha值。

下面的例子建立了一个简单的顶点结构,它储存了3-D坐标和漫反射颜色成分(它现在包含了一个alpha值):

// The custom vertexstructure and descriptor
typedef struct {
  FLOAT    x, y, z;
  D3DCOLOR diffuse;
} sVertex;
#define VertexFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE)

// Define 3 verticesin a local array
sVertex Verts = {
  {     0.0f,  100.0f,  0.0f,  D3DCOLOR_RGBA(255, 0, 0, 64)   },
  {   100.0f, -100.0f,  0.0f,  D3DCOLOR_RGBA(0, 255, 0, 128)  },
  { -100.0f,  - 100.0f,  0.0f, D3DCOLOR_RGBA(0, 0, 255, 255)  },
};

第一个顶点设成红色,并且是1.4半透明的(颜色的1.4会被混合)。第二个顶点是绿色的,使用1.2的半透明度度(颜色的1.2会被混合)。第三个顶点是蓝色的,并且是完全不透明的,表示不会有颜色被混合进来。(其实这段话很抽象。反正alpha值位0则表示完全透明,为255则表示完全不透明啦!)

如果你增加纹理映射坐标,并设置有效的纹理,你可以将漫反射颜色设为满值(红、绿、蓝都设为255),然后设置alpha值来混合纹理。

2.6.3 TransparentBlitting with Alpha Testing (用alpha测试进行透明的blitting)

        alpha测试(alpha testing)是这样一种技术,它在像素被绘制到显示屏之前测试其alpha值。

具有那些不落在某个特定范围内的alpha值的像素会被拒绝,因此就不会到达渲染阶段。跟前一节中获得半透明效果的方式类似,你可以使用alpha测试来渲染包含完全透明的部分的多边形。

使用前一节中的“墙中之洞”的例子,想象墙是一个多边形,然后你想要在其中心画一个洞。你想要这个多边形是完全不透明的(实心的),除了这个洞以外。你想要这个洞是完全透明的。为了实现这个效果,你使用一种称为透明的blit的技术(transparent blit),它使得你可以将一个纹理的某些部分排除掉,这样允许你可以从这些空洞中窥见背面的图形。

透明的blitting的秘密是建立你的纹理,并将单独的一个颜色设为颜色关键字。颜色关键字(color key)是在多边形被渲染时不会被绘制的颜色。

比如,如果你有一个纹理,它在中间有一个圆,被黑色所包围(如图2.17所示),你可以将颜色关键字设为黑色。当这个纹理被运用到一个多边形、该多边形被绘制的时候,Direct3D不会挥着这些黑色的像素,这样使得只有中间的圆会被渲染。

在实际应用中,并不是颜色关键字标记了透明的像素,而是像素的alpha值。为了让一个像素完全透明,它的alpha值必须被设为0。对于要被绘制的像素,alpha值必须被设为最高,也就是255。

正如你可能已经猜到的那样,与颜色关键字匹配的像素具有为0的alpha值;其他的所有像素具有更高的alpha值。

2.6.4 Loading Textureswith Color Keying (载入带颜色关键字的纹理)

当使用这种方式使用alpha测试的时候,你不需要在你的自定义顶点结构体或者描述器中设定漫反射颜色成分。alpha值直接储存在了纹理的像素数据中了。为了设置纹理像素数据中的alpha值,你使用扩展版本的D3DXCreateTextureFromFile函数载入纹理,如下所示:

HRESULT D3DXCreateTextureFromFileEx(
LPDIRECT3DDEVICE9      pDevice, // device object to create with
LPCSTR                pSrcFile, // filename of texture to load
UINT                     Width, // D3DX_DEFAULT
UINT                     Height,// D3DX_DEFAULT
UINT                 MipLevels, // D3DX_DEFAULT
DWORD                     Usage,// 0
D3DFORMAT                Format,// color format to use
D3DPOOL                    Pool,// D3DPOOL_MANAGED
DWORD                   Filter, // D3DX_FILTER_TRIANGLE
DWORD                 MipFilter,// D3DX_FILTER_TRIANGLE
D3DCOLOR              ColorKey, // Color key to use!
D3DXIMAGE_INFO       *pSrcInfo, // NULL
PALETTEENTRY         *pPalette, // NULL
LPDIRECT3DTEXTURE9 *ppTexture); // texture object to create

大多数参数使用上面显示的默认参数。你唯一需要提供的东西是要载入的位图的文件名、在创建纹理时要使用哪个3-D设备对象、在载入纹理时使用的颜色格式(以D3DFMT_开头的类型,它必须使用一个alpha值,例如D3DFMT_A8R8B8G8)以及颜色关键字(以D3DCOLOR的格式)。

在设定颜色关键字的值时,使用D3DCOLOR_RGBA 或D3DCOLOR_COLORVALUE 宏来设定你想要的颜色。例如,如果你想要避免黑色被绘制,那么使用一个颜色关键字来载入纹理:

D3DCOLOR_RGBA(0, 0,0, 255);

注意alpha 的值为255。这很重要!在载入位图文件(.BMP)的时候,你还必须将alpha的值设定为255。如果你在处理已经包含了alpha通道值的非位图文件(例如.TGA),你必须将设定的alpha值与储存在图像文件中的alpha值相匹配。

在此书中,我只使用位图文件,所以只需要记住使用等于255的alpha值。在将纹理的每个像素的alpha值都设定好后,使用alpha测试来基于像素的alpha值对其拒绝就是小意思了。

2.6.5 EnablingAlpha Testing (启用alpha测试)

一旦载入了纹理(并且设置了颜色关键字和alpha值),你可以在你初始化时或者渲染循环中添加下列代码来启用alpha测试:

// g_pD3DDevice = pre-initialized deviceobject
g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF,0x08);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC,                                                               D3DCMP_GREATEREQUAL);

D3DRS_ALPHAREF 状态很神奇,因为它告诉Direct3D允许哪些alpha值(从0到255之间变动)。在刚才展示的三种函数被调用后,所有的alpha值低于8的像素将会被拒绝。如果你正确地设定了颜色关键字,这三个函数会迫使所有具有零值的alpha的纹理从渲染阶段中排除掉,这样就使得它们透明了!

2.6.6 A Transparent Blitting Example (一个透明的Blitting 示例)

已经说够了;是时候给出一些代码了!下面是一个载入一个按钮图像并将之显示到屏幕上的小小例子。纹理的黑色像素被拒绝了,这样就允许背景颜色透出来:

// g_pD3DDevice = pre-initialized deviceobject
// Custom vertex structure and descriptor
typedef struct {
  FLOATx, y, z, rhw; // Screen coordinates
  FLOAT        u, v; // Texture coordinates
} sVertex;
#define VertexFVF (D3DFVF_XYZRHW |D3DFVF_TEX1)

// Vertex buffer and texture
IDirect3DVertexBuffer9 *g_pVB = NULL;
IDirect3DTexture9 *g_pTexture = NULL;
// Set up the vertex buffer and texture
// assuming a 400x400 window
BYTE *Ptr;
sVertex Verts[4] = {
  {  0.0f,  0.0f, 0.0f, 1.0f, 0.0f, 0.0f },
  {399.0f,   0.0f, 0.0f, 1.0f, 1.0f, 0.0f },
  {  0.0f, 399.0f, 0.0f, 1.0f, 0.0f, 1.0f },
  {399.0f, 399.0f, 0.0f, 1.0f, 1.0f, 1.0f }
};

// Create vertex buffer and stuff in data
g_pD3DDevice->CreateVertexBuffer(sizeof(sVertex)*4,0,                                                       VertexFVF,D3DPOOL_MANAGED, &g_pVB, NULL))) {
g_pVB->Lock(0,0, (void**)&Ptr, 0)))
memcpy(Ptr, Verts, sizeof(Verts));
g_pVB->Unlock();

// Get texture
D3DXCreateTextureFromFileEx(g_pD3DDevice, “button.bmp”,                                                        D3DX_DEFAULT,D3DX_DEFAULT, D3DX_DEFAULT, 0,                                         D3DFMT_A8R8G8B8,D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE,                              D3DX_FILTER_TRIANGLE,D3DCOLOR_RGBA(0,0,0,255), NULL,                                NULL,&g_pTexture);

// Set alpha testing
g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF,0x01);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC,                                D3DCMP_GREATEREQUAL);

// Clear device backbuffer
g_pD3DDevice->Clear(0, NULL,D3DCLEAR_TARGET,                                  D3DCOLOR_RGBA(0,128,128,255),1.0f, 0);
if(SUCCEEDED(g_pD3DDevice->BeginScene())){
    //Set stream source to particle vertex buffer
    g_pD3DDevice->SetStreamSource(0,g_pVB, 0, sizeof(sVertex));
    //Set vertex shader to particle type
    g_pD3DDevice->SetFVF(VertexFVF);
    //Set texture
    g_pD3DDevice->SetTexture(0,g_pTexture);
    //Draw vertex buffer
    g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0, 2);
    g_pD3DDevice->EndScene();
    //Clear texture
    g_pD3DDevice->SetTexture(0,NULL);
    //Turn off alpha testing
    g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE);
}

// Flip surfaces to display work
g_pD3DDevice->Present(NULL, NULL, NULL,NULL);

===============================================================================

好啦,翻译完这一节了!下面是时候送上代码了!跟上次一样,我将同时送上原书的代码以及本人更新后的代码。下面是我的更新版代码运行时的截图:

几点说明:

1、  更新版代码在前面的更新版Draw2D基础上更改而得。

2、  用了两幅美女图来让程序不至于太枯燥。

3、  原书是简单的带颜色的顶点组成的两个长方形,顶点颜色自带alpha值;而现在用的两幅图不带alpha值,所以如果按照原来的blend factor来写代码的话,那么效果很不理想(大家可以试试),所以我把它换成了另外一种blend factor,效果……还真不错!

最后给出下载地址:

alpha代码下载地址

时间: 2024-10-13 06:30:17

DirectX 9.0c游戏开发手记之RPG编程自学日志之13: Drawing with DirectX Graphics (用DirectX图形绘图)(第6节)的相关文章

DirectX 9.0c游戏开发手记之RPG编程自学日志之16: Drawing with DirectX Graphics (用DirectX图形绘图)(第10-12节)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]   这一次我们继续来讲述Jim Adams 老哥的RPG编程书籍第二版第二章的第10节:Particles (粒子),第11节:Depth Sorting and Z-Buffering (深度排序和Z-缓存),以及第12节:Working with Viewports (使用视口).这两节的内容都不多,所以就放在一期里面讲了. 原文翻译: ==========================

DirectX 9.0c游戏开发手记之RPG编程自学日志之15: Drawing with DirectX Graphics (用DirectX图形绘图)(第8-9节)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]   这一次我们继续来讲述Jim Adams 老哥的RPG编程书籍第二版第二章的第8节:Using Fonts(使用字体),和第9节:Billboards (广告牌).这两节的内容都不多,所以就放在一期里面讲了. 原文翻译: =============================================================================== 2.8 Us

DirectX 9.0c游戏开发手记之RPG编程自学日志之十 ——Drawing with DirectX Graphics (用DirectX图形绘图)(第4节)(C)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]   这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第4节:Getting Down to Drawing.这个超级长的节前两次讲了一多半内容,这一期我们要把它讲完. 再次将这一节的各小节的标题列在下面,以供大家参考: 1.Using Vertices (使用顶点) 2.Flexible Vertex Format (灵活顶点格式) 3.Using Vertex Buf

DirectX 9.0c游戏开发手记之RPG编程自学日志之九 ——Drawing with DirectX Graphics (用DirectX图形绘图)(第4节)(B)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]   这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第4节:Getting Down to Drawing.这个超级长的节上次讲到了顶点部分,这一期我们讲变换部分. 再次这一节的各小节的标题列在下面,以供大家参考: 1.Using Vertices (使用顶点) 2.Flexible Vertex Format (灵活顶点格式) 3.Using Vertex Buffe

DirectX 9.0c游戏开发手记之RPG编程自学日志之五 ——Drawing with DirectX Graphics (用DirectX图形绘图)(第1节)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]     从这一期起,我们进入了本书的第二部分,叫做DirectX Basics (DirectX基础).这一部分分为以下五个章节: 第2章 Drawing with DirectX Graphics (用DirectX图形进行绘图) 第3章 Interacting with DirectInput (与DirectInput互动) 第4章 Playing Sound and Music wit

DirectX 9.0c游戏开发手记之RPG编程自学日志之八 ——Drawing with DirectX Graphics (用DirectX图形绘图)(第4节)(A)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]           这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第4节:Getting Down to Drawing.这一节可以说是超级长了,所以我们就分3次来讲吧! 由于这一节的内容实在是太多,所以我这一节的各小节的标题列在下面,以供大家参考: 1.Using Vertices (使用顶点) 2.Flexible Vertex Format (灵活顶点格式) 3

DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之8: Chap10: Lighting

这一章讲的是光照.光照(lighting)是Direct3D中非常重要的概念,而与之相对应的是材质(material)的概念.如果没有材质的话,那么光照的作用也无法体现. 在较早一些的关于DirectX 9的编程入门书籍里,一般是使用D3DLIGHT9结构体来建立一个光源,而用D3DMATERIAL9结构体来定义物体的材质.我们要做的就是一些很琐碎的家务活,基本上就是创建这些结构体对象.设定其中的参数.启用光照之类的,至于具体实现的细节就非吾等所需(和所能)操心的了. 不过在我们的"龙书&quo

irectX 9.0c游戏开发手记之“龙书”第二版学习笔记之10: Chap12: Blending

这一章讲的是Blending,包括alpha 混合和alpha 测试两个方面.这一章的内容总体来说比较简单.然而,后面的习题却并不是很简单-- 下面是习题解答部分: 习题1部分: =============================================================================== 这道题让我们研究使用不同的blend factor和blendop所产生的效果.这个实现起来不难,我就不打算详细解释了,大家都能够看懂的.另外,为了简单,我就不

游戏开发手记:游戏逻辑模块组织及数据同步

这周工作主要分两部分,一是服务器这边的基础模块搭建,二是服务器与客户端通信模式以及数据同步等方案的协定和验证.总体来说进展不错. 服务器采用actor模式来构建,目前暂时把服务器上运行着的actor叫做service,每个service维护一个请求队列.一个goroutine不断取出请求并进行处理.一组负责处理消息的逻辑模块.游戏服务器里的每个玩家都是一个service,不隶属玩家的功能模块也作为service运行(如排行榜.聊天.公会),还有其他全局模块也作为独立的service运行(如玩家i