note.x

[Papervision3D2.0] 日本の伝統色をHSV色空間に3Dプロットしてみた

てっく煮ブログ」さんにて、

3次元空間にプロットしてくれることを期待!
各国の伝統色をHSV空間に配置してみた

という面白そうな課題が提示されてたのでトライしてみた。下手でも、とにかくやってみるのココロ。

nitoyonさんのデモは、HSVのうち「V」を使ってないとのことで、これを使って3次元に拡張するわけだ。直球で拡張したら円柱状の空間になると思うんだけど、それでいいのか調べてみたら

HSVモデルの別の視覚化方法は円錐である。この表現では、色相は色環の三次元円錐状の構造に描かれる。彩度はその円錐の円形交差部分の中央からの距離、明度は円錐の頂点からの距離で表される。
WikiPedia:HSVの視覚化

というWikiPediaの解説を見つけた。これによると円柱で表現してもいいらしい(全然関係ないけど、HSVって「HSB」が正しいんだと思ってた、どっちでもいいんだ。)
せっかくなので円錐に挑戦。HSVの各要素から座標を算出して、手始めにパーティクルでプロット。

e_jtc.jpg

j_traditional_color_lt.swf(要:FlashPlayer9)

上手くいったみたいなので、TextFieldを配置したMovieClipからMovieMaterialを生成。それを貼り付けたPlaneをビルボード表示して終わり…とか簡単に済むわけがなく、動作重すぎ。安直すぎ。

色名テキストをHSV色空間にプロット – MovieMaterial版(要:FlashPlayer9)
※かなり重いです御注意下さい。

もうちょっと現実的な速度で動かせないもんかなぁと思って、ダミーのDO3Dを色数分配置して、そのスクリーン座標からTextFieldを持つMovieClipの表示位置を決めるというフェイク感漂う方法でやってみた。

e_jtc2.jpg

色名テキストをHSV色空間にプロット – MovieClip版(要:FlashPlayer9)
※ステージクリックで、BlendModeをon/off

スクリーン座標の算出には、DO3Dのプロジェクション変換そのまんまの式を使った。

//mc = TextFieldを持つMovieClip
//DO3D = ダミーのDisplayObject3D
//centerX,centerY = 原点を画面の中心にするための補正値

var persp:Number = (camera.focus * camera.zoom) / (camera.focus + DO3D.view.n34);
mc.x = DO3D.view.n14 * persp + centerX;
mc.y = DO3D.view.n24 * persp + centerY;

MCが拡大縮小しないのでcacheAsBitmapが効く効く。MovieMaterial使った場合と比べてかなりマトモに動くようになった。パーティクルよりボリューム感があっていいな。調子に乗ってステージクリックでBlendModeをon/offできるようにしてみた。onにするとキレイなんだけど、さすがに重い。

今回みたいなものは、PV3Dに限らずFlash用3Dエンジン使わずに自前で座標変換したほうがよさげ。って、自分でやるとかえって遅くなるから3Dエンジン頼みなわけなんだけども…。精進ですな。

以下、パーティクル版を簡略化したソース

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
102
103
104
105
106
107
108
package
{
    import flash.display.*;
    import flash.events.*;
    import flash.net.*;
 
    import com.adobe.serialization.json.*;
    import sketchbook.colors.*;
 
    import org.papervision3d.view.BasicView;
    import org.papervision3d.objects.*;
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.materials.*;
    import org.papervision3d.core.geom.*;
    import org.papervision3d.core.geom.renderables.*;
    import org.papervision3d.materials.special.ParticleMaterial;
 
    [SWF(backgroundColor=0x000000)]
 
    public class j_traditional_color_sample extends BasicView
    {
        private var colorArray  : Array;
        private var colorChips  : Array = new Array();
        private var pChips      : Particles;
        private var rotateAngle : Number = 0;
 
        public function j_traditional_color_sample()
        {
            stage.frameRate = 30;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.quality = StageQuality.LOW;
 
            super (0,0,true,true,"Target");
            initColor();
        }
 
        private function initColor():void
        {
            var jsonLoader:URLLoader = new URLLoader();
            jsonLoader.addEventListener(Event.COMPLETE, onComplete);
            jsonLoader.load(new URLRequest("asset/japan.json"));
 
            function onComplete(e:Event):void
            {
                var my_str:String = e.target.data;
                colorArray = (JSON.decode( my_str ) as Array);
                init3D();
            }
        }
 
        private function init3D():void
        {
            camera.x = 0;
            camera.y = 600;
            camera.z = 0;
            camera.fov = 30;
 
            pChips = new Particles("pChips");
            scene.addChild(pChips);
            for each(var col:Object in colorArray)
            {
                plotColorChip(col);
            }
 
            var wfmat:WireframeMaterial = new WireframeMaterial(0x333333);
            var objCone:Cone = new Cone( wfmat, 280, 600, 8, 4 );
            scene.addChild(objCone);
            objCone.pitch(180);
 
            startRendering();
        }
 
        override protected function onRenderTick(event:Event=null):void
        {
            rotateAngle += 1;
            if(rotateAngle > 360)
                rotateAngle -= 360;
 
            var radian:Number = rotateAngle * Math.PI/180;
            camera.x += ( ( Math.cos(radian) * 1800 ) - camera.x ) / 10;
            camera.z += ( -( Math.sin(radian) * 1800 ) - camera.z ) / 10;
 
            super.onRenderTick(event);
        }
 
        private function plotColorChip(col:Object):void
        {
            var RADIUS:Number = 280;
            var CONEHEIGHT:Number = 600;
 
            var hsb:Object = ColorUtil.getHSB(col.value);
            var rad:Number = (2 * Math.PI * hsb.h) / 360;
            var r:Number = RADIUS * (hsb.s / 100);
            var h:Number = CONEHEIGHT * (hsb.b / 100);
            var r2:Number = Number(h/CONEHEIGHT) * r;
 
            var pmat:ParticleMaterial = new ParticleMaterial(col.value,1);
            var tx:Number = r2 * Math.cos(rad);
            var tz:Number = r2 * Math.sin(rad);
            var ty:Number = h - CONEHEIGHT/2;
 
            var pt:Particle = new Particle(pmat, 10, tx,ty,tz)
            pChips.addParticle(pt);
        }
 
    }
}

ソースとJSONファイル一式ダウンロード

JSONのパースに、as3corelib、RGBからHSVへの変換にfladdict様謹製のsketchbook(これものすごい便利)を使ってるのでコンパイルする場合は、よしなに対応願います。


TRACKBACK

  1. [...] accédez au flash par ici, et le billet par là sur note.x, avec le code source. Ou comment la 3D sur le web pourrait servir à la visualisation de donnéeS [...]

Trackback URL : http://blog.r3c7.net/as3-software-rendering/170/trackback/

COMMENTS

  1. nitoyon - 2008.03.30 1:16:49

    おぉ。ありがとうございます。すごくきれいですねー!!

  2. rect - 2008.03.30 1:38:34

    >nitoyonさん

    どもー。
    キレイですよねぇ〜。自分もビックリです。
    面白いネタを提供していただいてありがとうございました。
    ホント勉強になりました。

  3. telmat - 2008.03.30 8:13:18

    génial !!!!!

Leave a Reply