Flashで3Dの表現:3Dメニューみたいな

3d.jpg

といっても、Flashは3Dソフトではないので、擬似的に3Dに見える表現をする事になります。

そのあたりの説明はKeith Petersさんの「Making Things Move」に大変分かりやすく書かれていますし、今回の核となるスクリプトも、書籍に書かれています。

・手前のものほど大きく、奥のものは小さく見える。
・奥のものほど消失点に近づく。
というのを基本ルールとし、今回は、奥のものほど暗くなる(照明が当たらなくなる)感じを表現してみました。(要 Flash Player8 以上)

3d.swf

というのが今回制作したサンプルです。ソースは以下のようになります。



import flash.geom.ColorTransform;

//Vanishing Point(消失点)
var vpX = Stage.width/2;
var vpY = Stage.height/2;
//矩形の数
var rectNum:Number = 20;
//中心軸と配置するムービークリップとの距離
var radius:Number = 150;
//Focal Length(焦点距離)
var fl:Number = 250;

init();
function init():Void {
    for (var i:Number = 0; i<rectNum; i++) {
        var rect:MovieClip = attachMovie("rect""rect"+i, i);
        var angleInitY:Number = (360/rectNum)*i;
        //ラジアンに変換
        angleInitY = angleInitY*Math.PI/180;
        var cosInitY:Number = Math.cos(angleInitY);
        var sinInitY:Number = Math.sin(angleInitY);
        var initX1:Number = radius*cosInitY-0*sinInitY;
        var initZ1:Number = 0*cosInitY+radius*sinInitY;
        rect.x = initX1;
        rect.y = 0;
        rect.z = initZ1;
        rect.numTF.text=i
        //pall.swapDepths(0)//中心棒を通す
    }
}
function onEnterFrame():Void {
    if(_root._xmouse>=0&&_root._xmouse<=Stage.width){//ブラウザの別ウィンドウが開かれた時の対策
        for (var i:Number = 0; i<rectNum; i++) {
            var rect:MovieClip = this["rect"+i];
            var angleY:Number = (_xmouse-vpX)*0.001;
            var cosY:Number = Math.cos(angleY);
            var sinY:Number = Math.sin(angleY);
            var angleX:Number = (_ymouse-vpY)*0.001;
            var cosX:Number = Math.cos(angleX);
            var sinX:Number = Math.sin(angleX);
            
            var x1:Number = rect.x*cosY-rect.z*sinY;
            var z1:Number = rect.z*cosY+rect.x*sinY;
            var y1:Number = rect.y*cosX-z1*sinX;
            var z2:Number = z1*cosX+rect.y*sinX;
            
            rect.x = x1;
            rect.y = y1;
            rect.z = z2;
            var scale = fl/(fl+rect.z);
            rect._xscale = rect._yscale=scale*100;
            rect._x = vpX+(rect.x*scale);
            rect._y = vpY+(rect.y*scale);
            //zの値をもとに、重なり順を調整
            rect.swapDepths(-rect.z);
            //奥のムービークリップの明度を下げる
            var val = Math.min(-5*Math.sqrt(z2),0);
            rect.transform.colorTransform = new ColorTransform(1, 1, 1, 1, val, val, val, 0);
        }
    }
}

このソースを第一フレームにコピペし、ライブラリに、中心を基準にしたムービークリップ「rect(リンケージ名もrect)」を用意すれば動くとおもいます。サンプルのように数字を表示させたいときはrectの中にダイナミックテキスト「numTF」を置いてください。

スクリプトの先頭から見ていきます。

まず、今回は奥のMCほど暗くなるという表現に使うために、ColorTransformクラスをインポートしておきます。

次に初期値の設定をします。値の内容はコメントを参考にしてください。

続いて、イニシャライズ、及びそれ用の関数の定義をしています。今回はy軸を中心軸として、軸からの距離radiusにシンボルrectをrectNumの数だけ等間隔に配置するように設定しています。(実際に配置しているのは後ろのonEnterFrameで処理していて、ここでは初期座標となるx,y,zの値を設定しているだけです。)

どうやって座標を得ているかというと、以前のエントリ「〜度回転させた後の_xと_yを求める方法」を使って、座標{x:radius, y:0, z:0}にあるものを中心軸を回転の軸として(30*i)度回転させたときの座標を得るようにしています。

その後、onEnterFrameの中で、ステージの中心とマウス座標の距離からy軸を中心にangleY、x軸を中心にangleX回転させる処理をしています。回転後の座標は先程と同様の手法で、今回は2軸回転させるので、一度y軸回転させ、さらにx軸回転させたときの座標を得るという感じの2段処理をしています。

var scale = fl/(fl+rect.z);
rect._xscale = rect._yscale=scale*100;
rect._x = vpX+(rect.x*scale);
rect._y = vpY+(rect.y*scale);

この時点で奥行きz(奥に行くほどzが大きくなる座標体系を使っています)が手に入りましたので、ステージ、焦点距離、zとの関係(Making Things Move p328)を使ってscaleを割り出し、ムービークリップの大きさ、座標を決定しています。

rect.swapDepths(-rect.z);

swapDepthsで手前のMCほど上に配置するようにしています。

var val = Math.min(-5*Math.sqrt(z2),0);
rect.transform.colorTransform = new ColorTransform(1, 1, 1, 1, val, val, val, 0);

最後に、焦点距離flより向こうにあるMCの明度を落とすようにしています。z2のままだと、再奥部で急激に暗くなる感じだったので、Math.sqrt()でバイアスをかけ、(しつこいようですが、zは奥がプラスになるので、明度を下げる→マイナスの値が欲しいので)-5を掛けています。このままだと手前のMCはプラスの値になり、明るくなってしまうので、値がプラスのときはMath.min()で0になるようにしています。

そして、Flash8の新機能であるColorTransformでrgbそれぞれを下げて、暗くしています。
(追記:上のスクリプトは多分彩度が下がる。明度は前の3つのパラメーター下げた方がいいかもです。)

これをベースに、1軸を固定して、1方向だけに回転するムービー(angleX=0にする等)とか、自動で回転し続ける(angleY=0.02にする等)、その際、やや見下ろす感じにする(initの中のrect.y=20にする等)とか、いろいろ調節するだけで、いろんな動きができるので、しばらく退屈しないとおもいます。

僕は3D表現なんてさっぱり分かりませんでしたが、「Making Things Move」を読んで「エウレカッ!」だったので激しくお勧めしておきます。

Foundation Actionscript Animation: Making Things Move (Foundation)

このエントリーをはてなブックマークに追加
はてなブックマーク - Flashで3Dの表現:3Dメニューみたいな

Comments:13

starter 06-09-21 (木) 23:48

ダイナミックテキストの文字も拡大縮小されると思いますが、なぜ綺麗に拡大縮小されるのですか?
私がやろうとしても、文字がぶれたりしてしまいます・・・

tera 06-09-22 (金) 0:45

>>starterさん
はじめましてこんばんは。
ご質問頂いた件ですが、ダイナミックテキストに対して、フォントの埋め込みはされているでしょうか?
ダイナミックテキストボックスを選択した状態で、プロパティパネルの右端の「埋め込み…」ボタンをクリックして、(サンプルの場合は)数字のアウトラインデータを選択し、埋め込んでます。その分swfファイルの総データ量は大きくなりますが、数字やアルファベットぐらいなら大丈夫かなと思います。日本語を埋め込むと激重になります。
フォントが「_ゴシック」とかだと埋め込み自体ができませんので何か他のフォントにして下さい。

心当たりといえばこれくらいなのですが、いかがでしょうか?それとも別の原因でしょうか?

starter 06-09-22 (金) 8:14

ありがとうございます。
おっしゃる通りでした♪お恥ずかしいです。
1軸回転で使わせて頂いております。

あと、BlurFilterも使わせて頂いておりますが、
flash.filters.BlurFilterとしないと私の環境では動きませんでした。これはバージョンの違いなどですかね?

今後も勉強させて頂きますのでよろしくお願いします。記事の更新楽しみにしております。

tera 06-09-22 (金) 8:23

おはようございます。
解決してよかったです。
BlurFilterは僕が書き忘れていました。starterさんがおっしゃられるように、どの環境でもflash.filters.BlurFilterしないといけないです。
記事の方を修正しておきます。
ありがとうございました。

araview 06-12-08 (金) 12:44

実際に3Dをブラウザ上で再生し、そのウィンドウを開いたまま他のウィンドウやデスクトップで作業を始めると
動きが暴走し始めるのはブラウザやコンピュータによるのでしょうか。多分SWFがマウスの位置を読めなくなるのが
原因ではないかと思ったのですが。。。

tera 06-12-08 (金) 13:34

>>araview様
コメントありがとうございます。
当方のMac/FireFox1.5でも確認いたしました。
この記事では、とにかくグイングインまわる仕組みだけを掲載していましたので、細かい条件設定等はしてませんでした。
エントリ中のコードとswfを修正し、対応しました。
onEnterFrame関数の2行目に、_xmouseの条件分岐を入れ、エリア外なら回転が止まるようにしました。
上記対応方法以外にも、変数をかませて、「エリア外の時はこの回転数で」という指定も可能ですし、ご自由に条件づけてくださいです。
よろしくお願いします。

shin 07-07-15 (日) 4:06

はじめまして。
私はaction scriptを勉強し始めて1ヶ月の初心者です。
このソースで、メニューを作りたいのですが、数字ではなく
テキストを表示させるにはどうしたらよろしいのでしょうか?
自分なりに調べてみたのですが、どうしてもわからずじまいで・・・
もし、お時間が許せばレスをお願い致します。

tera 07-07-15 (日) 10:39

init 関数の行末の rect.number.text=i; の i の所を “いろは” にしてみて下さい。その際、ネットで公開した時用に、ムービークリップ rect の中のダイナミックテキストに日本語を埋め込むか、フォントの指定を _ゴシック にするなどしておいてください。
これで、数字の部分が全て”いろは”になります。
文字をひとつひとつ帰る場合は予め外側(コード2行目にでも)ムービークリップの個数分の配列に各テキストを格納しておき、
menuArray = ["トップ", "about", "works", "recruit"]; とか
で、上記initの中を
rect.number.text=menuArray[i];
でいけるのではないでしょうか。(未検証ですが)

shin 07-07-17 (火) 0:24

お忙しい中、レスをありがとうございした。

さっそく検証してみます。

shima 07-07-31 (火) 16:19

 初めまして。今回初めて書き込みさせていただきます。アクションスクリプトを始めて間もないのですが、自分なりに頑張っております。このソース(回転する数字)で、画像などを個々に変更したい場合はどの様な仕組みになるのでしょうか?試行錯誤しているのですが、なかなか進まず・・・お時間の許す限りで結構ですので、教えて頂ければ嬉しいです。

tera 07-07-31 (火) 16:35

>shima様
はじめまして。コメントありがとうございます。
ご回答としましては、
http://www.trick7.com/blog/2006/07/10-124628.php
の記事のコメント部分に書いております内容以上のことは現状ご用意できませんです。
まずはそちらの方をご覧くださいませ〜。

有り難う御座います 07-08-01 (水) 12:00

素早いご返事感謝致します。無理を言って申し訳ありません。そちらを参考にして検証してみたいと思います。

nayu 08-06-06 (金) 13:36

エウレカッってどういう意味でしょうか?
Yahooで検索するとエウレカセンブンとでてきたのですが
関係あるのでしょうか

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://www.trick7.com/blog/2006/07/05-160520.php/trackback
Listed below are links to weblogs that reference
Flashで3Dの表現:3Dメニューみたいな from trick7

Return to page top