2008 年 6 月 のアーカイブ

Papervision3D – CurlingPlane.as

2008.6.29 日曜日

CurlingPlane.as を使ってみた。

以前、Papervision3Dについて色々調べてたら、
note.xさんというところで面白そうなもの見つけたので自分も作ってみた。
参照:Papervision3Dメモ #29


サンプル

と、言ってもこれ作ったの随分前だけど…フォルダの隅に埋もれてたので蔵出し。
AS3の話とかPapervision3Dの話とか一切無しでいきなりこんな物を出してくるこのブログの無節操ぶり。

CurlingPlane.asの公開元はこちら。

var obj:CurlingPlane = new CurlingPlane(picData:BitmapData, curl:int);
// curl = planeの分割数
obj.rotate(0);
scene.addChild( obj );

で、planeオブジェクトを生成して、

obj.rotate(angle:number);
// angle = めくれの角度

でページをめくる。

ページめくりを作る際、ページの裏表を表現するために、表向きのPlaneと裏返しのPlaneを貼り合わせて作る感じになるんだけど、
オリジナルの状態では裏返しのページを作る事が出来ないので、裏返しページ用に反転画像を作ったりする必要があったり、少々面倒。

公開元の、続きのエントリのコメント欄で、Planeを裏返しにする処理を追加する方法が記されているので、これを適用して使ってます。

  1. /*
  2. CurlingPlane.as
  3. Lee Felarca
  4. http://www.zeropointnine.com/blog
  5. v0.8.1 - 4-22-2007
  6. Mimics the curling of a sheet of paper, as if a page is being turned in a book.
  7. Source code licensed under a Creative Commons Attribution 3.0 License.
  8. http://creativecommons.org/licenses/by/3.0/
  9. Some Rights Reserved. Improvements made to this class are encouraged.
  10. HISTORY:
  11. v0.8.1 Removed sharedPresets() method, as it turned out to be little use.
  12. Added tesselation parameter to constructor.
  13. v0.8.0 First public release
  14. */
  15.  
  16. package
  17. {
  18. import org.papervision3d.core.*;
  19. import org.papervision3d.core.proto.*;
  20. import org.papervision3d.core.geom.*;
  21. import org.papervision3d.materials.BitmapMaterial;
  22. import flash.display.BitmapData;
  23. import flash.geom.Matrix;
  24. public class CurlingPlane extends Mesh3D
  25. {
  26. public static const MAX_ROTATION:Number = 180;
  27.  
  28. private var segmentsH:int;
  29. private var stripsU:Array = new Array();
  30. private var vStripWidths:Array = new Array();
  31. private var origVerts:Array = new Array();
  32. private var vertices:Array;
  33. private const DEGREE:Number = Math.PI / 180;
  34.  
  35. // hard-coded magic numbers (!) :P
  36. private var boundary1:Number = 55;
  37. private var boundary2:Number = 130;
  38. private var boundary1Mod:Number = 1.35;
  39. private var boundary2Mod:Number = 0.6;
  40. private var segmentsW:int = 5;
  41.  
  42.  
  43. //public function CurlingPlane(bmp:BitmapData, numHorizontalStrips:int = 5)
  44. public function CurlingPlane(bmp:BitmapData, numHorizontalStrips:int = 5, invert:Boolean = false)
  45. {
  46. /*
  47. * PARAMETERS:
  48. *
  49. * bmp The BitmapData image to be mapped to the plane.
  50. *
  51. * numHorizontalStrips Number of horizontal strips to be tesselated. More strips = less
  52. * texture perspective distortion, slower performance. Can be set as low
  53. * as 1. The default value of 5 seems to work pretty well for medium-sized
  54. * images. (Note that the number of vertical strips is hardcoded to 5.)
  55. */
  56. segmentsH = Math.floor(numHorizontalStrips);
  57. if (segmentsH < 1) segmentsH = 1;
  58. // spaces segmentsW in a logarithmic progression
  59. for (var i:int = 0; i <= segmentsW; i++)
  60. stripsU[i] = Math.log(i+1) / Math.log(segmentsW+1);
  61. /////////////////////
  62.  
  63. var myBitmapData:BitmapData
  64.  
  65. if (invert) {
  66. var myMatrix:Matrix = new Matrix();
  67. myMatrix.rotate(Math.PI);
  68. myMatrix.translate(bmp.width, bmp.height);
  69. myBitmapData = new BitmapData(bmp.width, bmp.height);
  70. myBitmapData.draw(bmp,myMatrix);
  71. } else {
  72. myBitmapData = bmp;
  73. }
  74.  
  75. /////////////////////
  76. super( new BitmapMaterial( myBitmapData ), new Array(), new Array(), null, null );
  77. this.material.smooth = true; // take note!
  78. vertices = this.geometry.vertices;
  79.  
  80. var width:Number = bmp.width;
  81. var height:Number = bmp.height;
  82.  
  83. var faces:Array = this.geometry.faces;
  84.  
  85. var gridX    :Number = segmentsW;
  86. var gridY    :Number = segmentsH;
  87. var gridX1   :Number = gridX + 1;
  88. var gridY1   :Number = gridY + 1;
  89. var iW       :Number = width / gridX;
  90. var iH       :Number = height / gridY;
  91. // Vertices
  92. for( var ix:int = 0; ix < gridX1; ix++ )
  93. {
  94. for( var iy:int = 0; iy < gridY1; iy++ )
  95. {
  96. var idx:Number = Math.floor( ix / (segmentsH+1) );
  97. var x:Number = stripsU[idx] * width;
  98. var y :Number = iy * iH - (height/2);
  99. vertices.push( new Vertex3D( x, y, 0 ) );
  100. }
  101. }
  102. if(invert) {
  103. vertices.reverse();
  104. }
  105. // Faces
  106. var uvA :NumberUV;
  107. var uvC :NumberUV;
  108. var uvB :NumberUV;
  109. for(  ix = 0; ix < gridX; ix++ )
  110. {
  111. for(  iy= 0; iy < gridY; iy++ )
  112. {
  113. // Triangle A
  114. var a:Vertex3D = vertices[ ix     * gridY1 + iy     ];
  115. var c:Vertex3D = vertices[ ix     * gridY1 + (iy+1) ];
  116. var b:Vertex3D = vertices[ (ix+1) * gridY1 + iy     ];
  117. uvA =  new NumberUV( stripsU[ix],  iy     / gridY );
  118. uvC =  new NumberUV( stripsU[ix],  (iy+1) / gridY );
  119. uvB =  new NumberUV( stripsU[ix+1], iy    / gridY );
  120. faces.push( new Face3D( [ a, b, c ], null, [ uvA, uvB, uvC ] ) );
  121. // Triangle B
  122. a = vertices[ (ix+1) * gridY1 + (iy+1) ];
  123. c = vertices[ (ix+1) * gridY1 + iy     ];
  124. b = vertices[ ix     * gridY1 + (iy+1) ];
  125. uvA =  new NumberUV( stripsU[ix+1], (iy+1) / gridY );
  126. uvC =  new NumberUV( stripsU[ix+1], iy     / gridY );
  127. uvB =  new NumberUV( stripsU[ix],   (iy+1) / gridY );
  128. faces.push( new Face3D( [ a, b, c ], null, [ uvA, uvB, uvC ] ) );
  129. }
  130. }
  131. // store the (unrotated) verts
  132. for (var l:int = 0; l < vertices.length; l++) {
  133. origVerts[l] = new Vertex3D();
  134. origVerts[l].x = vertices[l].x;
  135. origVerts[l].y = vertices[l].y;
  136. origVerts[l].z = vertices[l].z;
  137. }
  138.  
  139. // calc rectangle widths
  140. vStripWidths = new Array();
  141. for (var m:int = 0; m < segmentsW; m++) {
  142. vStripWidths[m] = stripsU[m+1] * width - stripsU[m] * width;
  143. }
  144.  
  145. this.geometry.ready = true;
  146. }
  147. public function rotate( degree:Number) : void
  148. {
  149. if (degree<0) degree=0;
  150. if (degree>MAX_ROTATION) degree=MAX_ROTATION;
  151. applyVerts( calcVerts(degree) );
  152. }
  153.  
  154.  
  155. private function calcVerts( degRot:Number ) : Array
  156. {
  157. if (degRot<0) degRot=0;
  158. if (degRot>MAX_ROTATION) degRot=MAX_ROTATION;
  159.  
  160. var myVerts:Array = new Array();
  161. var vStripRots:Array = new Array();
  162.   var r:Number = -degRot * DEGREE;
  163. var rMod:Number;
  164. // Calculate rotation amounts for each rectangle and store in vStripRots
  165.  
  166. // [A] Applies to all degrees
  167. rMod = boundary1Mod;
  168. // [B] Applies to all degrees > boundary1
  169. if (degRot > boundary1) {
  170. var a:Number = degRot - boundary1; // range: 0 to MAX_ROTATION - B1
  171. a = a / (boundary2 - boundary1) * boundary2Mod; // range: 0 to B2MOD
  172. rMod -= a; // range: B1MOD to B1MOD-B2MOD
  173. }
  174.  
  175. // Recursively multiply vStripRots elements by rMod
  176. for (var i:int=0; i < segmentsW; i++) {
  177. vStripRots[i] = r;
  178. r *= rMod;
  179. }
  180.  
  181. // [C] Applies to degrees > boundary2.
  182. //    Grow vStripRots proportionally to MAX_ROT. (Note the 'additive' nature of these 3 steps).
  183. if (degRot >= boundary2) {
  184. for (var j:int=0; j < vStripRots.length; j++) {
  185. var diff:Number = MAX_ROTATION*DEGREE - Math.abs(vStripRots[j]);
  186. var rotMult:Number = degRot - boundary2; // range: 0 to 30
  187. rotMult = rotMult / (MAX_ROTATION - boundary2); // range: 0 to 1
  188. vStripRots[j] -= diff * rotMult; // range: __ to MAX_ROTATION
  189. }
  190. }
  191. // [2] Create myVerts[]
  192. for (var k:int=0; k <  vertices.length; k++) {
  193. var idx:Number = Math.floor( k / (segmentsH+1) ) - 1;
  194. if (idx>=0) {
  195. myVerts[k] = new Vertex3D( vStripWidths[idx], origVerts[k].y, origVerts[k].z );
  196. } else {
  197. myVerts[k] = new Vertex3D( origVerts[k].x,    origVerts[k].y, origVerts[k].z );
  198. }
  199. }
  200.  
  201. // [3] Apply rotation to myVerts[]
  202. for (var l:int = segmentsH+1; l < myVerts.length; l++) {
  203. var idx2:Number = Math.floor( l / (segmentsH+1) ) - 1;
  204. myVerts[l] = rotateVertexY( myVerts[l], vStripRots[idx2] )
  205. }
  206.  
  207. // [4] 'connect' the rectangles
  208. for (var m:int = (segmentsH+1) * 2; m < myVerts.length; m++) { // (first 2 edges are fine)
  209. myVerts[m].x += myVerts[ m - (segmentsH+1) ].x;
  210. myVerts[m].z += myVerts[ m - (segmentsH+1) ].z; // (y stays constant)
  211. }
  212. return myVerts;
  213. }
  214.  
  215.  
  216. private function applyVerts( v:Array ) : void
  217. {
  218. for (var i:int = 0; i < vertices.length; i++) {
  219. vertices[i].x = v[i].x;
  220. vertices[i].y = v[i].y;
  221. vertices[i].z = v[i].z; 
  222. }
  223. }
  224. private function rotateVertexY( p:Vertex3D, angleY:Number ):Vertex3D
  225. {
  226. var x:Number = Math.cos(angleY) * p.x - Math.sin(angleY) * p.z;
  227. var z:Number = Math.cos(angleY) * p.z + Math.sin(angleY) * p.x;
  228. var y:Number = p.y;
  229. return new Vertex3D(x, y, z);
  230. }
  231. }
  232. }

※赤字は追加・変更した箇所
記されてなかったけど、flash.geom.Matrixをインポートしないとエラーになったので追記。

こうすると

var obj:CurlingPlane = new CurlingPlane(picData:BitmapData, curl:int, invert:Boolean );
// curl = planeの分割数
// invert = 裏返しにするかどうか(true:裏返し)

という定義になり、

ページを作る際、
表向き用1枚+裏返し用1枚を組み合わせて1ページを作る形に。

一応ソースも置いておきます。

3d_test04.zip(Flash CS3用)

※パブリッシュにはPaperVision3Dが必要です。

FLEXやFlashDeveropに移行しちゃった方が作業早そうなんだけど、
仕事でデザイナー側のFlash担当と連携することが多いので、未だにFlashの方が使用頻度高い…。

First Agentを振り返ってみる

2008.6.25 水曜日

デスマーチ状態の途中、
大人の事情でちょっと納期が延びて、若干余裕ができるも、
会社に篭もってたし、特に新しいネタもないので、駄文を書いてみたり。

昔、First Agentというブラウザゲームを運営してて、
思えばそれが、この道(web開発)に進んだ一番のきっかけになったなぁ、とふと思い返してみる。

どんな物か、というと、
パーツや武器を買ってロボットを組み立てて、他の人と対戦させて得た賞金でまたパーツを買い換えて…みたいな流れ。
で、勝つと名声が増えていってランクが上がったり、ランキングに載ったり。
全部PerlのCGIだったので、ゲーム画面は全部HTMLで、戦闘シーンとかもテキストベース。

今からしてみれば非常にお粗末なCGIゲームなんだけど、
やり始めた当時はネットゲームなんて物は全然広まって無くて、
ネットゲームと言えばPBeM(メールのやりとりで進行するゲーム)とか、CGIで行動を入力して、一定期間でサイト上に行動結果が更新されるような物とか、そういった物が多かった。
まだアナログ56kのテレホ全盛の頃だったし、今で言うオンラインゲームのような物はまだ黎明期、UltimaOnlineが出たばっかり、くらいだったかな…?

そんな状態だったので、割と受け入れて貰えたようで、思った以上に多数の人に遊んで貰えて、
一時期、雑誌に載ったり、2chのネットゲーム板にスレが立ったりしてて、ビックリした記憶が。
何度もサーバ落として、レンタルサーバを移転しつづけて、最終的には専用サーバを建ててしまったり…。

最初、運営し始めたときは、まだwebとは全然関係ない仕事をしてて(車のディーラーの営業)
完全に素人でした…。

CGI(Perl)も覚え立て、というか、それを作るために覚えた、といった感じ。

最初、webの事とか全然分からない状態で、PBeMのようなサイトをやり始めて、
もうちょっとリアルタイム性が欲しいなぁ、とか思い始めて、
そういえば、掲示板とかあるけど、どういう仕組みになってるんだろう、と思って調べてみたら、CGIの存在を知って、
「CGIなんてあるんだ、面白そう!」とか思って、
あちこちで配布してる掲示板スクリプトとかを落としてきて改造してみたりしつつ、徐々に覚えながら組み立ててみたのが上記のFirst Agent。

当時は(美大に行ってた影響で)Macしか持ってなかったので、
MacのSimple TextでCGIもHTMLも全部やってた…今思うと根性あったなぁ(笑
営業の仕事って拘束時間長いので(今はもっと長いかも!)夜な夜な寝る時間削ってコツコツやってました。

一通り完成後、テストプレイ公開して、いくつか宣伝してみたら、口コミなのか徐々に人が増えてきて、
そこで思ったのが「webって面白い!」
自分の作った物に不特定多数の人が集まってくる、という事にもの凄く感動したのを今でも覚えてる。

その後暫くして、営業の仕事を退職。
元々学生時代は車にはまっていて、その影響で進んだ仕事で、
営業という仕事は社会的な事も沢山学べるし、得る物も沢山あったんだけど、
自分がやりたいこととは違う、と強く思うようになっていて、
恐らく、この頃にはもう、webの世界に行こうと思い始めていたんだと思う。

退職して暫く時間が出来たので、仕事を探しつつ、新たにCGIの事を勉強して、
First Agentの方もアップデートしたりしながら数ヶ月。
ネットの求人により、今の会社と出会い、入社。

当時はまだ、開発に進みたい、とかまでは考えていなくて、
漠然と「何かを創る仕事をしたい」と思ってたので、特に部署の希望とかは無かったんだけど、
面接の際、作品持参とあったので、FirstAgentの画面見せて、
「こんなサイトを運営しています」
といくつか動くところを見せてみたら、どうやらシステム部に決まったらしく(笑

CGIを囓った程度の、限りなく素人に近いシステム部員となり、
分からないことだらけだったのでとにかく必死に勉強。

勉強して覚えたことはFirstAgentに反映されて、
逆に、FirstAgentで新しいこと試してみて、それが仕事に反映されたり。
しばらくはFirstAgentと仕事の二人三脚状態。

最初のスタート時
So-net(当時のプロバイダ)のレンタルサーバでCGI+データはテキストファイル(掲示板の延長)
ここのサーバはSolarisで(当時は分からなかったけど)、何故か排他処理しててもファイルがよく飛んだ…

自己ドメイン取得(今も使ってるmaro-z.com)
自己ドメインとCGIが使えるレンタルサーバを借りてCGI+テキストファイル
月\5000、当時の相場かな…?

ここで転職

ネットゲーム制作者メーリングリストみたいなのに参加するようになって、
そこの人が借りた専用サーバを間借りさせて貰えることになり、移転
DBの扱い覚えたので、リニューアルがてら、CGI+PostgreSQLに。
頻繁にサーバ落としてしまい、申し訳なさ過ぎたので早々に移転を考えてた…。

Linuxサーバの構築を覚えたので、専用サーバを借りることを決意
CGI+PostgreSQL
AT-LINKで月\30450
少々痛かったけど、車いじりをしなくなったので、パーツ代とかに使ってた分を回した感じ。

んで、新たにPHP+MySQLで組み直してたんだけど、
色々とあって一旦更新を停止。
サイト自体は残ってたけどそのまま廃墟と化してしまい…。

何度か再開を計画するも、頓挫してしまってます。
数年前に一度TOPをリニューアルして、開発も進めてたら、
当時、(休止から数年経ってたのに)まだ覚えてくれてたユーザーさんが次々と訪問してくれて、それもまた感動でした。

それも暗礁に乗り上げて、ずっと止まってしまっていて、
変に期待させてしまって申し訳なかったなぁ…と…。

でも未だに、色々考えてみたり作ってみたりはしてはいます。
折角だからまたwebを使って何か面白いことやりたいし!

ちと長くなったので、また次回にでも。

デスマーチ・クライマックス

2008.6.22 日曜日

もの凄い勢いで会社に缶詰中。

うひー。

祭りが始まってた。

2008.6.18 水曜日

帰宅して、しばらくしたらFirefox祭りが始まってた。

DL開始が「Tuesday, June 17th 10:00 PDT.」とのことで、
日本時間で午前2時から。

DLサイトにも、アドオンのサイトにもぜんっぜん繋がりません!

Flock 2.0Betaにアップグレード&日本語化

2008.6.17 火曜日

先日エルワンさんから頂いたコメントで、FireFox3.0ベースのFlock2ベータがリリースされたということで、
早速入れてみました。

Flock 2.0 Beta

前回と同じ方法で一部日本語化出来るかな、と思って試してみたら、できたので一応報告。

バージョン情報を表示してみたら、

Firefox/3.0 Flock/2.0b1となっているので、
またしてもこちらで、

3.0正式版用の言語ファイルがリリースされていたので、
/3.0/win32/xpi/ja.xpiをインストール。


成功。
毎度の事ながら、アプリ名が「Mozilla Firefox」になってしまうのがちょっと悲しい。
Firefox用の言語ファイル使ってるから仕方ないんだけども。

今回はアップグレードで、プロファイルもそのまま移行したので、作業は以上で完了だったけど、
新規インストールの場合は、about:configでロケールの変更をお忘れ無く。

手順は、以前書いた、
Flockを使ってみる&一部日本語化
こちらの手順そのままです。

少々使ってみた感想。
Firefox3がベースなだけに、1と比べたらかなり速くなってます。

あと、嬉しい点。
1の時は、general.useragent.localeをja-JPにしていても、googleとかの多言語サイトでは英語版ブラウザ扱いをされてたっぽかったけど、
今回はちゃんと日本語版ブラウザとして扱ってくれてる。

仕事用、個人用で、暫くFirefox3と併用してみようかな。
あとは、日本のソーシャル系サービスに対応してくれたら文句なしかなぁ。
Firefox+ソーシャル系アドオンが売りのブラウザだし。