Windows Phone 7 XNA:ピクセルを曲げるか、シェーダーに合わせない

こんにちは親愛なる友人。



繰り返しますが、多くの時間が経ちましたが、興味深い情報であなたを喜ばせませんでした

ゲームの開発について。 今日、私はこの記事をWP7用のゲーム開発に捧げたいと思います

ここここここここで書いたすばらしいXNAフレームワーク。 具体的には、 シェーダーなしで美しいエフェクト作成する方法を説明します。 この記事では、歪み影響について検討します 。 残りはカットの下にあります。











理論





私がシェーダーについて書いた最後の2つの記事と、ゲームの視覚を改善する方法。 しかし、 ReachHiDef XNAプロファイルの比較を見ると、恐ろしいことがあります

ReachShader Modele 2.0をサポートしており、 WP7はそれをまったくサポートしていないことを確認してください。 そして、これからシェーダーなしでこれをすべて行う方法考え出し、ヒットさせたいと思います。



もちろん、通常のマッピングを使用したクールな照明については説明していません(ただし、変質することはできます) 。BasicEffectを使用してピクセルを曲げる方法についてのみ説明しています。 この方法は狂気に単純ですが、非常に効果的です。



だから、あなたが私が誰であり私が書いたもの思い出すなら、私たちはそのアルゴリズムを思い出すことができます

シェーダーで使用:歪みマップとカラーマップがあります。 歪みマップに従って、カラーマップを曲げます。 ただ? 忘れて この方法は、GPUの介入なしにWP7で実装することは非常に困難です(残念ながら、アクセスできません)。



-どうする?



どのような原理で、たとえば普通の平らな正方形など、3Dで何かを描くのか覚えていますか? 2つの三角形を使用して描画されます。 これはどのように役立ちますか? シンプルで、たくさんの三角形を作成してから、テクスチャ座標を使用して、「kakbe」を三角形自体に移動して、歪み効果を作成します。



実際、画像があります-480x800、48x80のグリッドを作成します(美しい効果のために-ちょうどいい)。 グリッドは、3840要素の1次元配列です。 WP7では約3〜4ミリ秒 、メッシュ品質は1〜2ミリ秒で計算されます。 しかし、グリッドが小さすぎる場合、歪みがあると、三角形がまだ存在していることがわかります。 しかし、グリッドが10倍小さい場合、これは比較のために目立ちません-画面上のステップは3 mm = 10ピクセルです。 さて、大丈夫、私は会話に入ったもの。



-おいおい、それで十分な理論です、練習に行きます。



練習する





プリミティブから画面に何かを描くには、 BasicEffectが必要です 。 たとえば、 spriteBatchはあらゆる種類のBasicEffectを目から隠す巨大なクラスですが、最終的にはプリミティブを描画し、テクスチャを適用することになります。 このケースでのBasicEffectの使用について、さらに詳しく説明しようと思います。



材料を探して、道路に行きます。



まず、曲げるテクスチャが必要です。愛する友人に会います。





そして、どういうわけか奇妙ですが、空のプロジェクトが必要なので、作成します。



WP7でのXNAの機能の1つは、デフォルトで30 FPS (ネイティブ60 FPSではなく)であることです。 しかし、何かがそれ以上のことが可能であることを教えてくれます。 一方、タイムキラーではなく、キラーバッテリーが必要なのは誰ですか? したがって、 30 FPSを使用します。



空のプロジェクトには次のものがあります。



// Frame rate is 30 fps by default for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks(333333); // Extend battery life under lock. InactiveSleepTime = TimeSpan.FromSeconds(1);
      
      







FPSを担当する行-自分で推測します。



次のポイントはキーボードがないことです。すべてのアクションはマルチタッチを使用して実行されます。

インターセプトできる唯一のボタンは、デフォルトでは「戻る」ボタンです-アプリケーションを終了します。



 if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();
      
      







したがって、空のプロジェクトでは何も触れず、プログラミングに進み、実際に練習します。 まず第一に-Game1を意味と愛で満たしてください



変数を作成します。



 Texture2D background; BasicEffect basicEffect;
      
      







background-テクスチャ、まあ、または何らかのRenderTarget。

BasicEffectは、プリミティブを描画するために必要なヒーローです。



コンテンツをロードします。



 background = Content.Load<Texture2D>("distortion");
      
      







私はほとんど忘れていました、コンストラクタに入れてください:



 graphics.PreferredBackBufferWidth = 480; graphics.PreferredBackBufferHeight = 800; graphics.IsFullScreen = true;
      
      







そのため、オリエンテーションが1つあり、ポジショニングに問題はありませんでした。



BasicEffectの初期化(初期化中)



 basicEffect = new BasicEffect(GraphicsDevice); basicEffect.TextureEnabled = true; //      basicEffect.Projection = Matrix.CreateOrthographicOffCenter(0, 480, 800, 0, 0f, 10f); basicEffect.View = Matrix.Identity; basicEffect.World = Matrix.Identity;
      
      







投影-2次元平面(スクリーン)への3次元オブジェクトのマトリックス投影。

ビュー -必要に応じて、ビューのマトリックス、カメラ。

ワールド -ワールドマトリックス:回転、サイズ、位置。



ビューワールド -単位行列を設定します

そして、 射影は正射影を定義します。 プリミティブがスクリーンに完全に投影されます。 説明しやすい場合は、画面の端にあるプリミティブの端。



それでは、 とりあえずGame1で、新しいクラスGridVertexPositionColorTextureを作成しましょう。ここにその完全なリストがあります(完全なものをおaびしますが、コメント付きです)。



 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework; namespace GridDistortion { public class GridVertexPositionColorTexture { public VertexPositionColorTexture[] Vertices; //   ,      ,    UV   public short[] Indices; // ,       ,   3D ,   ,    public int Width; //    X public int Height; //    Y public Vector2 CellSize; //       X  Y  public void BuildGeometry(int colums, int rows, Vector2 cellSize) //     { Width = colums; Height = rows; CellSize = cellSize; Vertices = new VertexPositionColorTexture[(Width + 1) * (Height + 1)]; //    Indices = new short[Width * Height * 6]; //      /*    */ for (int i = 0; i < Width + 1; i++) { for (int j = 0; j < Height + 1; j++) { int index = j * (Width + 1) + i; VertexPositionColorTexture vertex = new VertexPositionColorTexture() { Position = new Vector3(new Vector2(i, j) * CellSize, 0f), //   Color = Color.White, TextureCoordinate = GetDefaultUV(index) //   }; Vertices[index] = vertex; } } /*    */ int indexPos = 0; for (int i = 0; i < Width; i++) { for (int j = 0; j < Height; j++) { int v0 = j * (Width + 1) + i; int v1 = j * (Width + 1) + i + 1; int v2 = (j + 1) * (Width + 1) + i; int v3 = (j + 1) * (Width + 1) + i + 1; Indices[indexPos] = (short)v0; Indices[indexPos + 1] = (short)v1; Indices[indexPos + 2] = (short)v2; Indices[indexPos + 3] = (short)v2; Indices[indexPos + 4] = (short)v1; Indices[indexPos + 5] = (short)v3; indexPos += 6; } } } public void Draw(GraphicsDevice graphicsDevice) //     VertexPositionColorTexture { graphicsDevice.DrawUserIndexedPrimitives<VertexPositionColorTexture>(PrimitiveType.TriangleList, Vertices, 0, Vertices.Length, Indices, 0, Indices.Length / 3); } public void ResetUVs() //  UV  { for (int i = 0; i < Vertices.Length; i++) { VertexPositionColorTexture v = Vertices[i]; v.TextureCoordinate = GetDefaultUV(i); Vertices[i] = v; } } public Vector2 GetUV0(int index) //    { return Vertices[index].TextureCoordinate; } public void SetUV0(int index, Vector2 value) //    { Vertices[index].TextureCoordinate = value; } public Vector2 GetDefaultUV(int index) //       { int i = index % (Width + 1); int j = index / (Width + 1); return new Vector2((float)i / Width, (float)j / Height); } } }
      
      







すべてが正常で、プリミティブの描画とグリッド自体を担当するクラスが作成されました。 次に、このグリッド用のコントローラーを考え出す必要があります。 この記事では、 SimpleGridElasticGridの 2つのグリッドコントローラーについて説明します。



まず、グリッドをリセットし、現在の歪みを適用します。

2番目はグリッドをゼリーに変えます。ゼリーはデフォルトの状態になるまで変動します。



最初のコントローラーを作成し、新しいSimpleGridクラスとそのリストを作成します。



 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; namespace GridDistortion { public class SimpleGrid { publicGridVertexPositionColorTexture grid; //    public SimpleGrid(GridVertexPositionColorTexture grid) { this.grid = grid; } public void Update() { swap(); } public virutal void swap() //       { grid.ResetUVs(); } public void Rebellion(Vector2 pos_rebellion, float radius) //         { Vector2 gridSize = new Vector2(grid.Width, grid.Height) * grid.CellSize; //    for (int i = 0; i < grid.Vertices.Length; i++) { Vector2 pos = grid.GetUV0(i) * gridSize; //       Vector2 newPos = pos; Vector2 center = pos_rebellion; //    float distance = Distance(pos, center); //         if (distance < radius) //    ,    ,   { Vector2 dir = pos - center; //    float length = dir.Length(); float minDisplacement = -length; if (dir.Length() != 0) { dir.Normalize(); //   } Vector2 displacement = dir * Math.Max(-100f, minDisplacement); //   ,  -100f —  ,   —   ,   newPos += displacement * (1f - distance / radius) * 0.25f; grid.SetUV0(i, newPos / gridSize); //    } } } public static float Distance(Vector2 vector1, Vector2 vector2) { double value = ((vector2.X - vector1.X) * (vector2.X - vector1.X)) + ((vector2.Y - vector1.Y) * (vector2.Y - vector1.Y)); return (float)Math.Sqrt(value); } } }
      
      







コントローラーが作成され、 Game1に戻ります。2つの新しい変数:



 GridVertexPositionColorTexture grid; SimpleGrid simpleGrid;
      
      







それらの初期化:



 grid = new GridVertexPositionColorTexture(); grid.BuildGeometry(48, 80, new Vector2(10, 10)); simpleGrid = new SimpleGrid(grid);
      
      







自身を更新する:



 simpleGrid.Update(); //    TouchCollection collection = TouchPanel.GetState(); //    foreach (TouchLocation point in collection) { if (point.State == TouchLocationState.Moved) { simpleGrid.Rebellion(point.Position, 100f); //     point.Position   100f } }
      
      







そして最後に、図面:



 GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp; //  Clamp, ..  Wrap-    Reach ,      basicEffect.Texture = background; //     basicEffect.CurrentTechnique.Passes[0].Apply(); //  basicEffect grid.Draw(GraphicsDevice); //  
      
      







画面をタッチして、レンズの歪みや効果を確認します。

ただし、 SimpleGridから継承したElasticGridクラスのテクスチャからゼリーを作成して、楽しみましょう。



 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; namespace GridDistortion { public class ElasticGrid : SimpleGrid { private Vector2[] Velocity; //   public ElasticGrid(GridVertexPositionColorTexture grid) : base(grid) { this.Velocity = new Vector2[(grid.Width + 1) * (grid.Height + 1)]; } public override void swap() { Vector2 gridSize = new Vector2(grid.Width, grid.Height) * grid.CellSize; for (int i = 0; i < grid.Vertices.Length; i++) { //Get the position in pixels Vector2 pos = grid.GetUV0(i) * gridSize; Vector2 pos_default = grid.GetDefaultUV(i) * gridSize; Vector2 dir = (pos_default - pos) / 1.1f; //          1.1f, //Set the new Texture Coordinates grid.SetUV0(i, (pos + Velocity[i]) / gridSize); //   +   Velocity[i] = dir; //     } } } }
      
      







Game1のグリッドコントローラーを変更し、歪みを楽しんでください。



以下に、このようなシンプルで興味深いアプローチを示します。 コントローラーの数は無制限です。たとえば、波やand婦のあるシェーダーなしのリアルタイムのリアルな水です。



次回は、ゲームに美しさを追加する他の方法を説明しようとします。

また、XNAシリーズの3Dトピックに関する記事を書く予定です。

ボーナスとして、次の記事では、おそらくWP7でゲームを作成し、広告なしで無料で市場に投入し、貧困に陥る方法について説明します。



ソースはここからダウンロードできます



実験、作成; じゃあまたね:-)



All Articles