在3D场景中显示汉字
TWaver 3D for Flex本身支持3D文字的显示,但是用户必须嵌入一套字库才可以。使用传统的方式,显示3D文字。
[Embed("extrusionfonts.swf", mimeType="application/octet-stream")] private var font:Class; ..... twaver.threed.util.Util3D.checkTextFont(font); var network:Network3D = new Network3D(); network.applyHoverCamera(-180,10,5,300); this.addElement(network); var n2:Node = new Node(); n2.setStyle(Style3D.THREED_SHAPE_TYPE,Consts3D.THREED_SHAPE_TYPE_TEXT); n2.setStyle(Style3D.TEXT_FONT_SIZE,20); n2.setStyle(Style3D.TEXT_FONT_3D,"Arial"); n2.setStyle(Style3D.TEXT_WIDTH,200); n2.setStyle(Style3D.TEXT_CONTENT,"Hello"); n2.setStyle(Style3D.MAPPINGTYPE,Consts3D.MAPPINGTYPE_COLOR); n2.setStyle(Style3D.MATERIAL_COLOR,0x00FF00); n2.setStyle(Style3D.PROPERTY_SPACE_LOCATION,new Vector3D(100,0,0)); n2.setStyle(Style3D.BOTH_SIDES_VISIBLE,true); network.elementBox.add(n2); network.showAxises();
对于国内客户来说,这一点就有些痛苦了,一个中文字库的体积太大,嵌入发布程序中的话,会增大发布包的大小,及时是远程加载,也会因为其恐怖的体积,让用户的web化设计面临网络情况的挑战。当然为了用户也可以去裁剪一个字库,把自己会用到的文字收入其中,做个可控数量级的枚举,但是实时系统在运行过程中,会碰到什么样的汉字也是个未知,很难做裁剪的时候枚举尽所需要的汉字。这个问题一直苦苦萦绕在每个人的心头。
,,,,,,
,,,,,,
终于,TWaver 3D支持动态贴图了,这里的动态贴图已经不只是说可以动态切换贴图资源的来源,更重要的是可以动态切换上在内存中生成的BitmapData对象。大家都知道,Flex的BitmapData支持将其UIComponent绘制出来,这一下子为我们解决汉字显示提供了一个非常便捷的方式,那就是我们把汉字写进一个TextInput组件中去,然后再把这个组件画到一个BitmapData对象中,然后在将这个对象变成我们一个3D对象的贴图(例如一个Plane,一个Billboard,一个Cube等等)。ok,动手试验
按步就班,搭建一个3D场景,并且放入一个Plane对象。
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:ns="http://www.servasoft.com/twaver/3D" creationComplete="init()"> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ import twaver.*; import twaver.threed.event.*; import twaver.threed.util.*; private var databox:ElementBox; private var source:BitmapData; private var rect:Rectangle = new Rectangle(0,0,128,128); private var text:TextInput = new TextInput(); private var n1:Node; private function init():void{ prepare(); setupNetwork(); fillData(); network.showAxises(); network.callLater(function():void{ paintTexture(n1); }); } private function fillData():void{ n1 = NodeUtils.buildPlane(new Vector3D(0,0,0),new Vector3D(32,0,32),new Vector3D(90,0,0),Consts3D.MAPPINGTYPE_COMMON,source,true); databox.add(n1); } private function setupNetwork():void{ databox = network.elementBox; network.applyHoverCamera(-180,10,5,200); } ]]> </fx:Script> <ns:Network3D id="network" width="100%" height="100%"/> </s:Application>
我们会得到一个类似截图的效果,一个只有一个plane对象的3D场景:
现在就让我们用点小技巧,把自己需要的汉字画到3D场景中去吧。
我们需要针对前面的代码做点改进,引入一个TextInput组件,用来呈现汉字;然后我们需要动态地生成一个BitmapData对象,把这个汉字画到指定的图片中去,最后我们再把内存里的这个画好了汉字的图片作为贴图,贴到plane上去。
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:ns="http://www.servasoft.com/twaver/3D" creationComplete="init()"> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ import mx.controls.TextInput; import twaver.*; import twaver.threed.event.*; import twaver.threed.util.*; private var databox:ElementBox; private var source:BitmapData; private var rect:Rectangle = new Rectangle(0,0,128,128); private var text:TextInput = new TextInput(); private var n1:Node; private function init():void{ prepare(); setupNetwork(); fillData(); network.showAxises(); network.callLater(function():void{ paintTexture(n1); }); } private function prepare():void{ text.width = 150; text.height = 60; text.setStyle('borderStyle','none'); text.text = "你好"; text.alpha = 1; this.addElement(text); text.visible = false; } private function fillData():void{ n1 = NodeUtils.buildPlane(new Vector3D(0,0,0),new Vector3D(32,0,32),new Vector3D(90,0,0),Consts3D.MAPPINGTYPE_COMMON,source,true); databox.add(n1); } private function setupNetwork():void{ databox = network.elementBox; network.applyHoverCamera(-180,10,5,200); } private function setTexture(n:Element,source:BitmapData):void{ var type:String = n.getStyle(Style3D.THREED_SHAPE_TYPE); switch(type){ case Consts3D.THREED_SHAPE_TYPE_BILLBOARD: n.setStyle(Style3D.BILLBOARD_TEXTURE,source); break; case Consts3D.THREED_SHAPE_TYPE_PLANE: n.setStyle(Style3D.PLANE_MATERIAL,source); break; default: n.setStyle(Style3D.MAPPING_COMMON_PATH,source); break; } } private function paintTexture(n:Element):void{ source = new BitmapData(32,32,true,0x00000000); text.text = n.getClient("label"); source.fillRect(rect,0x00000000); source.draw(text); setTexture(n,source); } ]]> </fx:Script> <ns:Network3D id="network" width="100%" height="100%"/> </s:Application>
再次运行,看看是不是能够得偿所愿。
吼吼,look,出来了,汉字出来了,没有引入任何字库,汉字就能够出现在我的3D场景中了。 8过,还是有些遗憾,那就是有时候如果让这汉字的内容动态地变化的时候,可怎么办??
......
......
有了!我动态切换不就行了!?说干就干,抓紧验证,重新打造代码,添加动态变化。
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:ns="http://www.servasoft.com/twaver/3D" creationComplete="init()"> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ import mx.controls.TextInput; import mx.events.PropertyChangeEvent; import twaver.*; import twaver.threed.event.*; import twaver.threed.util.*; private var databox:ElementBox; private var source:BitmapData; private var rect:Rectangle = new Rectangle(0,0,128,128); private var text:TextInput = new TextInput(); private var n1:Node; private function init():void{ prepare(); setupNetwork(); fillData(); network.showAxises(); network.callLater(function():void{ paintTexture(n1); }); var timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER,function(evt:Event):void{ var date:Date = new Date(); n1.setClient("label",date.seconds); }); timer.start(); } private function prepare():void{ text.width = 150; text.height = 60; text.setStyle('borderStyle','none'); text.text = "你好"; text.alpha = 1; this.addElement(text); text.visible = false; } private function fillData():void{ n1 = NodeUtils.buildPlane(new Vector3D(0,0,0),new Vector3D(32,0,32),new Vector3D(90,0,0),Consts3D.MAPPINGTYPE_COMMON,source,true); databox.add(n1); } private function setupNetwork():void{ databox = network.elementBox; network.applyHoverCamera(-180,10,5,200); databox.addDataPropertyChangeListener(this.onPropertyChanged); } private function onPropertyChanged(evt:PropertyChangeEvent):void{ var name:String = Util3D.getPropertyName(evt.property as String); if("label"==name){ var element:Element = evt.source as Element; paintTexture(element); } } private function setTexture(n:Element,source:BitmapData):void{ var type:String = n.getStyle(Style3D.THREED_SHAPE_TYPE); switch(type){ case Consts3D.THREED_SHAPE_TYPE_BILLBOARD: n.setStyle(Style3D.BILLBOARD_TEXTURE,source); break; case Consts3D.THREED_SHAPE_TYPE_PLANE: n.setStyle(Style3D.PLANE_MATERIAL,source); break; default: n.setStyle(Style3D.MAPPING_COMMON_PATH,source); break; } } private function paintTexture(n:Element):void{ source = new BitmapData(50,32,true,0x00000000); text.text = n.getClient("label"); source.fillRect(rect,0x00000000); source.draw(text); setTexture(n,source); } ]]> </fx:Script> <ns:Network3D id="network" width="100%" height="100%"/> </s:Application>
run again! Please check you screen!
大家一起来看看,哪里还有可以改进的,让我们把3D应用做得更彻底一些。
这里是文章中用到的UsingChineseCharacter.mxml代码(见原文最下方)。