2011年10月アーカイブ

サーバー上の画像を読み込んで、立方体を動かしてみましょう。

このやり方だと画像をサーバー上で読み込みますので、プログラムが苦手なweb担当者でも気軽に立方体の画像を変更することができます。難点は画像を読み込む間に立方体が黒く表示されることがあるかもしれない事です。

説明はいいからやり方を教えろという方向けの手順です。

  1. CubePic.asファイルをダウンロードしてFlashDevelopなどに取り込みます。
  2. FlashDevelopの場合asファイルはsrcフォルダに入れます。またsrcフォルダにはPV3Dから持って来たnochumpフォルダと orgフォルダも入れておきます。
  3. 書き出しサイズは315x250pxとします。FlashDevelopではメニューのプロジェクトからプロジェクトの設定で行います。
  4. binフォルダーの中にimagesフォルダを作成してimg0.jpgからimg5.jpgの画像ファイル6枚を入れてください。Embedを使用する場合はsrcフォルダに入れましたが今度はbinフォルダです。間違わないようにしましょう。
  5. コンパイルするとbinフォルダにswf拡張子のファイルができています。これがFlashファイルです。binフォルダに入っているファイルとフォルダをそのままサーバーの目的のフォルダににアップします。
  6. 画像を変更する場合はサーバーにアップしたimagesフォルダ内のimg0.jpgからimg5.jpgまでの画像を希望の画像に上書きします。必ずファイル名はimg0.jpgからimg5.jpgまでの画像を使用します。サーバー上の画像ファイルとswfファイルとhtmlファイルは必ずbinフォルダ内と同じ階層構造にします。そうしないと画像が正しく表示されません。

 

立方体を動かすソース

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 CubePic extends ReflectionView {                       
        private var cube:Cube;
        public function CubePic() {
            cube = createCube();
            scene.addChild(cube);
            camera.y = 600;
            addEventListener(Event.ENTER_FRAME, onMove);
            }

        private function createCube():Cube {
            var materialsList:MaterialsList = new MaterialsList();
            var imgArr:Array = new Array();
            for (var i:int = 0; i < 6; i++) {
                imgArr[i] = new BitmapFileMaterial('images/img'+i+'.jpg');
            }           
            var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left'];
            for (var j:int = 0; j < imgArr.length; j++ ) {
                var bitmap:BitmapFileMaterial = imgArr[j];
                bitmap.smooth = true;
                materialsList.addMaterial(bitmap, faceArr[j]);
                }
            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();
        }
    }
}

ここから文法の説明です。

ソースについて

createMyCubeメソッドの定義

createMyCubeメソッドはCubeクラスをインスタンス化するための処理をメソッドにしてまとめたものです。createMyCubeメソッドの中身が前回のEmbedを使用したものと変わるだけです。他のソースは変更する必要がありません。

  1. MaterialsListをインスタンス化。MaterialsListとはキューブ体をインスタンス化する際に必要になる各側面のテクスチャーをリスト化するクラスです。
  2. 画像のクラスを配列にする
  3. for文で画像の配列をインスタンス化し、BitmapFileMaterialクラスをインスタンス化して画像をロードする。それを配列に代入しています。「3Dを描画する(4)〜カスタムクラス作成/画像の貼付け」で行った画像の張り付けを配列とfor文を使って処理しています。
  4. 各面を配列として格納します。
  5. BitmapFileMaterial型の変数に画像を代入します。
  6. addMaterialメソッドでmaterialsListに画像データを追加します
  7. materialsListを第1引数に入れてCubeクラスをインスタンス化します。
        private function createCube():Cube {
            var materialsList:MaterialsList = new MaterialsList();//--------------(1)
            var imgArr:Array = new Array();//-------------------------------(2)
            for (var i:int = 0; i < 6; i++) {
                imgArr[i] = new BitmapFileMaterial('images/img'+i+'.jpg');//-------(3)
            }           
            var faceArr:Array = ['front', 'back', 'top', 'bottom', 'right', 'left'];//------(4)
            for (var j:int = 0; j < imgArr.length; j++ ) {
                var bitmap:BitmapFileMaterial = imgArr[j];//---------------------(5)
                bitmap.smooth = true;
                materialsList.addMaterial(bitmap, faceArr[j]);//-------------------(6)
                }
            cube = new Cube(materialsList, 120, 120, 120, 1, 1, 1);//------------(7)
            return cube;
        }

次はHTML5とCSS3そしてJavaScriptに取り組みたいと思います。比較的簡単な内容から入るつもりです。ActionScriptについては機会をみて補填していきます。

ソースサンプルはこちらから右クリックでダウンロード

出来上がりサンプルはこちらから右クリックでダウンロード

<author Tahara>

もしよろしければ、下ボタンをクリックお願いします。

 

最初に戻って立方体を動かしてみましょう。

説明はいいからやり方を教えろという方向けの手順です。

  1. CubePic.asファイルをダウンロードしてFlashDevelopなどに取り込みます。Adbe Flash ではうまくいかないです。(FlashCS3以上ではEmbedは使えないし、その必要もないですね。画像はもっと簡単にクラス化できる訳ですから)
  2. FlashDevelopの場合asファイルはsrcフォルダに入れます。またsrcフォルダにはPV3Dから持って来たnochumpフォルダと orgフォルダも入れておきます。
  3. 書き出しサイズは315x250pxとします。FlashDevelopではメニューのプロジェクトからプロジェクトの設定で行います。
  4. srcフォルダーの中にimagesフォルダを作成してa.jpg,b.jpg,c.jpg,d.jpg,e.jpg,f.jpgの画像ファイル6枚を入れてください
  5. コンパイルすると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;

コンストラクタ

 
     
  1. Cubeクラスをインスタンス化するメソッドcreateMyCube()を実行。
  2.  
  3. インスタンスcubeを表示リストに加えています。
  4.  
  5. ENTER_FRAMEが実施されるごとに行われるリスナー関数 enterFrameHandleを宣言しています。
  6.  
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クラスのインスタンス化で活用しています。

  1. MaterialsListをインスタンス化。MaterialsListとはキューブ体をインスタンス化する際に必要になる各側面のテクスチャーをリスト化するクラスです。
  2. 画像のクラスを配列にする
  3. キューブの面を配列にする
  4. for文で画像の配列をインスタンス化し、そのままBitmap型にキャストする
  5. 新規のBitmapDataクラスをインスタンス化する。サイズは縦横200px。なぜBitmapDataクラスが必要なのかは別途説明します。
  6. BitmapDataクラスのdrawメソッドで画像を描きます。
  7. BitmapMaterialをインスタンス化します
  8. materialをsmooth に表示させる処理
  9. addMaterialメソッドでmaterialsListに画像データを追加します
  10. 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();
        }
    }
}

次は同じ立方体の回転でも画像の読み込みをサーバー上で行う方法です。

ソースサンプルはこちらから右クリックでダウンロード

出来上がりサンプルはこちらから右クリックでダウンロード

<author Tahara>

もしよろしければ、下ボタンをクリックお願いします。

補助資料です。
詳細な説明はありませんが参考にしてください。

物理運動シミュレーションPDFファイルはこちら



もしよろしければ、下ボタンをクリックお願いします。

 

今回は前回まで作成した3Dの球体を動かしてみましょう。

説明はいいからやり方を教えろという方への手順です。

  1. 前回までの方法で作成した3Dの球体のソースを用意します。
  2. addEventListenerでENTER_FRAMEイベントを待ち受けて リスナー関数を実行する。
  3. リスナー関数で球体を動かす処理を行う。

 

3D球体を動かすソース

package 
{
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.view.*;
    import org.papervision3d.materials.*;
    import flash.events.Event


    public class Main4 extends BasicView
    {

        public function Main4():void 
        {
            var sphere:Sphere = new Sphere(null,60,10,10);
            scene.addChild(sphere);
            stage.addEventListener(Event.ENTER_FRAME, onmove);
            var houkou:int =1;
            function onmove ():void {
                sphere.x += 10 * houkou;
                sphere.rotationY += 10 ;
                if (sphere.x < 0 || sphere.x > stage.stageWidth) {
                    houkou *= -1;
                }
            }
            startRendering();
        }       
    }   
}

ここから文法の説明です。

addEventListeneとは

stage.addEventListener(Event.ENTER_FRAME, onmove);

「インスタンスbox_mcをクリックしたらtest()を実行する」といったインタラクティブ(対話式)な処理を考えたとき、この中には「1どこで、2何が起きたら、3どうする」の3つの要素が含まれています。このイベント処理をスクリプトではaddEventListener()というメソッドを使って設定します。書式は次のようになります。イベントが発生するオブジェクトに対して、イベントタイプとリスナー関数をペアにしてイベントリスナーとして追加します。

イベントターゲット.addEventListener(イベントタイプ,リスナー関数)
addEventListenerの引数は正確には次のとおりですが簡単なイベント処理を行うには第2引数まで指定して後は省略する場合があります。その他の引数の意味については別途特集で解説します。
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false)

イベントについてはイベントの概念資料をこちらのPDFで参照ください。

ENTER_FRAMEについて

ENTER_FRAMEは繰り返し発生するイベントです。フレームレートに合わせて繰り返し発生するフレーム再生イベントは、アニメーションで利用する繰り返しイベントとして最適なイベントです。デフォルトのフレームレートは毎秒12フレームなので、デフォルトのENTER_FRAMEの頻度は毎秒12回になります。

リスナー関数

function onmove ():void {
        sphere.x += 10 * houkou;
        sphere.rotationY += 10 ;
        if (sphere.x < 0 || sphere.x > stage.stageWidth) {
        houkou *= -1;
}

sphere.x += 10 * houkou;はもう少し親切に書くとsphere.x = sphere.x + 10 * houkou;となります。物理運動の等速運動を行う動きはsphere.x += 10の部分で表されます。ENTER_FRAMEが発生するごとに10ピクセルだけ右に動くという意味です。
ちなみに、sphere.y += 10ではy軸に対して下に10ピクセル動くという意味になります。

sphere.rotationY += 10 ;はy軸を基準に時計回りに回転をさせています。地球の自転と逆の動きですね。

* houkouは方向を決めます。
if (sphere.x < 0 || sphere.x > stage.stageWidth)
if文でx軸が0またはステージの右側を出てしまったらという条件を表しています。 そしてその条件にあてはまったらhoukou *= -1にするというステートメントになっています。
マイナス1を積算することで動きを逆にするわけです。

ところで、このソースで動かしてみるとなんだか小さな範囲で動いています。if文の条件と違うと思いませんか。
実はこれはカメラの設定に原因があります。 trace(camera);を最後に入れてカメラの設定をトレースしてみるとx:0 y:0 z:-1000 という結果がでてきます。つまり明示的にカメラの設定を書かなければデフォルトのカメラの設定が使用されています。で、カメラの位置がx:0 y:0 z:-1000となっている訳です。
カメラの位置を明示的に示したい場合はstartRendering();の前にcamera.z = -500;などのように指定します。

camera.z = -500;
startRendering();

円周運動させるにはsin、cosを使います。参考ソースです。

package 
{
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.view.*;
    import org.papervision3d.materials.*;
    import flash.events.Event

    public class Main5 extends BasicView
    {

        public function Main5():void 
        {

            var angle:Number = 0;
            var radius:Number = 600;
            var angleChange:Number = 5;
            var centerX:Number = stage.stageWidth/2;
            var centerY:Number = stage.stageHeight/2;

            var sphere:Sphere = new Sphere(null,60,10,10);
            scene.addChild(sphere);
            addEventListener(Event.ENTER_FRAME, onmove);
            function onmove ():void {
                var radian:Number = deg2rad(angle);
                sphere.x = centerX + radius * Math.cos(radian);
                sphere.y = centerY + radius / 3 * Math.sin(radian);
                sphere.rotationY = 10;
                angle += angleChange;
                angle %= 360;
            }

            function deg2rad(deg:Number):Number {
                return deg * (Math.PI/180)
            }
            startRendering();
        }

    }

}

<author Tahara>

もしよろしければ、下ボタンをクリックお願いします。

このアーカイブについて

このページには、2011年10月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2011年9月です。

次のアーカイブは2011年11月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

カテゴリ

ウェブページ