DisplacementMapFilterを使用した空間へのへこみ

メインの仕事からの自由時間に、私はゲーム制作の分野で彫刻をします。

最後の記事は、古典的な宇宙防衛タワーの防衛に関する記事です。



ゲームはアイソメで行われるため、このようなシーンを描きたかった





ここから取られた



疑問が生じました-どうやって?




ありがとう、専門会議の親切な人が検索パスを提案しました-DisplacementMapFilter。

ドキュメントを開いて、いくつかの例をコピーし、独自のフィルターを作成しようとしましたが、すぐには機能しませんでした。

ソリューションの検索については説明しません。すぐに結果を( Googleコードで )提示し、いくつかの重要な説明を作成します。



作業クラスDisplacementMapFilterGravityおよびDisplacementMapFilterGravityParamsのコードをそのまま拡散しました。 執筆時点では、これらはプロジェクトのものと同じです。 Mainクラスはデモンストレーション用です。



クラスMain

  1. drawGrid()-グリッドを描画してビットマップに保存します。これはシーンにくっついています
  2. updateGravities()-フィルタークラスを構成します。

    • ISOMETRIC座標に基づいて2つの重力領域を追加します(実験すると、クラスは等尺性レンダリングから引き裂かれます)
    • ビットマップに描かれたグリッドにフィルターを適用します
  3. drawPlanets()-「惑星」を描画します。 実際、これらは「へこみ」に投影された単なる装飾です


クラスDisplacementMapFilterGravity

  1. createDisplacementFilter-名前はそれ自体を物語っています
  2. createDisplacementMap-フィルターマップを作成します
  3. getShape-特定の重力領域の形状を生成します
  4. getRectangleIntersection-ヘルパーメソッド。重力場の交差領域を検索します




次に、アルゴリズムの詳細を説明します。




1.クラスMainで、フィルターカードの「製造」用のデータを準備します



private function updateGravities():void { var funcs:Array = [Easing.easeOutQuart];//, Easing.easeOutCubic, Easing.easeOutCircular]; var arr:Array = []; var params:DisplacementMapFilterGravityParams; params = new DisplacementMapFilterGravityParams(); params.x = 250; params.y = 50; params.radius = 200; params.func = funcs[arr.length%funcs.length]; arr.push( params ); params = new DisplacementMapFilterGravityParams(); params.x = 500; params.y = 100; params.radius = 300; params.func = funcs[arr.length%funcs.length]; arr.push( params ); ... }
      
      





アイソメの座標をすぐに設定します(クラスはリアルであり、アイソメのレンダリングから引き裂かれているため)



2.パラメーターをDisplacementMapFilterGravityに渡した後、「グラデーションパンケーキ」-「へこみ」の空白を描画します



 private function getShape(gr:DisplacementMapFilterGravityParams):Shape { var shape:Shape = new Shape(); var g:Graphics = shape.graphics; var color:uint; var radius:int = gr.radius; // TODO    ""   (..     ,    ) var deep:int = 10000/radius; for(var r:Number=radius-1; r>-1; r--) { color = gr.func(r, deep, 0x80-deep, radius-1); g.beginFill(color); g.drawCircle(0, 0, r); g.endFill(); } return shape; }
      
      





それは次のようなものになります(しかし、はるかに大きい-ページ上のスペースを占有しないように、より細かく描写しました)







暗い色-未来の空洞、明るい(0x80)-平面レベル



ここで、マジックナンバー0x80に特別な注意を払いたいと思います-これは、カラーチャンネルの値です(フィルターがピクセル単位でシフトを実行するのに関連する)ことは、歪みレベルがゼロであることを意味します-フィルターは、このカラー値でピクセルをシフトしません。 つまり -この場合のグリッドプレーンのレベルはゼロ(チャンネルカラー0x80)であるため、窪みのエッジがグリッドプレーンにスムーズに移行するように、この値(0x80)も必要です。



次に、機能について説明します。これは、サイクル内で同様の状況を示しています。 これはEasing.easeOutCircularにすぎず、グラフは次のようになります







他の関数の例はチートシートで見ることができ、 ここで実装を取り、 新しいものを発明します



コード行(イージングsの処理方法) -color = gr.func(r、deep、0x80-deep、radius-1); -jQuery Easingの短い記事を読むだけで理解できます カスタムイージング»



3.「ベイク」後 、マトリックス変換を使用してパンケーキを別のビットマップにコピーし(等角投影を取得する必要があります)、等角座標に共通のコンテナーを配置します



 public function createDisplacementMap():void { ... var gr:DisplacementMapFilterGravityParams; for(var i:int=0; i<arrGravities.length; i++) { gr = arrGravities[i]; shape = getShape(gr); var bmd:Bitmap = sprite.addChild(new Bitmap(new BitmapData(shape.width*2+2, shape.height+2, true, 0x00ff00))) as Bitmap; bmd.bitmapData.draw(shape, new Matrix(1, .5, -1, .5, shape.width + 1, shape.height/2 + 1)); bmd.x = UtilsIsometric.xToIsoX(int(gr.x), int(gr.y)) - bmd.width/2; bmd.y = UtilsIsometric.yToIsoY(int(gr.x), int(gr.y)) - bmd.height/2; } ... }
      
      







その結果、コンテンツを含むコンテナは次のようになります。「パンケーキ」は互いに重なり合います-スムーズな移行はありません







4.将来の不況の間をスムーズに移行する必要があります 。 要するに、すべての「パンケーキ」が順番に撮影され、交差点で色が比較され、結果としてより大きな深度(より暗い)に対応する色が選択されます。 最終結果は次のようになります。







 public function createDisplacementMap():void { ... {//   ,      var child:Bitmap = sprite.getChildAt(0) as Bitmap; var rectChild:Rectangle = child.getBounds(sprite); bitmapdata.draw(child, new Matrix(1,0,0,1,rectChild.left-rect.left + 1, rectChild.top-rect.top + 1)); var rectSumm:Rectangle = rectChild.clone(); for(var l:int=1; l<sprite.numChildren; l++) { child = sprite.getChildAt(l) as Bitmap; rectChild = child.getBounds(sprite); var rectIntersection:Rectangle = getRectangleIntersection(rectSumm, rectChild); var bmdIntersection:BitmapData; if(rectIntersection != null) { bmdIntersection = new BitmapData(rectIntersection.width, rectIntersection.height, false, 0xff0000); bmdIntersection.draw(bitmapdata, new Matrix(1,0,0,1, -rectIntersection.left+rect.left, -rectIntersection.top+rect.top)); bitmapdata.draw(child, new Matrix(1,0,0,1,rectChild.left-rect.left + 1, rectChild.top-rect.top + 1)); var bColor:uint; var pColor:uint; var lengthW:int = bmdIntersection.width; var lengthH:int = bmdIntersection.height; for(var xx:int=0; xx<lengthW; xx++) { for(var yy:int=0; yy<lengthH; yy++) { pColor = bitmapdata.getPixel(xx+rectIntersection.left-rect.left, yy+rectIntersection.top-rect.top); bColor = bmdIntersection.getPixel(xx, yy); bitmapdata.setPixel(xx+rectIntersection.x-rect.left, yy+rectIntersection.y-rect.top, ( pColor > bColor ? bColor : pColor )); } } } rectSumm = rectSumm.union(rectChild); } ... } }
      
      







5.最終結果では、もちろん白い領域は同じ0x80で「塗りつぶされ」ます(すべてが0x80の背景色でビットマップにコピーされます)。



6.フィルターを適用した後、新しいグリッドを取得します。







トラフは見た目がよくないように見えるので、惑星でカバーします。







変形の場所のグリッドも「壊れやすい」ように見えます。これを何らかの方法で隠すことができるかどうか、アーティストのアドバイスを求める必要があります。 できなければ、少なくともプロトタイプで使用できます。 たとえば、次のように



All Articles