タグ「Papervision3D」の一覧

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の方が使用頻度高い…。