Alternativa3D 8.8.0でTextureMaterialのBitmapDataを動的に変更してみる。
textureウィンドウをクリックする
TextureMaterialをBitmapDataから作るにはBitmapDataからBitmapTextureResourceを作り、それを使うのでちょっとひと手間。
このBitmapTextureResourceはdataプロパティを持ち、ここからテクスチャのBitmapDataをget/setできる。
ところが、CPU側で書き換えただけではGPUに伝わらず、変更が反映されない。
Resourceを変えたときは必ずupload()しましょう。それだけの話。
package { import alternativa.engine3d.materials.TextureMaterial; import alternativa.engine3d.primitives.GeoSphere; import alternativa.engine3d.resources.BitmapTextureResource; import com.bit101.components.Window; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; /** * ... * @author */ [SWF(width="550",height="400")] public class Main extends AlBasicView { private var canvas:Sprite; //dummy canvas to detect MouseEvent private var textureBd:BitmapData; private var textureResource:BitmapTextureResource; public function Main():void { camera.view.backgroundColor = 0x333333; var dummy:Sprite = createDummy(stage.stageWidth, stage.stageHeight); addChild(dummy); new RoundCameraController(camera, dummy); // var sphere:GeoSphere = new GeoSphere(300, 8); textureBd = new BitmapData(256, 256, false, 0xffffff); textureResource = new BitmapTextureResource(textureBd); sphere.setMaterialToAllSurfaces(new TextureMaterial(textureResource)); scene.addChild(sphere); //2D var window:Window = new Window(this, 0, 0, "texture"); canvas = createDummy(256, 256); window.content.addChild(canvas); window.hasMinimizeButton = true; window.setSize(256, 256 + 20); window.content.addChild(new Bitmap(textureBd)); // request(); } private function createDummy(width:Number, height:Number):Sprite { var dummy:Sprite = new Sprite(); dummy.graphics.beginFill(0x0, 0); dummy.graphics.drawRect(0, 0, width, height); dummy.graphics.endFill(); return dummy; } override public function onContextCreate(e:Event):void { super.onContextCreate(e); canvas.addEventListener(MouseEvent.CLICK, onClick); } private function onClick(e:MouseEvent):void { textureBd.copyPixels(new BitmapData(16, 16, false, 0xffffff * Math.random()), new Rectangle(0, 0, 16, 16), new Point(canvas.mouseX - 8, canvas.mouseY - 8)); textureResource.upload(context3D); } } }
今回も例のクラスを。あとはminimalcomps。
createDummy()はただSpriteに透明な矩形を書くメソッド。2回使うからまとめただけ。
今回は2Dのstageにオブジェクトがあり、その上ではRoundCameraControllerのマウスイベントを反応させたくなかったのでダミーを2Dの一番下に置いてる。
2Dの部分はクリックした座標のBitmapDataにランダムな色の矩形をcopyPixels()するというもの。単純なお絵描き機能。
Bitmapはマウスイベントを受け取らないからこれも下にダミーのキャンバスを置いてそいつにクリックの座標を取得させてる。
Bitmapdataを動的に書き換える部分は今回の記事の本質じゃないから飛ばして。
BitmapTextureResourceはBitamapDataへの参照を持っているのでtextureResourceはBitmapDataが更新されるとリアルタイムに反映される。
ところが、このBitmapTextureResourceとGPU上のテクスチャは別物なわけだ。
なので変更を3Dに反映させたいならそのたびに
textureResource.upload(context3D);
とGPUにResourceをアップロードしなくちゃならない。
このへんはGeometryと一緒。
このマウスイベントはonContextCreate()をオーバーライドしてそこでaddEventListener()している。
コンストラクタに書くと、context3Dを受け取る前にupload()しちゃうかもしれないから。
動的にBitmapDataを上書きする話だったけど、textureResource.data=newBdで他の画像に差し替えることもできるよ。
そんな場合もそのあとしっかりupload()。
ところが、テクスチャは画像データだから当然重い。
毎フレーム多量のテクスチャを動的変更するのは速度的によろしくないだろう。
ATF(Adobe Texture Format)フォーマットなるGPUで扱える圧縮された画像形式が開発され、Alternativa3D 8もこの画像フォーマットを扱うことができる(CompressedTextureResourceクラス)。
現在のところはAdobe側でATFの変換方法が発表されていなようだが、そのうち使えるようになるこのATFなら転送速度もあがるんだろう。たぶん。
Author:9ballsyn
ActionScriptについて
最近はMolehill