【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 5177|回复: 10

在DirectX 9.0中渲染文字

[复制链接]
发表于 2005-8-8 09:23:12 | 显示全部楼层 |阅读模式

9.   字体

本文翻译自《Introduction to 3D Game Programming with DirectX 9.0》第九章“Fonts”,敬请斧正!fficeffice" />

 

在游戏中,文字信息的显示是必不可少的。本章将讨论在D3D中使用的三种显示字体的方法。同样,这里只列出每种方法的演示程序的主体框架。学完本章将达到如下目标:

l          学习如何使用ID3DXFont接口渲染文字

l          学习如何使用CD3DFont类渲染文字

l          学习计算游戏帧速度的方法

l          学习使用D3DXCreateText函数创建3D文字

9.1. ID3DXFont

要在D3D程序输出文字,使用D3DX库提供的ID3DXFont接口很方便。其实该接口是使用GDI实现的,所以,其执行效率有所降低,但是它可以很方便地处理复杂的字体和格式。

9.1.1.    创建一个ID3DXFont

可使用D3DXCreateFontIndirect函数创建ID3DXFont

HRESULT WINAPI D3DXCreateFontIndirect(

    LPDIRECT3DDEVICE9 pDevice,

    CONST D3DXFONT_DESC *pDesc,

    LPD3DXFONT *ppFont

);

译者注:我所使用的DirectX SDKMicrosoft DirectX 9.0 SDK Update (Summer 2004),也就是使用DirectX 9.0c的那个版本,在较早的版本里,该函数的原型有所不同:第二个参数为CONST LOGFONT *pLogFont,它是GDI中的结构。以后,如无特别说明,将以DirectX 9.0 SDK Update (Summer 2004)中声明的函数原型为准,特此声明

 楼主| 发表于 2005-8-8 09:23:29 | 显示全部楼层

使用这个函数时,需要一个D3DXFONT_DESC结构:fficeffice" />

D3DXFONT_DESC d3dFont;

memset(&d3dFont,0,sizeof(d3dFont));

d3dFont.Height=25; // in logical units

d3dFont.Width=12;  // in logical units

d3dFont.Weight=500;// boldness, range 0(light) - 1000(bold)

d3dFont.Italic=FALSE;

d3dFont.CharSet=DEFAULT_CHARSET;

strcpy(d3dFont.FaceName,"Times New Roman");

ID3DXFont* font=0;

D3DXCreateFontIndirect(Device,&d3dFont,&font);

如果你使用的是LOGFONT结构,则:

LOGFONT lf;

ZeroMemory(&lf, sizeof(LOGFONT));

lf.lfHeight = 25; // in logical units

lf.lfWidth = 12; // in logical units

lf.lfWeight = 500; // boldness, range 0(light) - 1000(bold)

lf.lfItalic = false;

lf.lfUnderline = false;

lf.lfStrikeOut = false;

lf.lfCharSet = DEFAULT_CHARSET;

strcpy(lf.lfFaceName, "Times New Roman"); // font style

ID3DXFont* font = 0;

D3DXCreateFontIndirect(Device, &lf, &font);

另外,还可以使用D3DXCreateFont函数创建ID3DXFont的对象。

 楼主| 发表于 2005-8-8 09:23:56 | 显示全部楼层

9.1.2.    绘制文字

得到ID3DXFont接口后,绘制文字就很简单了,只需要调用ID3DXFont:rawText方法:fficeffice" />

INT ID3DXFont:rawText(

    LPD3DXSPRITE pSprite,

    LPCTSTR pString,

    INT Count,

    LPRECT pRect,

    DWORD Format,

    D3DCOLOR Color

);

l          pSprite –输出目标,为ID3DXSprite对象指针,可以为NULL值,此时字符串输出到默认对象

l          pString –需要输出的字符串

l          Count –字符串的字符数,如果为-1,则以0字符为结束标志

l          pRect –绘制字符串的区域

l          Format –文字的输出格式

l          Color –文字颜色

例如,可以这样使用该方法:

Font->DrawText(NULL,

    "Hello World", // String to draw.

    -1, // Null terminating string.

    &rect, // Rectangle to draw the string in.

    DT_TOP | DT_LEFT, // Draw in top-left corner of rect.

    0xff000000); // Black.

 楼主| 发表于 2005-8-8 09:24:35 | 显示全部楼层

9.1.3.    计算帧速率

帧速率用FPSFrame per Second)表示。首先声明三个全局变量:fficeffice" />

DWORD FrameCnt; // The number of frames that have occurred.

float TimeElapsed; // The time that has elapsed so far.

float FPS; // The frames rendered per second.

每秒计算一次FPS,这里计算的是平均值。我们也可以有足够的时间去读FPS值,而不至于因FPS的快速变化而产生较大误差。

每渲染一帧,累加一次帧数和所用的时间值:

FrameCnt++;

TimeElapsed += timeDelta;

这里的timeDelta表示两帧间的时间间隔。每过去一秒,就可以使用下面的公式计算FPS了:

FPS = (float)FrameCnt / TimeElapsed;

计算完成后,需要将FrameCntTimeElapsed重新置0,这样下一次的计算结果才正确:

void CalcFPS(float timeDelta)

{

    FrameCnt++;

    TimeElapsed += timeDelta;

    if(TimeElapsed >= 1.0f)

    {

        FPS = (float)FrameCnt / TimeElapsed;

        TimeElapsed = 0.0f;

        FrameCnt = 0;

    }

}

 楼主| 发表于 2005-8-8 09:25:05 | 显示全部楼层

9.2. CD3DFont

DirectX SDK的安装目录下,提供了很多有用的代码CD3DFont类就位于其中。该类使用纹理三角形和Direct3D渲染文字,而不是通过GDI渲染,所以,其效率高于ID3DXFont。但是,CD3DFont不支持复杂的字体和文本格式,如果只需要高速渲染简单的字体,CD3DFont应是首选。fficeffice" />

使用CD3DFont类时,需要加入以下源文件:d3dfont.hd3dfont.cppd3dutil.hd3dutil.cppdxutil.hdxutil.cpp。这些文件可在DirectX SDK的安装目录下找到。DirectX 9.0 SDK Update (Summer 2004)中,该类却消失了,所以,该节内容只适用于较早的DirectX 9.0 SDK版本!

 楼主| 发表于 2005-8-8 09:25:18 | 显示全部楼层

9.2.1.    创建CD3DFont对象

创建CD3DFont的对象,就像创建一个普通的C++对象一样,其构造函数如下:fficeffice" />

CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L);

l          strFontName –所使用的字体名称

l          dwHeight –字体高度

l          dwFlags –可选的标志,如D3DFONT_BOLDD3DFONT_ITALICD3DFONT_ZENABLE等。

得到CD3DFont对象后,还需按顺序进行初始化,如:

Font = new CD3DFont("Times New Roman", 16, 0); // instantiate

Font->InitDeviceObjects( Device );

Font->RestoreDeviceObjects();

 楼主| 发表于 2005-8-8 09:25:30 | 显示全部楼层

9.2.2.    绘制文字

使用CD3DFont对象的如下方法渲染文字:fficeffice" />

HRESULT CD3DFont:rawText(FLOAT x, FLOAT y, DWORD dwColor,

    const TCHAR* strText, DWORD dwFlags=0L);

l          x –屏幕的x坐标

l          y –屏幕的y坐标

l          dwColor –文字的颜色

l          strText –要绘制的字符串

l          dwFlags –可选的渲染标志,可为0或下面的值:D3DFONT_CENTEREDD3DFONT_TWOSIDEDD3DFONT_FILTERED

例如:

Font->DrawText(20, 20, 0xff000000, “Hello, World”);

9.2.3.    资源清除

在删除CD3DFont对象前,还需作一些清除的工作:

Font->InvalidateDeviceObjects();

Font->DeleteDeviceObjects();

delete Font;

 楼主| 发表于 2005-8-8 09:26:20 | 显示全部楼层

9.3. 函数D3DXCreateText

该函数用于创建3D文字Mesh,原型如下:fficeffice" />

HRESULT WINAPI D3DXCreateText(

    LPDIRECT3DDEVICE9 pDevice,

    HDC hDC,

    LPCTSTR pText,

    FLOAT Deviation,

    FLOAT Extrusion,

    LPD3DXMESH *ppMesh,

    LPD3DXBUFFER *ppAdjacency,

    LPGLYPHMETRICSFLOAT pGlyphMetrics

);

l          pDevice –D3D设备

l          hDC –描述字体的设备上下文句柄

l          pText –要渲染的字符串

l          Deviation –TrueType字体的一个属性,该值不能小于0。如果为0,则使用字体的默认值

l          Extrusion –字体的深度,相对于Z坐标轴

l          ppMesh –返回生成的Mesh对象指针

l          ppAdjacency –返回邻接信息。如果不需要该信息,可使用NULL指针

l          pGlyphMetrics –结构GLYPHMETRICSFLOAT的数组,返回轮廓矩阵数据。如果不需要该数据,可以设该参数为NULL

 楼主| 发表于 2005-8-8 09:26:45 | 显示全部楼层

下面就举例说明如何使用该函数创建3D文字的Mesh对象。fficeffice" />

// Obtain a handle to a device context.

HDC hdc = CreateCompatibleDC( 0 );

// Fill out a LOGFONT structure that describes the font’s properties.

LOGFONT lf;

ZeroMemory(&lf, sizeof(LOGFONT));

lf.lfHeight = 25; // in logical units

lf.lfWidth = 12; // in logical units

lf.lfWeight = 500; // boldness, range 0(light) - 1000(bold)

lf.lfItalic = false;

lf.lfUnderline = false;

lf.lfStrikeOut = false;

lf.lfCharSet = DEFAULT_CHARSET;

strcpy(lf.lfFaceName, "Times New Roman"); // font style

// Create a font and select that font with the device context.

HFONT hFont;

HFONT hFontOld;

hFont = CreateFontIndirect(&lf);

hFontOld = (HFONT)SelectObject(hdc, hFont);

// Create the 3D mesh of text.

ID3DXMesh* Text = 0;

D3DXCreateText(_device, hdc, "Direct3D", 0.001f, 0.4f, &Text, 0, 0);

// Reselect the old font, and free resources.

SelectObject(hdc, hFontOld);

DeleteObject( hFont );

DeleteDC( hdc );

这时,Mesh对象已经得到了。最后,直接使用DrawSubset方法渲染即可:

Text->DrawSubset( 0 );

译者注:上面的例子代码,使用的是较早的DirectX 9.0 SDK,不是Summer 2004版本。

 楼主| 发表于 2005-8-8 09:26:55 | 显示全部楼层

9.4. 总结

l          如果需要渲染较复杂的字体和格式,使用ID3DXFont接口会很方便。但是该接口是使用GDI实现的,故效率较低。fficeffice" />

l          CD3DFont类可以快速的渲染简单的字体。该类实用D3D的纹理三角形渲染文字,故速度较ID3DXFont为快。

l          使用D3DXCreateText函数可以创建文字的3D网格模型。

 楼主| 发表于 2007-4-5 22:35:38 | 显示全部楼层
DT_BOTTOM:将正文调整到矩形底部。此值必须和DT_SINGLELINE组合。  
   
          DT_CALCRECT:决定矩形的宽和高。如果正文有多行,DrawText使用lpRect定义的矩形的宽度,并扩展矩形的底训以容纳正文的最后一行,如果正文只有一行,则DrawText改变矩形的右边界,以容纳下正文行的最后一个字符,上述任何一种情况,DrawText返回格式化正文的高度而不是写正文。  
   
          DT_CENTER:使正文在矩形中水平居中。  
   
          DT_EDITCONTROL:复制多行编辑控制的正文显示特性,特殊地,为编辑控制的平均字符宽度是以同样的方法计算的,此函数不显示只是部分可见的最后一行。  
   
          DT_END_ELLIPSIS或DT_PATH_ELLIPSIS:可以指定DT_END_ELLIPSIS来替换在字符串末尾的字符,或指定DT_PATH_ELLIPSIS来替换字符串中间的字符。如果字符串里含有反斜扛,DT_PATH_ELLIPSIS尽可能地保留最后一个反斜杠之后的正文。  
   
          DT_EXPANDTABS:扩展制表符,每个制表符的缺省字符数是8。  
   
          DT_EXTERNALLEADING:在行的高度里包含字体的外部标头,通常,外部标头不被包含在正文行的高度里。  
   
          DT_INTERNAL:用系统字体来计算正文度量。  
   
          DT_LEFT:正文左对齐。  
   
          DT_MODIFYSTRING:修改给定的字符串来匹配显示的正文,此标志必须和DT_END_ELLIPSIS或DT_PATH_ELLIPSIS同时使用。  
   
          DT_NOCLIP:无裁剪绘制当DT_NOCLIP使用时DrawText的使用会有所加快。  
   
          DT_NOPREFIX:关闭前缀字符的处理,通常DrawText解释助记前缀字符,&为给其后的字符加下划线,解释&&为显示单个&。指定DT_NOPREFIX,这种处理被关闭。  
   
          DT_RIGHT:正文右对齐。  
   
          DT_RTLREADING:当选择进设备环境的字体是Hebrew或Arabicf时,为双向正文安排从右到左的阅读顺序都是从左到右的。  
   
          DT_SINGLELINE:显示正文的同一行,回车和换行符都不能折行。  
   
          DT_TABSTOP:设置制表,参数uFormat的15"C8位(低位字中的高位字节)指定每个制表符的字符数,每个制表符的缺省字符数是8。  
   
          DT_TOP:正文顶端对齐(仅对单行)。DT_VCENTER:正文水平居中(仅对单行)。  
   
          DT_WORDBREAK:断开字。当一行中的字符将会延伸到由lpRect指定的矩形的边框时,此行自动地在字之间断开。一个回车一换行也能使行折断。  
   
          DT_WORD_ELLIPSIS:截短不符合矩形的正文,并增加椭圆。  
   
          注意:DT_CALCRECT,   DT_EXTERNALLEADING,   DT_INTERNAL,   DT_NOCLIP,   DT_NOPREFIX值不能和DT_TABSTOP值一起使
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2024-5-22 03:00

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表