この原則に基づいて作成されたいくつかのプロジェクトをサポートし、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を使用したラッパーの例
このコードを自分でコピーする価値はないことに注意してください-GL_TEXTURE_WIDTH / GL_TEXTURE_HEIGHT定数がない場合は機能しません。 同時に、呼び出しの前にs_textureCropOesTiv変数を入力する必要があり、コード自体は縦座標に沿ってビューポートを反転しません。
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の変換コード
clipRect-トリミングパラメーター付きの長方形、上記の例のs_textureCropOesTivの類似物
texture-テクスチャ自体を含むBitmapSource
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を使用したバージョンはかなり疑わしく、元の計画にまったく対応していません
GL2DX
このライブラリは、数年前にCodePlexの平均的なユーザーによってアップロードされ、もはや更新されていません。 これは、OpenGLと同じ関数を宣言し、それらをD3D11呼び出しに内部的に変換するC ++ライブラリです。 ライブラリのC ++ / CXには、SwapChainBackgroundPanelを使用してXAMLページを作成し、D3D11CreateDeviceを通じて初期化してC ++パーツで動作する例がありました。 このプロジェクトは、少なくともプロトタイプの段階から少しでも外れていれば良いでしょう。 技術的には、OpenGLメソッドのほんの数パーセントしか機能せず、残りはアサーションです。 一方、2Dテクスチャ出力、変換、および単純なジオメトリを処理します。 この段階で、ライブラリを引き継ぎ、製品の状態にしました。これにより、Visual Studio拡張機能としてC#プロジェクトに接続し、同様のコードを記述できます。
コード
PSコードはOpenTK呼び出し形式であり、GL.Color4の代わりにglColor4fを書くことに慣れている人にとっては少し混乱します。
これらのことは私から誇らしげな名前MetroGLを受け取りました。
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を書くことに慣れている人にとっては少し混乱します。
メトログル
C ++ / CXの例は、同じ
もう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ではまだ使用できませんが、クロスプラットフォームの未来を反映したものではありませんか?