「てっく煮ブログ」さんにて、
3次元空間にプロットしてくれることを期待!
各国の伝統色をHSV空間に配置してみた
という面白そうな課題が提示されてたのでトライしてみた。下手でも、とにかくやってみるのココロ。
nitoyonさんのデモは、HSVのうち「V」を使ってないとのことで、これを使って3次元に拡張するわけだ。直球で拡張したら円柱状の空間になると思うんだけど、それでいいのか調べてみたら
HSVモデルの別の視覚化方法は円錐である。この表現では、色相は色環の三次元円錐状の構造に描かれる。彩度はその円錐の円形交差部分の中央からの距離、明度は円錐の頂点からの距離で表される。
WikiPedia:HSVの視覚化
というWikiPediaの解説を見つけた。これによると円柱で表現してもいいらしい(全然関係ないけど、HSVって「HSB」が正しいんだと思ってた、どっちでもいいんだ。)
せっかくなので円錐に挑戦。HSVの各要素から座標を算出して、手始めにパーティクルでプロット。
j_traditional_color_lt.swf(要:FlashPlayer9)
上手くいったみたいなので、TextFieldを配置したMovieClipからMovieMaterialを生成。それを貼り付けたPlaneをビルボード表示して終わり…とか簡単に済むわけがなく、動作重すぎ。安直すぎ。
色名テキストをHSV色空間にプロット – MovieMaterial版(要:FlashPlayer9)
※かなり重いです御注意下さい。
もうちょっと現実的な速度で動かせないもんかなぁと思って、ダミーのDO3Dを色数分配置して、そのスクリーン座標からTextFieldを持つMovieClipの表示位置を決めるというフェイク感漂う方法でやってみた。
色名テキストを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のパースに、as3corelib、RGBからHSVへの変換にfladdict様謹製のsketchbook(これものすごい便利)を使ってるのでコンパイルする場合は、よしなに対応願います。








