Windows 8およびWindows Phone 8.1上のOpenGL ES 1.1

1998年に、OpenGLを使用してゲームを作成しようとしました。 開発はほとんどアルファに達せず、放棄されましたが、特に覚えているのは、GLインターフェース(直交投影、2、3の変換、GL_TRIANGLE_STRIPを備えたいくつかの頂点バインダー)を行うのがどれほど便利かということで、すでにボタンがあります。 そして今、16年後、モバイルゲームの構築を行った後、OpenGL ES 1で同じアプローチに出会いました。*、回転のない2DテクスチャをglDrawTexfOESで描画できない限り。

この原則に基づいて作成されたいくつかのプロジェクトをサポートし、OpenGL ESとC#を使用してモバイルで、通常のOpenGLを使用してデスクトップでクロスプラットフォームの2Dゲームを作成するという少し陰湿な計画を立てました。 私は最初に目標を達成しませんでしたが、これには多くの問題がありましたが、結果として、次のプロジェクトはiOS、Android、BlackBerry、Windows XP / 7、Mac OS X、Linux、ReactOS、Windows 8のビジネスロジックを変更することなく機能しますWindows Phone 8.1。 多くの記事で多くの資料を集めましたが、今回はWindowsランタイムのサポートについてお話します。



Opentk



フルゲームにはシェーダーとマルチパスレンダリングが必要であることを納得させるために、特に2D向けのOpenGLの利便性について多くのことを議論できます。同時に、古いOpenGL ES 1.1がシェーダーを介したエミュレーションのレベルで正確に実装されていることを確認できます。 これはドン・キホーテと理論家に任せます。 しかし、これは、巨大なUnity、MonoGame、およびその他のエンジンを使用せずに、2Dレンダリングコードを1回作成して異なるプラットフォームで実行する最も簡単な方法であると心配していました。

iOSおよびAndroidでは、Xamarinの下ですべてがスムーズに進み、GLの操作はOpenGL.Graphics.GL11名前空間を持つOpenTKライブラリを介して行われ、定数とメソッドは両方のプラットフォームで同じです。 デスクトップでは、OpenTK.Graphics.OpenGL、つまり C#ラッパーを使用した通常のデスクトップOpenGL。 原則としてglDrawTexfOESはありませんが、GL_TRIANGLE_STIP / GL_TRIANGLESとglDrawElementsを使用して問題なく交換でき、2つの三角形を描画できます。モバイルと比較して、パフォーマンスは十分であり、VBOはここでは必要ありません。

GL_TRIANGLESを使用したラッパーの例
private static readonly int[] s_textureCropOesTiv = new int[4]; private static readonly short[] s_indexValues = new short[] { 0, 1, 2, 1, 2, 3 }; private static readonly float[] s_vertexValues = new float[] { -0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; public void glDrawTexfOES(float x, float y, float z, float w, float h) { glPushMatrix(); glLoadIdentity(); glTranslatef(w / 2.0f + x, h / 2.0f + y, 0.0f); glScalef(w, -h, 1.0f); int[] tiv = s_textureCropOesTiv; // NOTE: clip rectangle, should be set before call int[] texW = new int[1]; glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, texW); int[] texH = new int[1]; glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, texH); float[] texCoordValues = new float[8]; float left = 1.0f - (tiv[0] + tiv[2]) / (float)texW[0]; float bottom = 1.0f - tiv[1] / (float)texH[0]; float right = 1.0f - tiv[0] / (float)texW[0]; float top = 1.0f - (tiv[1] + tiv[3]) / (float)texH[0]; texCoordValues[0] = right; texCoordValues[2] = left; texCoordValues[4] = right; texCoordValues[6] = left; texCoordValues[1] = bottom; texCoordValues[3] = bottom; texCoordValues[5] = top; texCoordValues[7] = top; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, s_vertexValues); glTexCoordPointer(2, GL_FLOAT, 0, texCoordValues); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, s_indexValues); glPopMatrix(); }
      
      





このコードを自分でコピーする価値はないことに注意してください-GL_TEXTURE_WIDTH / GL_TEXTURE_HEIGHT定数がない場合は機能しません。 同時に、呼び出しの前にs_textureCropOesTiv変数を入力する必要があり、コード自体は縦座標に沿ってビューポートを反転しません。





Xaml



現在のバージョンのMono、.Net 2.0-4.5、Wine、およびReactOSで同時にプロジェクトを実行するには、ある程度の魔法が必要でしたが、一般に、テクスチャを備えた動物園以外に特別な問題はありませんでした。 しかし、問題はWindows 8とWindows Phoneで始まり、OpenGLは原則として存在しません。 最初から、私は文字通りglDrawTexfOESの私のバージョンを追加して、少し血でそれを解決しようとしました。 実験中に、XAML Canvas要素を使用し、その中にRectangleを描画しました。Rectangleは、Brushでテクスチャの一部のみを表示するために必要な変換を使用しました。

XAMLの変換コード
  TransformGroup group = new TransformGroup(); ScaleTransform scale = new ScaleTransform(); scale.ScaleX = (double)texture.PixelWidth / (double)clipRect.Width; scale.ScaleY = (double)texture.PixelHeight / (double)clipRect.Height; group.Children.Add(scale); TranslateTransform translate = new TranslateTransform(); translate.X = -scale.ScaleX * (double)clipRect.X / (double)texture.PixelWidth; translate.Y = -scale.ScaleY * (double)clipRect.Y / (double)texture.PixelHeight; group.Children.Add(translate); imageBrush.RelativeTransform = group;
      
      





clipRect-トリミングパラメーター付きの長方形、上記の例のs_textureCropOesTivの類似物

texture-テクスチャ自体を含むBitmapSource



この方法は奇妙に思えますが、XAMLは多くの場合ハードウェアアクセラレーションであり、かなり高速です。 Windows 8でいくつかのOpenGL ESモバイルゲームをこのアプローチに移植しましたが、それらはかなりうまく機能しますが、glColorを介したGLのように、テクスチャの色を変更する方法はありません。 つまり 原則として、XAMLでは要素の透明度を変更できますが、色の濃淡を変更することはできません。 たとえば、白いフォントを使用してから異なる色でペイントした場合、このアプローチではそれらは白のままになります。



一般に、XAMLを使用したバージョンはかなり疑わしく、元の計画にまったく対応していませんでした。また、モジュレーションパンツの色の区別がなくても、ゲームが80%の準備ができてモバイルおよび固定の.Net / Monoで既に動作していたため、より受け入れやすいオプションを探し始めましたWindows8。Angleライブラリの移植について多くのうわさや熱意がありましたが、当時はすでに非常に生でC#のサポートがありませんでした。 直接、C#からDirectXを直接操作することもできませんでした。Microsoft自体が開発者にいくつかの「簡単な」方法を提供します。すべてのC#コードをC ++で再作成する、サードパーティのSharpDXライブラリを使用する(DirectX経由のC#バインディング)、またはMonoGameに切り替える MonoGameライブラリは、Windows 8で同じSharpDXを使用してグラフィックスを表示するXNAの子孫であり、かなり優れていますが、非常に具体的であり、私のプロジェクトで切り替えるのは少し遅かったです。 SharpDXは、既存のすべてのDirectX機能を使用しているので、私が必要とするものにかなり近いものの、それほど怪しくはありませんでした。 gl2dxプロジェクトに出くわしたとき、私はすでにはんだごてとマニュアルで彼と真剣な会話を始めました。



GL2DX



このライブラリは、数年前にCodePlex平均的なユーザーによってアップロードされ、もはや更新されていません。 これは、OpenGLと同じ関数を宣言し、それらをD3D11呼び出しに内部的に変換するC ++ライブラリです。 ライブラリのC ++ / CXには、SwapChainBackgroundPanelを使用してXAMLページを作成し、D3D11CreateDeviceを通じて初期化してC ++パーツで動作する例がありました。 このプロジェクトは、少なくともプロトタイプの段階から少しでも外れていれば良いでしょう。 技術的には、OpenGLメソッドのほんの数パーセントしか機能せず、残りはアサーションです。 一方、2Dテクスチャ出力、変換、および単純なジオメトリを処理します。 この段階で、ライブラリを引き継ぎ、製品の状態にしました。これにより、Visual Studio拡張機能としてC#プロジェクトに接続し、同様のコードを記述できます。

コード
  GL.Enable(All.ColorMaterial); GL.Enable(All.Texture2D); GL.Color4(1.0f, 1.0f, 1.0f, 1.0f); GL.TexParameter(All.Texture2D, All.TextureCropRectOes, new int[] { 0, 0, 1024, 1024 }); GL.BindTexture(All.Texture2D, m_textureId1); GL.DrawTex(0, - (m_width - m_height) / 2, 0, m_width, m_width); for (int i = 0; i < 10; i++) { if (i % 2 == 0) { GL.BindTexture(All.Texture2D, m_textureId2); GL.TexParameter(All.Texture2D, All.TextureCropRectOes, new int[] { 0, 0, 256, 256 }); } else { GL.BindTexture(All.Texture2D, m_textureId2); GL.TexParameter(All.Texture2D, All.TextureCropRectOes, new int[] { 256, 0, 256, 256 }); } int aqPadding = 20; int fishSize = 128; int aqWidth = (int)m_width - aqPadding * 2 - fishSize; float x = (Environment.TickCount / (i + 10)) % aqWidth; float alpha = 1.0f; if (x < fishSize) alpha = x / fishSize; else if (x > aqWidth - fishSize) alpha = (aqWidth - x - fishSize) / 128.0f; GL.Color4(1.0f, 1.0f, 1.0f, alpha); GL.DrawTex(x + aqPadding, m_height / 20 * (i + 5), 0, fishSize, fishSize); }
      
      





PSコードはOpenTK呼び出し形式であり、GL.Color4の代わりにglColor4fを書くことに慣れている人にとっては少し混乱します。

これらのことは私から誇らしげな名前MetroGLを受け取りました。



メトログル



C ++ / CXの例は、同じ鳥の現代言語ライブラリに変換され、多数の追加機能で草に覆われ、C ++は多くのOpenGLメソッド、ブレンド、内部VertexBuilderの最適化、任意の画像とDDSテクスチャのロード、そして最も重要なglDrawTexfOESの実装を受け取りました1v1はOpenGL ESの場合と同じ図ですが、同時に1つのテクスチャを使用して順次操作を1つのDrawCallに接続します。 ファイルを使用して何かを作成する必要があり、コード自体が場所で汚れています(私の前後両方)。VSIX拡張機能を作成するには、各アーキテクチャ(x86、x64、ARM)のプロジェクトを手動で再構築し、VSIXプロジェクトのみをビルドする必要があります。 主なことは、OpenGL ES 1をお持ちの場合* 2Dインターフェイスまたは複雑な3Dのコードがない場合、このライブラリを使用すると、内部、C ++コード、D3D11コンテキスト、その他の厄介な喜びを考えずにC#から直接使用できます 同時に、右側の魚とカタの下からのコードで例が作られました。 もちろん、シェーダーと拡張機能を備えたOpenGL 2.0+コードをお持ちの場合は、移植については一切話しません。

もう1つの不愉快な瞬間は、OpenGLとライブラリを50〜100%の互換性のレベルにする気分と欲求がないことです。つまり、特定のタスクのために自分でライブラリをシャープにする必要があります。 幸いなことに、すべてのコードはgithubに投稿されており、これまでのところ私はどこにも姿を消しておらず、コミットまたはこの負担を引き受けたい人さえ喜んでいます。 このライブラリはWindows 8.0およびWindows Phone 8.1で構築されています。VSIXの場合、Visual Studioの非Expressバージョンが必要になる場合があります。



エピローグ



最後に、ゲームについて少し説明します。 私はプロジェクトを100%完成させました。C#とOpenGLの組み合わせにより、高レベルのコードを完全に変更不可能にすることができました。これは、システムコールを使用しない単一の定義のないライブラリです。 次に、中間レベルのコードがあります:OpenGLを介して回転、変換、および色変調を使用して2Dで描画します。ここでは、プラットフォームによってコードがわずかに異なります-テクスチャ、データの保存方法が異なります。 低レベルの部分はプラットフォームごとに既に異なります。これはウィンドウの作成、コンテキストの初期化、サウンドの出力です。 いずれにせよ、記事の冒頭にリストされた9つのプラットフォームは実際に機能しますが、OpenGLと組み合わせたC#はWebやFirefox OSではまだ使用できませんが、クロスプラットフォームの未来を反映したものではありませんか?








All Articles