2008.07 Monthly archives

[Away3D] collision study

2008.07.30

Floor Collision Demo(要:FlashPlayer9)※マウスクリックでSphereが増えます。

衝突判定のお勉強。とにかく頭に来るほど基礎が無いので、先人の技から学んでいくぞと。

ベースにしたのは zero point nine のデモコード。エッセンスのみ抽出させていただいて、キー入力によるコントロールとかはひとまず無しにしてみた。あとオリジナルには無い要素として、perlinNoiseのoffsetを使った連続的な変形エフェクトを追加した。変な弄り方したのが悪いのか、ときどき床をすり抜けてSphereがこぼれ落ちる;

オブジェクト中心座標のX,Z成分から、Planeの該当Faceを割り出した後、Faceを構成する2つのポリゴンのうち、どっちにオブジェクト中心座標のX,Z成分が含まれるかを求め、オブジェクト中心座標から-Y方向に伸びるレイと、△ポリの交点を求めて、最終的なY座標を得る。ってな方法だと思うので、地面がPlane以外だとこの方法は使えなさそう。

zero point nine のコードと、「マルペケつくろーどっとこむ」さんの記事を比較しながらアルゴリズムを紐解こうとしたんだけど、オブジェクト中心座標から-Y方向に伸びるレイと、△ポリの交点を求める部分がどーもよくわかんね。このへん色んな方法があるんだろうけど、zero point nine のそれはなんだか面倒なことをやってそうな印象。うーむ。

とりあえずは、これを突破口に内積と外積の海に飛び込んでみよう。

オレのような凡人が3Dプログラミングの勉強する場合、ある程度期待した通りの動きをするコードがとりあえず無いことには、正直とっかかりが掴めない。そういった意味で『ニワトリが先か卵が先か』みたいな状況にしょっちゅう陥るわけで、ヒントになるコードを公開してくれてる方々には感謝しきれねーッス。本当にありがたいことでございます。

[Away3D] RA DIOHEA_D / HOU SE OF_C ARDS

2008.07.17

レディオヘッドのアルバムIn Rainbows収録曲”House of Cards” のPVで使われた3DキャプチャデータのcsvファイルがGoogle Codeで公開された。データと一緒にProce55ingのソースも公開されてて太っ腹。

RA DIOHEA_D / HOU SE OF_C ARDS – Google Code

ってのを、PV3Dのオフィシャルブログで見かけて、しかもなんか件のページのFlashビューアが、PV3Dを多少モディファイで作られたらしいので、Away3Dでも出来ないもんかなと思った次第。もうすでにこれ使ったデモで溢れ返ってそうな気がするけど、やるだけやってみた。

House of Cards 3D Plot(要:FlashPlayer9)

12000頂点、とりあえずプロットまではできた。激重だけどなんとか動いてる。
元ネタのFlashビューアは、ブラーフィルターがかかってる上にそこそこ軽いのが不思議でしょーがねぇ。頂点間引いてるのかなぁ?描画に関してはビットマップ化がキモなんじゃねーかとにらんでガリガリやってみたけど、どーも上手くいかね。あとはCSV→プロットまでのパイプラインを最適化しないと、ギリギリな感じの今の状態じゃアニメーションなんかとても無理だ。

むむむー、悔しいからもう少し粘ってみよう。
せめてブラーフィルタかけてもそこそこ動いてる状態にはもっていきたい。

データをスクリーン上に再構成するのも面白いんだけど、このデータ自体を作るほうにも興味津々。

人物のキャプチャには、
http://www.geometricinformatics.com/geoVideo.php
町並みのキャプチャには
http://www.velodyne.com/lidar/

の技術をそれぞれ使ったっつーことなんだけど、サッパリわからん。とりあえず金はかかりそうだ(笑)
特に後者のほうは、軍事転用前提のロボットカーレースで使われてるような技術とか入ってそうで高そうな印象。なんだろ「ものすごいレーザー測量器」って感じなのかな。
トイレくらいの広さしかスキャンできないオモチャっぽいものでもいいから個人で買えるものがあったらいいのに。タカラトミーが作ってくれることに期待。

それにしたってデータ大公開ってRadioHeadスゲー。アルバムの売り方といい、こういうプロモーションって日本でもやればいいのにな。せっかくニコニコとかあるんだし。

08/07/23 追記:
12000頂点をAway3Dのジオメトリパイプラインで処理するってのは、どー考えても自前で透視変換した座標をビットマップ描画する方法には速度的に及ばないってのをNUTSUさんや、MASDAさんのデモ見て痛感した。特にMASDAさんのはサウンドスペクトルになってて超カコイイ!

んで、自前レンダリングの軽さとAway3Dの汎用性の良いトコ取りを目指して、カメラと空間のみを拝借(ビュー行列で座標変換。プロジェクション変換してないので微妙にインチキ)しつつ、描画は自前で行う方法を模索してみた。

bitmapTest.swf(要:FlashPlayer9)

結局重いんだけど、エフェクト追加したわりには軽くなったかも。

いずれにせよ、ビットマップにしちゃえばテクスチャとして使えるぜーってことで、闇雲に貼ってみたのが下のデモ。オレはいったい何がしたいのか。

textureDemo.swf(要:FlashPlayer9)

Join Away3D Contributors

2008.07.15

Away3D開発チームの一人、katopz(http://www.sleepydesign.com)の紹介で、Away3Dのコントリビュータリストに名を連ねる事になった。英語でメールのやり取りなんかしたこと無かったんで、超ビビリまくりだったけどそれなりに通じるもんですな(笑)

コアな開発に関わるわけじゃないので、今まで通り自分が実際使ってみた中で得たものを、備忘録的にまとめるスタイルで貢献できればなぁと。場合によってはなるべくがんばって英文も書くようにしよう。
基本的にマッタリ貢献の方向で。

Thanks katopz and Rob, for letting me be a member of away3d contributors.
Away3D rocks!

Froce55ingをFlexSDK3で

2008.07.11

たまには3D以外のこともやってみるべーということで、NUTSUさん作の、Processing気分を味わうAS3.0ライブリラリ「Frocessing」で遊んでみた。

nutsu/Frocessing – Spark project

svnリポジトリに上がってるサンプルが .flaファイルしか無いので、FlexSDKで扱う方法を模索。とりあえず F5MovieClip2DとかF5MovieClip3Dを継承しとけばいいみたいだということにオレの中で結論づいたので、なんぞ作ってみる。

で、これまたP5ライクな「NodeBox」のサンプルを移植して若干イジったのが下記。
Hello Froce55ing(要:FlashPlayer9)

package
{
    import flash.display.*;
    import frocessing.display.F5MovieClip2D;
 
    public class main extends F5MovieClip2D
    {
        private var count:int;
 
        public function main()
        {
            stage.frameRate = 30;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
 
            super();
            QBest();
        }
 
        public function draw():void
        {
            clear();
            background(255,255,255);
 
            count++;
            translate(fg.width/2, fg.height/2);
            fill(0, 153, 230, 0.1);
            stroke(0, 153, 230, 0.4);
            strokeWeight(0);
 
            for (var i:int = 0; i < 150; i++)
            {
                var x:Number = random(fg.width/2, -fg.width/2) * cos(radians(count));
                var y:Number = random(fg.height/2, -fg.height/2) * cos(radians(count));
                var r:Number = cos(radians(count)) * 50;
                circle(x,y,r);
            }
        }
 
    }
}

ステージプロパティ設定してるあたりがかなりビミョーだけど、こんな感じでいいのかなぁ?FlashIDEのドキュメントクラス設定と同等のことってFlexSDKで出来るのかしら。このあたり激しく勉強不足でワカンネー。けど動いたからまぁいいや(えー)

もっとP5っぽいものを、と思ってストレンジアトラクタ系ネタも作ってみたものの、lineで描画しまくったら予想通りのブラクラになっちゃったんで静止画のみで。

setBmpMode()を使えばBitmapが描画対象になる…のか?軽くする方法が解かるまでひとまず保留っと。

FlexSDK3 + Rascut + mi という修行僧のような環境でもそこそこ楽しめた。
でもまぁ素直にFlashIDEつかってフレームスクリプト書いたほうがシンプルに書けて、よりP5気分に浸れるのかも。ただこれ、慣れちゃうとAS3.0本来のシンタックス忘れるわ、間違いなく確実にオレは(笑)

[PV3D2.0] material.precise

2008.07.09

久々のPV3Dネタ。
アクセスログ見てたら、FxUGのフォーラムでオレのエントリが引き合いに出されてたんで、これについて補足してみる。

とりあえず、

var bitmapMaterial:BitmapMaterial = new BitmapFileMaterial("sample.jpg");

は、マズいんじゃないかと。

それはおいといて、上記のトピックは「 MovieMaterial を使えば、precise が有効にできる。」という解釈で終了してる感じだけど、そもそも precise プロパティで制御するパースペクティブコレクトの機能は、BitmapMaterial クラスで提供されてるものなので BitmapMaterial を継承する全マテリアルで指定が可能なハズ。MovieMaterial も、そのひとつっていうだけのハナシ。
というわけで、基本である BitmapMaterial で precise プロパティを使ってみたデモが下記。

material.preciseのテスト(要:FlashPlayer9)
※キューブをクリックすると、preciseプロパティの true / false 切り替え。

そのソース。

package
{
    import flash.display.*;
    import flash.events.*;
 
    import org.papervision3d.view.BasicView;
    import org.papervision3d.events.InteractiveScene3DEvent;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
 
    [SWF(backgroundColor=0x000000)]
 
    public class bm_precise extends BasicView
    {
        private var rootNode: DisplayObject3D;
        private var valx    : Number = 0;
 
        [Embed(source='texture.jpg')] public var texBitmap:Class;
 
        public function bm_precise()
        {
            stage.frameRate = 30;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.quality = StageQuality.MEDIUM;
 
            //viewportの定義とカメラタイプ定義
            super (0,0,true,true,"Target");
            init3D();
        }
 
        public function init3D():void
        {
            rootNode = new DisplayObject3D();
            scene.addChild(rootNode);
 
            //カメラ設定
            camera.z = -1200;
            camera.y = 500;
            camera.fov = 30;
 
            //マテリアル設定
            var material:BitmapMaterial = new BitmapMaterial( new texBitmap().bitmapData, true );
            material.interactive = true;
            var materials:MaterialsList = new MaterialsList(
            {
                all : material
            });
 
            //オブジェクト生成
            var objCube:Cube = new Cube( materials, 250, 250, 250, 1, 1, 1);
            rootNode.addChild(objCube);
            objCube.material.tiled = true;
            objCube.material.maxU = 2;
            objCube.material.maxV = 2;
 
            objCube.addEventListener(InteractiveScene3DEvent.OBJECT_RELEASE, mouseRelease);
 
            //レンダリング開始
            startRendering();
        }
 
        override protected function onRenderTick(event:Event=null):void
        {
            valx += (stage.mouseX - (stage.stageWidth &gt;&gt; 1 ) ) / 50;
            rootNode.rotationY = valx;
 
            super.onRenderTick(event);
        }
 
        private function mouseRelease(event:InteractiveScene3DEvent):void
        {
            var targetMat:BitmapMaterial = event.displayObject3D.materials.materialsByName['all'];
            targetMat.precise = !targetMat.precise;
        }
    }
}

SWFにBitmapを埋め込んじゃうのが一番ラク。
件のトピックで質問者の方が公開してるソースで使ってる BitmapFileMaterial のように、外部ファイルを使ってマテリアルを生成する場合は、ファイルの読み込み完了を待たずに描画を始めるとエラーになる。これは、BitmapMaterial の drawTriangle メソッド内で precise プロパティが false の場合は bitmap の存在をチェックしているのに、trueの場合、bitmap が nullでも描画しようとしてるため。バグか仕様かはともかくとして、要はファイルの読み込み完了を待たないとダメと。

で、どうするかの例が下記のソース。

package
{
    import flash.display.*;
    import flash.events.*;
 
    import org.papervision3d.view.BasicView;
    import org.papervision3d.events.InteractiveScene3DEvent;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.materials.BitmapFileMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
 
    [SWF(backgroundColor=0x000000)]
 
    public class bmf_precise extends BasicView
    {
        private var rootNode:DisplayObject3D;
        private var material:BitmapFileMaterial;
        private var valx    : Number = 0;
 
        public function bmf_precise()
        {
            stage.frameRate = 30;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.quality = StageQuality.MEDIUM;
 
            //viewportの定義とカメラタイプ定義
            super (0,0,true,true,"Target");
            loadMaterial();
        }
 
        public function loadMaterial():void
        {
            //ファイル読み込み後のコールバック指定
            BitmapFileMaterial.callback = init3D;
            material = new BitmapFileMaterial( 'texture.jpg', true );
            material.interactive = true;
        }
 
        public function init3D():void
        {
            rootNode = new DisplayObject3D();
            scene.addChild(rootNode);
 
            //カメラ設定
            camera.z = -1200;
            camera.y = 500;
            camera.fov = 30;
 
            //マテリアル設定
            var materials:MaterialsList = new MaterialsList(
            {
                all : material
            });
 
            //オブジェクト生成
            var objCube:Cube = new Cube( materials, 250, 250, 250, 1, 1, 1);
            rootNode.addChild(objCube);
            objCube.material.tiled = true;
            objCube.material.maxU = 2;
            objCube.material.maxV = 2;
 
            objCube.addEventListener(InteractiveScene3DEvent.OBJECT_RELEASE, mouseRelease);
 
            //レンダリング開始
            startRendering();
        }
 
        override protected function onRenderTick(event:Event=null):void
        {
            valx += (stage.mouseX - (stage.stageWidth >> 1 ) ) / 50;
            rootNode.rotationY = valx;
 
            super.onRenderTick(event);
        }
 
        private function mouseRelease(event:InteractiveScene3DEvent):void
        {
            var targetMat:BitmapFileMaterial = event.displayObject3D.materials.materialsByName['all'];
            targetMat.precise = !targetMat.precise;
        }
    }
}
BitmapFileMaterial.callback = init3D;

って感じで、ファイル読み込み後のコールバックが指定できるので、これを使った。PV3Dの仕様に合わせるならこんな感じだけど、実際にはBitmapFileMaterialを使わずに自前で外部ファイル読み込んで、BitmapMaterial使ったほうが自由度高いと思う。MovieMaterialを使う場合でも、外部のSWFを読み込んで使うなら当然同じ事に注意。

あと、オレのようにFlexSDKオンリーで外部ファイルを使うコードは、コンパイル時

mxmlc -use-network=false hoge.as

にしないと、スタンドアローンプレーヤーでローカル再生できない。FlashIDEとかFlexBuilderだったら、この辺は大丈夫なのかな。(Rascutはこういうことから開放されるので、すこぶる便利。)

と、ここまで書いてアレだけど、上記ソースのカメラ設定部分を下記のように書き換えると、案外歪みが目立たなくなる。

//カメラ設定
camera.z = -3500;
camera.y = 1500;
camera.focus = 320;
camera.zoom = 10;

テクスチャの歪みはパースがきつくなると発生するので、視野角が極端に広くならないようにfocusとzoomを調整してやれば、それで済んじゃう場合もある。奥行き感が無くなるのとトレードオフだけど、今回のように「ステージ中心にオブジェクトひとつ」みたいな場合はこれで充分かも。precise 使う場合でも、カメラとの距離に応じて true / false できるようにしておくとか、負荷軽減の工夫は必要かと。