最初に戻って立方体を動かしてみましょう。
説明はいいからやり方を教えろという方向けの手順です。
- CubePic.asファイルをダウンロードしてFlashDevelopなどに取り込みます。Adbe Flash ではうまくいかないです。(FlashCS3以上ではEmbedは使えないし、その必要もないですね。画像はもっと簡単にクラス化できる訳ですから)
- FlashDevelopの場合asファイルはsrcフォルダに入れます。またsrcフォルダにはPV3Dから持って来たnochumpフォルダと orgフォルダも入れておきます。
- 書き出しサイズは315x250pxとします。FlashDevelopではメニューのプロジェクトからプロジェクトの設定で行います。
- srcフォルダーの中にimagesフォルダを作成してa.jpg,b.jpg,c.jpg,d.jpg,e.jpg,f.jpgの画像ファイル6枚を入れてください
- コンパイルするとbinフォルダにswf拡張子のファイルができています。これがFlashファイルです。
立方体を動かすソース
package { import flash.display.*; import flash.events.*; import flash.utils.*; import org.papervision3d.cameras.*; import org.papervision3d.core.effects.view.ReflectionView; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; public class CubePicembed2 extends ReflectionView { [Embed(source = 'images/a.jpg')] private var A:Class; [Embed(source = 'images/b.jpg')] private var B:Class; [Embed(source = 'images/c.jpg')] private var C:Class; [Embed(source = 'images/d.jpg')] private var D:Class; [Embed(source = 'images/e.jpg')] private var E:Class; [Embed(source = 'images/f.jpg')] private var F:Class; private var cube:Cube; public function CubePicembed2() { cube = createCube(); scene.addChild(cube); surfaceHeight = 0; camera.y = 600; stage.addEventListener(Event.ENTER_FRAME, onMove); } private function createCube():Cube { var materialsList:MaterialsList = new MaterialsList(); var imgArr:Array = [A, B, C, D, E, F]; var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left']; for (var i:int = 0; i < imgArr.length; i++ ) { var bitmap:Bitmap = new imgArr[i]() as Bitmap; var bitmapData:BitmapData = new BitmapData(200, 200); bitmapData.draw(bitmap); var material:BitmapMaterial = new BitmapMaterial(bitmapData, true); material.smooth = true; materialsList.addMaterial(material, faceArr[i]); } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1); return cube; } private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 50 * Math.sin(getTimer() / 4000); camera.z = 50 * Math.cos(getTimer() / 4000); startRendering(); } } }
ここから文法の説明です。
Embedとは
Embedは謎が多いです。使い方だけ覚えてしまいましょう。
//Embed使用例 [Embed(source = 'images/a.jpg')] private var A:Class; var img:Bitmap = new A() as Bitmap;
通常Embedを使用した画像表示はEmbedでロードしたい画像のファイル名を指定し,クラス型の任意の名前のクラスとして宣言します。次にそのクラスを使用してBitmapとしてインスタンス化します。(asを使用してキャストしています)その後はこのBitmapをaddChildしてやれば表示することが出来ます。
ソースについて
以下はEmbedを使用して各画像をクラスとして宣言しています。
[Embed(source = 'images/a.jpg')] private var A:Class; [Embed(source = 'images/b.jpg')] private var B:Class; [Embed(source = 'images/c.jpg')] private var C:Class; [Embed(source = 'images/d.jpg')] private var D:Class; [Embed(source = 'images/e.jpg')] private var E:Class; [Embed(source = 'images/f.jpg')] private var F:Class;
コンストラクタ
- Cubeクラスをインスタンス化するメソッドcreateMyCube()を実行。
- インスタンスcubeを表示リストに加えています。
- ENTER_FRAMEが実施されるごとに行われるリスナー関数 enterFrameHandleを宣言しています。
public function CubePicembed2() cube = createMyCube(); //--------------------------(1) scene.addChild(cube); //-----------------------------------(2) surfaceHeight = 0; camera.y = 600; stage.addEventListener(Event.ENTER_FRAME, enterFrameHandle);//-(3) }
createMyCubeメソッドの定義
createMyCubeメソッドはCubeクラスをインスタンス化するための処理をメソッドにしてまとめたものです。
以下Cube クラスのコンストラクタのパラメータです。
Cube(materials:MaterialsList, width:Number = 500, depth:Number = 500, height:Number = 500, segmentsS:int = 1, segmentsT:int = 1, segmentsH:int = 1, insideFaces:int = 0, excludeFaces:int = 0)
以下はMaterialsListクラスをインスタンス化して画像をそれぞれの面に設定し、最後にCubeクラスのインスタンス化で活用しています。
- MaterialsListをインスタンス化。MaterialsListとはキューブ体をインスタンス化する際に必要になる各側面のテクスチャーをリスト化するクラスです。
- 画像のクラスを配列にする
- キューブの面を配列にする
- for文で画像の配列をインスタンス化し、そのままBitmap型にキャストする
- 新規のBitmapDataクラスをインスタンス化する。サイズは縦横200px。なぜBitmapDataクラスが必要なのかは別途説明します。
- BitmapDataクラスのdrawメソッドで画像を描きます。
- BitmapMaterialをインスタンス化します
- materialをsmooth に表示させる処理
- addMaterialメソッドでmaterialsListに画像データを追加します
- materialsListを第1引数に入れてCubeクラスをインスタンス化します。
private function createMyCube():Cube { var materialsList:MaterialsList = new MaterialsList();//------------------(1) var imgClassArr:Array = [A, B, C, D, E, F];//---------------------------(2) var faceNameArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left'];//----(3) for (var i:int = 0; i < imgClassArr.length; i++ ) { var bitmap:Bitmap = new imgClassArr[i]() as Bitmap;//---------------(4) var bitmapData:BitmapData = new BitmapData(200, 200);//-----------(5) bitmapData.draw(bitmap);//-------------------------------------(6) var material:BitmapMaterial = new BitmapMaterial(bitmapData, true);//--(7) material.smooth = true;//---------------------------------------(8) materialsList.addMaterial(material, faceNameArr[i]);//----------------(9) } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1);//--------------(10) return cube; }
メソッドの詳細はPapervision3D 2.1 日本語 リファレンスガイドを参照してください。
onMove(e:Event)について
イベントのENTER_FRAMEが実行されるごとに実施されるリスナー関数です。
オブジェクトcubeのヨー(y軸を中心に回転)とピッチ(x軸を中心にした回転)、そしてy座標を決めカメラのx座標とz座標を決めてレンダリングを開始します。
startRendering();メソッドをsingleRender();と書き換えると鏡面効果が得られます。
private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 50 * Math.sin(getTimer() / 4000); camera.z = 50* Math.cos(getTimer() / 4000); startRendering(); }
一番下のstartRendering();メソドッドをsingleRender();メソッドに変更するだけで鏡面体が現れます。カメラの位置を多少変更します。
更に次のようにソースを一部加えると鏡面との境界面ができ上がります。
package { import flash.display.*; import flash.events.*; import flash.utils.*; import org.papervision3d.cameras.*; import org.papervision3d.core.effects.view.ReflectionView; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; public class CubePicembed extends ReflectionView { [Embed(source = 'images/a.jpg')] private var A:Class; [Embed(source = 'images/b.jpg')] private var B:Class; [Embed(source = 'images/c.jpg')] private var C:Class; [Embed(source = 'images/d.jpg')] private var D:Class; [Embed(source = 'images/e.jpg')] private var E:Class; [Embed(source = 'images/f.jpg')] private var F:Class; private var cube:Cube; private var earth:Plane; public function CubePicembed() { cube = createCube(); earth = createEarth(); scene.addChild(cube); scene.addChild(earth); surfaceHeight = 0; camera.y = 600; stage.addEventListener(Event.ENTER_FRAME, onMove); } private function createEarth():Plane { var earth:Plane = new Plane(new WireframeMaterial(0xFFFFFF, .5), 600, 600, 10, 10); earth.rotationX = 90; earth.rotationY = 20; earth.y = -100; return earth; } private function createCube():Cube { var materialsList:MaterialsList = new MaterialsList(); var imgArr:Array = [A, B, C, D, E, F]; var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left']; for (var i:int = 0; i < imgArr.length; i++ ) { var bitmap:Bitmap = new imgArr[i]() as Bitmap; var bitmapData:BitmapData = new BitmapData(200, 200); bitmapData.draw(bitmap); var material:BitmapMaterial = new BitmapMaterial(bitmapData, true); material.smooth = true; materialsList.addMaterial(material, faceArr[i]); } cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1); return cube; } private function onMove(e:Event):void { cube.yaw((200 - mouseX ) / 14); cube.pitch((200 - mouseY ) / 14); cube.y = Math.sin(getTimer() / 300) * -25 + 240; camera.x = 500 * Math.sin(getTimer() / 4000); camera.z = 500 * Math.cos(getTimer() / 4000); singleRender(); } } }
次は同じ立方体の回転でも画像の読み込みをサーバー上で行う方法です。