2007.04 Monthly archives

Papervision3Dメモ #16

2007.04.25

Hemisphere(半球)クラスを使う

ついこの間Torus.asが公開されたばっかりなのに、PV3D Wikiに半球を生成するクラスHemisphere.asが掲載されてた。なんだか気合い入ってんなー。Sphere.asと同じパラメータ指定で半球が生成されるってだけなので、扱いはとても簡単だった。

obj_Hemisphere.swf(要:Flashplayer9)

3D空間内で空とかを表現することを想定してると思う(地味に便利)んだけど、そのせいかデフォルトだとポリゴンの法線が半球の内側を向いているので、状況によっては

hemisphereObj.material.doubleSided = true;

みたいな感じで、リャンメンポリゴンにするか、

hemisphereObj.material.opposite = true;

で、法線を逆向きに指定してやる必要があると。

Papervision3Dメモ #15

2007.04.19

Torus(ドーナツ形状)クラスを使う

PV3D Wikiにドーナツ形状を生成するクラスTorus.asが掲載されていたので使ってみる。

クラスを使えるようにするには、SorcePathを通したフォルダ内に「com」-「suite75」-「papervision3d」-「objects」という階層でフォルダを新規に作成し、そこにTorus.asを設置すればいいんだけど、面倒なので、Torus.asの

package com.suite75.papervision3d.objects

というパッケージ宣言を

package org.papervision3d.objects

に書き換えて、他の純正クラスと同じ場所に置いた。

var torus:Torus = new Torus( マテリアル, 外側半径, 内側半径, 旋回の分割数, 旋回する平面の頂点数 );

ってな感じでドーナツ型のオブジェクトが生成できると。

obj_Torus.swf(要:Flashplayer9)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package
{
    import flash.display.*;
    import flash.events.*;
 
    import org.papervision3d.scenes.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.cameras.*;
    import org.papervision3d.materials.*;
 
    [SWF(backgroundColor=0x000000)]
 
    public class obj_Torus extends Sprite
    {
        // _______________________________________________________________________
        //                                                                  vars3D
        private var container : Sprite;
        private var scene     : Scene3D;
        private var camera    : Camera3D;
        private var rootNode  : DisplayObject3D;
 
        private var torusObj  : Torus;
        private var largeRadius : int = 150;    //外周半径
        private var smallRadius : int = 50;     //内周半径
        private var segmentW  : int = 12;       //旋回の分割数
        private var segmentH  : int = 6;        //断面の頂点数
 
        private var valx      : Number = 0;
        private var valy      : Number = 0;
 
        // _______________________________________________________________________
        //                                                             Constructor
        public function obj_Torus():void
        {
            stage.frameRate = 60;
            stage.quality   = "MEDIUM";
            stage.scaleMode = "noScale";
            stage.align = StageAlign.TOP_LEFT;
            this.addEventListener(Event.ENTER_FRAME, loop3D);
            this.stage.addEventListener(Event.RESIZE, onStageResize);
 
            init3D();
        }
 
        // _______________________________________________________________________
        //                                                                  Init3D
        private function init3D():void
        {
            //コンテナ生成
            this.container = new Sprite();
            addChild(this.container);
            this.container.x = this.stage.stageWidth  / 2;
            this.container.y = this.stage.stageHeight / 2;
 
            //シーン生成
            scene = new Scene3D( container );
 
            //カメラ設定
            camera = new Camera3D();
            camera.z = largeRadius*2;
            camera.focus = 500;
            camera.zoom = 1;
 
            //rootNode生成
            rootNode = scene.addChild( new DisplayObject3D( "rootNode" ) );
 
            //マテリアル設定
            var colorMaterial:ColorMaterial = new ColorMaterial( 0x0099cc, 1);
            var wireMaterial:WireframeMaterial = new WireframeMaterial( 0x00ccff );
            var compoMaterial:CompositeMaterial = new CompositeMaterial();
            compoMaterial.addMaterial(colorMaterial);
            compoMaterial.addMaterial(wireMaterial);
 
            //Torusオブジェクト生成
            torusObj = new Torus( compoMaterial, largeRadius, smallRadius, segmentW, segmentH)
            rootNode.addChild( torusObj );
        }
 
        // _______________________________________________________________________
        //                                                                    Loop
        private function loop3D( event:Event ):void
        {
            //マウス座標でオブジェクトを回転
            valx += this.container.mouseX / 50;
            valy += this.container.mouseY / 50;
            torusObj.rotationY = valx;
            torusObj.rotationX = valy;
 
            //レンダリング
            this.scene.renderCamera( camera );
        }
 
        // _______________________________________________________________________
        //                                                           onStageResize
        private function onStageResize(event:Event):void
        {
            this.container.x = this.stage.stageWidth  / 2;
            this.container.y = this.stage.stageHeight / 2;
        }
    }
}

これを参考にすれば3Dアプリでワイングラスとかを作るのに使う、いわゆる「旋回」による形状生成を可能にするクラスが作れそう。時間があるとき作ってみよう。

Papervision3Dメモ #14

2007.04.19

法線マップ(NormalMap)に挑んでみる

FACEsの法線マッピングに関するエントリを見て唸らされたので、PV3Dでも出来ないもんかなと思ってトライしてみた。いつでも無謀。

まずは、法線マップそのものを用意しなくちゃならないのでBlenderで作ろうと調べてみたら、こんなチュートリアルを発見。けど、モデリングするの面倒だし、Blender内蔵の猿のオブジェクト使うなら結局同じものができ上がるので、チュートリアル記事の完成画像を拝借した。Windows環境ならNvidia’s normal map toolsっていうPhotoshopプラグインがある(PaintShop Proでもイケる模様)ので、モデリングしなくても法線マップが作れる。ガックリなことにOSX版は無いので、GIMPのNormalMapプラグインを使うのがいいのかなぁ、試してないけど。< br>

用意した法線マップを前述のエントリにあるColorMatrixFilterで変換(PV3Dには光源が無いので、カメラのベクトルを光源替わりに使った)して、テクスチャ用のビットマップに乗算(MULTIPLY)し、さらにOVERLAYで重ねてBitmapMaterialに割り当ててあるビットマップオブジェクトに毎フレームdraw()したのがこれ。

normalmap.swf(要:Flashplayer9)

なんか違和感があるな、膨らんでんのか凹んでんのかどっち付かずな感じ。適用したColorMatrixFilterは、光源に垂直な面が真っ黒になるということだったんで、適当にイジくり回したんだけどそれが原因だろうな。光源に垂直なほど(露出オーバーしない程度に)明るくなるにはどうすりゃいいのかなぁ。道は険しいのぉ。

Papervision3Dメモ #13

2007.04.18

ベクトルと行列の勉強の為に、PV3Dにおいてベクトルを扱うクラス「Number3D」と行列を扱うクラス「Matrix3D」を使って球体(Sphere)の頂点をperlinNoiseで歪ませてみたら、全然全くこれっぽっちも狙い通りの結果にはならなかったんだけど(ダメじゃん)なんだか面白い形が生成されるので失敗作だけど晒してみる。

Terrain_sphere.swf(要:Flashplayer9)
※ヘンなオブジェをクリックすると、再計算してヘンなオブジェを再生成。

ちょっとデコボコした地球儀みたいになるはずだったんだけどなぁ(笑)
Number3DとMatrix3Dについては、Codin’In The Free Worldさんの、このエントリこのエントリが大変参考になりました。ゴチになりました。

Papervision3Dメモ #12

2007.04.14

いわゆるIK(インバースキネマティクス)ってどのくらい難易度高いのかなぁと思って、無謀は承知でトライしてみた。インバースキネマティクスのアルゴリズムに関しては、これっぽっちも解ってないので、とりあえずLightWave触ってた時の手順と印象で探りを入れてみる。

形状のペアレント
LightWaveでIKするには、目的のオブジェクトをペアレント(親子関係)する必要があるので、ひとまずこれをPV3Dでやってみる…といっても単に階層上にaddChild()すればペアレント終了。例えば、Arm01、Arm02、Arm03という3つの形状で階層を作るなら、

rootNode = scene.addChild( new DisplayObject3D( "rootNode" ) );
rootNode.addChild( Arm01,"Arm01" );
Arm01.addChild( Arm02,"Arm02" );
Arm02.addChild( Arm03,"Arm03" );

ってな感じで、入れ子にaddChild()しておけば親オブジェクトの移動や変形に子オブジェクトが追随するペアレント指定が完了。ここまではムービークリップの概念そのまんまなので、さすがのオレでもすぐに出来た。

IKっぽいことをしてみる
「逆運動学」とかで検索して、それっぽいサイトをいくつか見て回った結果、要は「ゴールオブジェクトの位置で、他のオブジェクトの姿勢が決まる」ってことが満たされればいいんじゃね?いいんでしょ?イイ!という凡人なんてこんなもんですよ的発想を下敷きに、なんとかしてベクトルだの行列だのを駆使しなくてもできる方法が無いもんかと考えた揚げ句に閃いたのが、ゴールオブジェクト以外のオブジェクトを全部lookAt()使ってゴールオブジェクトの方向向ければいいんじゃね?というアホみたいな発想。さっきの例でいうと「Arm03」をゴールオブジェクトにするとして、

Arm02.lookAt(Arm03);
Arm01.lookAt(Arm03);

こんな感じ。

んで、実際にやってみたのがこれ。※要:Flashplayer9
黄色いパーツがゴールオブジェクト。

び、微妙。なんかソレっぽく動いたけど、どうにもインチキくさい。ていうかほぼ間違いなくインチキIKだろこれ。どっちにしてもこれじゃ関節ごとの動きの制限とかどうすればいいか全然わかんないし、やっぱりちゃんと自分でベクトルとか使ってやらないとダメっぽいなぁ。なんとなく、lookAt()メソッドがやってる事にヒントがありそうな気がするので、そのへんから攻めてみよう。