嵌入式爱好者

查看: 9803|回复: 0

关于Direct3D11里汉字显示的一些思考

[复制链接]

153

主题

3910

帖子

4207

积分

AM5718通行证AM335x通行证i.MX6UL通行证i.MX RT通行证i.MX6Q通行证XX18通行证TCU通行证FCU1401通行证FCU1301通行证FCU11xx通行证

扫一扫,手机访问本帖
发表于 2012-11-10 09:49:20 | 显示全部楼层 |阅读模式
一、关于Direct2D与DirectWrite
先讲讲Direct2D和DirectWrite吧,下面关于字体讨论的时候有涉及到的地方。首先,Direct2D,它是DirectX11附带着发布的全新的二维图形API。顾名思义,看到Direct2D立马想到了它的大哥Direct3D。的确,Direct2D就是仿照着Direct3D来设计的,一款支持硬件加速的即时模式的二维图形API,因为支持硬件加速,Direct2D跑起来比GDI,GDI+效率都高。Direct2D用于取代DirectDraw,可用于2D游戏开发,但是目前世界范围内对Direct2D研究热情似乎不高。关于DirectWrite,它也是DirectX11中的新组件,主要是配合Direct2D使用,用于Direct2D应用程序中的字体和文字渲染。


二、Direct3D11里文字显示的一些讨论
然后我们就开始正题,Direct3D11中关于文字显示方案的一些讨论,特别是汉字的显示问题。
Direct3D11中微软非常奇葩地移除了ID3DXFont这个在Direct3D 9中非常好用的字体接口,这样导致了目前的Direct3D11中竟然没有一个官方的字体解决方案- -,这真心不科学。要在Direct3D11中显示文字,除去那已经在DirectX11中离我们远去的D3DXFont接口,我们还可以想到的字体解决方案主要就以下三种(且不管方法正不正确,我们先把他们列举出来):
第一种方案,用子图形贴图的方式。
第二种方案,与GDI/GDI+进行交互,使用GDI/GDI+中虽然相对Direct3D来说低效,却五脏俱全的2D字体体系。
第三种方案,使用DirectX11中专门设计用来加强Windows中2D文字显示质量的全新API——DirectWrite。
下面我们按上面的三种解决方案分别来进行一个小小的分析。
第一种方案,用子图形贴图的方式解决Direct3D11里文字显示的问题。没错,这个是目前使用最广泛的Direct3D11文字解决方案。这种方案理解起来很简单,就是我们实际上在屏幕上贴出的是图片,而这些图片的内容就是一个个字母,这些图片组合在一起,就成了一段段的文字。正所谓巧妇难为无米之炊,说到图片,就必须有图片素材文件。使用这种方案需要准备如下所示的纹理素材:


关于使用方法的细节,我们可以参考下面这张图片:



很容易理解,如果要显示“D”字母,就把素材文件中“D“字母所在的矩形区域贴到文字需要显示的地方,这样就完成了D字母的显示。
然后,问题就来了,我们可以看到,英文也就那26个字母,算上大写小写,阿拉伯数字,符号等等,需要的也就是数量不超过100个的字体元。然而中文怎么办?中华浩浩荡荡上下五千年,厚重的文化底蕴孕育了浩如烟海、动辄数千的汉字,且不说还有繁体字,古体字……
所以,第一种方案总结一下——Direct3D11中想用子图形贴图方式作为显示汉字的方案有待考究。
且我们不要被这忙忙多的汉字吓到。来看一下,这种字体图集的做法,可以使用GDI/GDI+的字体绘制API函数,配合FreeType(TTF字体),将某种特定字体的每个字母元(单个汉字)渲染到一张纹理图集上。然后制作出来的纹理图集可以作为cache使用,进行字体的显示。汉字虽然多,但是按理来说,是可以实现的。
实现代码如下:
[cpp] view plaincopyprint?

  • void SpriteBatch::DrawString(ID3D11DeviceContext* dc,  
  •     FontSheet& fs,  
  •     const std::wstring& text,  
  •     const POINT& pos,  
  •     XMCOLOR color)  
  • {  
  •     BeginBatch(fs.GetFontSheetSRV());  
  •     UINT length = text.length();  
  •     int posX = pos.x;  
  •     int posY = pos.y;  
  •     // For each character in the string...  
  •     for(UINT i = 0; i < length; ++i)  
  •     {  
  •         WCHAR character = text;  
  •         // Is the character a space char?  
  •         if(character == ' ')  
  •         {  
  •             posX += fs.GetSpaceWidth();  
  •         }  
  •         // Is the character a newline char?  
  •         else if(character == '\n')  
  •         {  
  •             posX = pos.x;  
  •             posY += fs.GetCharHeight();  
  •         }  
  •         else  
  •         {  
  •             // Get the bounding rect of the character on the fontsheet.  
  •             const CD3D11_RECT& charRect = fs.GetCharRect(character);  
  •             int width = charRect.right - charRect.left;  
  •             int height = charRect.bottom - charRect.top;  
  •             // Draw the character sprite.  
  •             Draw(CD3D11_RECT(posX, posY,  
  •                 posX + width,  
  •                 posY + height),  
  •                 charRect,  
  •                 color);  
  •             // Move to the next character position.  
  •             posX += width + 1;  
  •         }  
  •     }  
  •     EndBatch(dc);  
  • }  



第二种方案,我们可以让Direct3D11与GDI/GDI+进行交互,使用GDI/GDI+中虽然相对Direct3D来说低效,却五脏俱全的2D字体体系。
是的,与GDI/GDI+进行交互是目前Direct3D11里汉字显示主流方案,但是执行效率差强人意,个人觉得完全没有Direct3D 9中的ID3DXFont字体接口用起来舒服。
第三种方案,在Direct3D11中使用DirectX11中专门设计用来加强Windows中2D文字显示质量的全新API——DirectWrite。
这种方法行不行得通呢?
答案是不行的,这种方案不可取。目前Direct3D11无法直接与Direct2D/DirectWrite进行交互。很有意思的是,Direct3D 10同样也不能直接与Direct2D/DirectWrite交互,而Direct3D 10.1却可以通过GXDI进行共享表面来实现,浅墨记得好像Direct2D/DirectWrite就是在Direct3D 10.1的架构上进行开发的,所以他们的关系才会如此微妙。
总结起来就是,目前Direct3D11中可以使用的汉字显示解决方案,第一种与第二种方案都可以。
最后提一点,关于第三种方案,在Windows 8中倒是可以实现Direct3D与Direct2D(DirectWrite)之间的交互,这里有一个微软提供的代码示例可以下载:
Direct3D-Direct2D interop sample   运行环境:Windows 8 ,VS2012
不过鉴于目前Windows 8操作系统微不足道的市场占有率,我们也就把这种方式暂时忽略了。

技术支持电话:0312-3119192
技术支持邮箱:Linux@forlinx.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋| 飞凌嵌入式 ( 冀ICP备12004394号-1 )

GMT+8, 2024-12-28 02:57

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

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