翻译:Panda3D Manual/V. Programming with Panda/J. Text and Image Rendering

来源:互联网 发布:jenkins 插件源码下载 编辑:程序博客网 时间:2024/05/20 14:42

文本和图片渲染(Text and Image Rendering

Panda能够在屏幕或3维世界动态地绘制文字,它支持全部Unicode字符集,可以方便地渲染各国语言(包括亚洲语言,但要选择恰当的字体)。

Panda3D提供3种文本接口,你可以按需选择:TextNode是基础的文本渲染类,其他两个类都是构建于它之上;OnscreenTexTextNode的高层封装,OnscreenImageOnscreenTex类似,但它用于渲染图片;DirectLabel也是TextNode的高层封装,它集成到DirectGUI系统中。

国际字符集

Panda把输入的文本字符串默认当成iso8859格式,该格式在Linux上称为Latin-1,它的一个字符占用一个字节,支持绝大部分的字母文字,在大多数情况下适用。如果想用iso8859以外的字符,就必须使用更高级的编码系统如utf-8(一个字符可以占用1个、2个或3个字节)。为了使用utf-8,将下面这行写入你的Config.prc文件:

text-encoding utf8

然后,确保你输入的字符串是“utf-8”编码格式,例如你可以把你的Python源代码文件保存为“utf-8”格式(Windows下实现起来比较麻烦,我们推荐使用非微软的编辑器如EmacsEclipse)。

 

字体(Text Fonts

Panda3D支持多种字体,如果你的Panda3D在支持FreeType库的条件下编译(Panda3D发行版默认已经支持),就可以直接载入任意的TTF文件,或者其他FreeType支持的字体文件:

font = loader.loadFont('arial.ttf')

字体文件的搜索路径跟模型文件的搜索一样,你也可以给出字体文件的完全路径(注意使用Panda的路径格式)。

也可以使用panda提供的egg-mkfont命令行工具来预生成一种字体:

egg-mkfont -o arial.egg arial.ttf

该命令将生成一个egg文件(上例中为arial.egg文件)和一个相关的纹理文件,可以当成字体来载入:

font = loader.loadFont('arial.egg')

egg-mkfont工具有很多种参数,使用“egg-mkfont -h”列出全部选项。

预生成字体的好处是,(a)所得到的egg文件可以被不支持FreeTypePanda版本使用,(b)可以使用Photoshop等图像工具对得到的纹理图片进行修改,制作出某种文字效果。但从另一方面来说,你必须预先确定你要对哪种字符集使用字体,默认字符为ASCII字符。

Panda3D发行版的模型文件夹里有3种默认的字体文件,分别是“cmr12.egg”,一种罗马字体,“cmss12.egg”一种Sans-Serif 字体,“cmtt12.egg”一种Teletypewriter风格的固定宽度字体。这3种字体是由Metafont工具(Panda3D不包含)提供的免费字体。如果你没有加载其他字体,panda会使用一种默认的字体图片。

 

Text Node

Panda3D最基础的渲染文字方法就是TextNode接口,它用起来可能不如OnscreenTextDirectLabel对象那么方便,但它能对文字进行更多的控制。

使用TextNode,只需创建一个TextNode对象并调用setText()来设定要显示的文本,然后把TextNode连接到任何地方(可以把它放到aspect2d节点下,产生一个2维屏幕文本,或放到3维场景中)。注意,如果你把文本连接成render2daspect2d的子节点,你必须给它一个很小的缩小比例,因为在render2d中整个屏幕空间坐标大小仅为 (-1, 1)

text = TextNode('node name')
text.setText("Every day in every way I'm getting better and better.")
textNodePath = aspect2d.attachNewNode(text)
textNodePath.setScale(0.07)

注意TextNode的构造函数接受一个字符串名字,但该名字与要显示的文本没有任何关系,而且默认的文本颜色为白色;在此文本显示为黑色是为了便于读者阅读。

TextNode为我们提供大量的属性用以调节文字的形态。

字体

cmr12 = loader.loadFont('cmr12.egg')
text.setFont(cmr12)

你可以使用任何字体,包括TTF文件。见前面的字体部分。

缩小的大写字母

text.setSmallCaps(1)

setSmallCaps()接受一个布尔值;真的话将进入缩小大写模式。在这个模式下不显示小写字母,而大写字母要比真实的大小要小。它用于字体没有小写形式时。

可以指定“小写”字母的大小:

text.setSmallCapsScale(0.4)

值为1.0时与大写字母同等大小,0.5为一半大。默认值为0.8

倾斜

text.setSlant(0.3)

Slant用以模拟斜体字的效果。参数值为0.0时不倾斜,1.045度右倾。一般把值设为0.20.3的效果最好。可以用一个负数得到反方向的倾斜。

颜色

text.setTextColor(1, 0.5, 0.5, 1)

颜色值由rgba四个分量指定。注意a值如果不是1,文本将有些透明。

阴影

text.setShadow(0.05, 0.05)
text.setShadowColor(0, 0, 0, 1)

阴影只是一份文本的拷贝,在原文本后面显示,向右下方稍稍偏移一点位置,造成文字突出平面的感觉,尤其当文字颜色与背景颜色对比度不太高时很明显。(本例的文本颜色与背景相近都是粉色,可以看到其阴影效果很清晰)使用阴影的缺点就是渲染文字所需的多边形变成了2倍。

设置阴影需要调用两个函数:setShadow()接受一对数字参数,分别指定阴影向右、向下偏移的距离,用的是屏幕的长度单位;一般是一个很小的数如0.05setShadowColor()接受指定阴影的rgba颜色,默认为白色。

行宽(Wordwrap

默认状态下,文本将以一行显示,除非它包含换行字符。打开行宽将根据指定的行宽自动将文本分割为多行:

text.setWordwrap(15.0)

setWordwrap()的参数是每一行的最大宽度,用的是屏幕的长度单位。

对齐

文本默认为左对齐;从textNodePath.setPos()指定的位置开始向右显示文字。如果文本有多行,可以居中对齐或右对齐:

text.setAlign(TextNode.ACenter)

setAlign()的参数应该是TextNode.ALeftTextNode.ACenterTextNode.Aright其中之一。注意改变对齐方式将改变文本的起始位置。

边框

可以在文本外围绘制一个矩形边框:

text.setFrameColor(0, 0, 1, 1)
text.setFrameAsMargin(0.2, 0.2, 0.1, 0.1)

和阴影一样,设置边框需要两个函数:一个指定颜色,另一个指定边框的尺寸。setFrameAsMargin()指定4个参数,分别给出上下左右边框与文本之间的距离。全部4个都是0.0时边框紧紧包围文本(即使某些字体会超出边界)。

卡片(Card

最后,你可以在文本矩形之后绘制卡片效果:

text.setCardColor(1, 1, 0.5, 1)
text.setCardAsMargin(0, 0, 0, 0)

这样做使文本在相近的背景色下更方便阅读。通常卡片是半透明的,可以通过setCardColor()指定alpha值为0.20.3

setCardAsMargin()的参数与setFrameAsMargin()一样:分别是卡片上下左右的距离。(本例,我们同时设置了卡片和边框,你可以把卡片设成与文本吻合,而边框则要宽一些——setCardAsMargin()与上例中setFrameAsMargin()参数稍微不同。)

拾取(pick)一个TextNode

严格说来,TextNode没有几何数据,因此不能被拾取。

2种可能的办法:

1)在TexeNode后面创建一个卡片,使用CardMaker。可以用cardMaker.setFrame(textNode.getFrameActual())设定卡片的大小与文本框架相同。然后你需要将文本从卡片前面移出几英寸以消除Z-fighting现象,或者显示地把文本贴花(decal)到卡片上,如下:

card = NodePath(cardMaker.generate())

tnp = card.attachNewNode(textNode) card.setEffect(DecalEffect.make())

2)不要把TextNode直接连接到scene graph,而是把textNode.generate()返回的节点连接到scene graph。它是一个静态节点,包含渲染文本的多边形。之后文本若发生了改变,它并不自动更新此节点的几何模型;你必须用新的textNode.generate()代替旧的节点。但该节点是百分之百可以被拾取的。如果已经指定textNode.setCardDecal(1),那么该节点的第一个子节点应该就是卡片的几何模型。

 

OnscreenText

为方便用户使用,OnscreenText对象对TextNode进行了封装,使用它,可以快速地在屏幕上显示文本而不必创建TextNode和进行一系列格式设置。但它不提供TextNode那样对渲染的直接控制,也不支持DirectLableDirectGUI属性。显示普通文本时用OnscreenText是一种快捷的方法:

from direct.gui.OnscreenText import OnscreenText
textObject = OnscreenText(text = 'my text string', pos = (-0.5, 0.02), scale = 0.07)

OnscreenText对象继承自NodePath,因此可以对文本对象使用所有标准的NodePath操作。当你不再需要这些文本使,使用:

textObject.destroy()

下面是构造函数的几个关键参数:

text

要显示的文本。如果暂时没有可以留空,在以后通过setText()指定,但最好预先指定

style

一个在OnscreenText.py文件头部定义的预定义参数。你没有指定的参数会有一个默认的值;但是,指定的参数值将覆盖掉预定义的值

pos

文本在屏幕上的xy位置

scale

文本的大小。单个浮点数(通常是一个很小的数如0.07)或者是一个浮点数2元组,指定xy方向上的缩放值

fg

指定文本的(rgba)前景色,各分量的值可以是浮点数也可以是整数

bg

指定文本的(rgba)背景色,如果第四个分量a的值不为0,文本后面将出现一个对应颜色的卡片

shadow

指定阴影的(rgba)颜色,如果第四个分量a的值不为0,文字将产生阴影

frame

指定文本边框的(rgba)颜色,如果第四个分量a的值不为0,文字将有边框

align

TextNode.ALeftTextNode.ACenterTextNode.Aright三个值其中之一

wordwrap

文字的行宽,留空表示自动行宽

font

文本的字体

parent

文本的父节点NodePath,默认为aspect2d

mayChange

当文本属性需要在运行时动态改变时值设为真,值为假时属性保持不变(此时内存更加优化)。默认为假。

OnscreenImage的作用与OnscreenText新近,但它用于显示图片而不是文本。

 

OnscreenImage

OnscreenText一样,OnscreenImage是一个在屏幕上快速显示图片的方法,如果想要显示一张常规的图片而没有其他要求时,就使用OnscreenImage

from direct.gui.OnscreenImage import OnscreenImage
imageObject = OnscreenImage(image = 'myImage.jpg', pos = (-0.5, 0, 0.02))

可以使用setImage()来变换另一张图片:

imageObject.setImage('myImage2.jpg')

如果想去掉图片,如下:

imageObject.destroy()

下面列出该类构造器的关键参数:

image

要显示的图片或一个文件名。如果暂时没有可以留空,在以后通过setImage()指定

pos

在屏幕上的xyz位置,一个浮点3元组或一个向量,y值为0

scale

图片的大小,可以是单个浮点数,也可以是一个3元组或一个向量,y值应该为1

hpr

图片的hpr值,可以是一个浮点3元组或一个向量

color

图片的(rgba)颜色,通常是一个浮点或整数4元组

parent

图片的父节点NodePath,默认为aspect2d

注意:为了打开图像透明度,必须首先设置TransparencyAttrib,否则图片的透明部分将会显示为黑色:

from pandac.PandaModules import TransparencyAttrib
self.myImage=OnscreenImage(image = 'myImage.png', pos = (0, 0, 0))
self.myImage.setTransparency(TransparencyAttrib.MAlpha)

Panda不支持GIF,因此需要图片透明时应该使用PNGTGA

 

植入的文本属性(Embedded Text Properties

我们可以在一个段落当中改变文本的属性。为此,必须首先定义你想改变的文本属性,为每种属性命名。然后你就可以对字符串中的某些字符使用这些预定义的文本属性。

定义你的文本属性

可以创建任意多个TextProperties对象。每个对象保存一种文本属性,你可以对一个TextNode直接应用其中一种属性。这些属性包括单个字符属性如字体、颜色、阴影和倾斜,以及文字行格式属性如对齐和行宽。

tpRed = TextProperties()

tpRed.setTextColor(1, 0, 0, 1)

tpSlant = TextProperties()

tpSlant.setSlant(0.3)

tpRoman = TextProperties()

tpRoman.setFont(cmr12)

在一个TextProperties对象里你可以尽量多或尽量少地设定不同属性。只有你指定的属性才会应用到文本字符串;你没有指定的属性将维持不变。上例中,对某个文本字符串应用tpRed将只会把文本颜色变为红色;其他属性,如倾斜、阴影和字体,将维持原状。类似的,tpSlant只改变文字的倾斜度,tpRoman只改变字体。

注册新的TextProperties对象

需要一个指向全局TextPropertiesManager对象的指针:

tpMgr = TextPropertiesManager.getGlobalPtr()

在创建了TextProperties对象之后,你必须在TextPropertiesManager中注册,并为每个TextProperties对象取一个不同的名字:

tpMgr.setProperties("red", tpRed)

tpMgr.setProperties("slant", tpSlant)

tpMgr.setProperties("roman", tpRoman)

在文本字符串中引用TextProperties

现在你可以在字符串中放入特殊字符以激活这些变化的属性。为此,你将使用特殊字符‘/1’,或者ASCII0x01的字符。用两个‘/1’作为某种引号标出注册TextProperties时使用的名字,例如,‘/1red/1’激活tpRed,‘/1slant/1’激活tpSlant

序列‘/1red/1’作用相当于一个push命令,它把tpRed添加到当前的文本属性,先前的属性也被记录下来。要回到原来的属性状态,使用/2’字符。每个‘/2’将撤回最近一次‘/1name/1’激活的属性。

下面这个函数:

text.setText("Every day in /1slant/1every way/2 I'm /1red/1getting /1roman/1better /1slant/1and/2 better./2/2")

得到文本字符:

可以对任何产生文本的Panda结构使用这些特殊字符,包括TextNodeOnscreenText和任何DirectGui对象。

 
原创粉丝点击