オブジェクト指向OpenGL


12

私はしばらくの間OpenGLを使用しており、多数のチュートリアルを読みました。それらの多くがまだ固定パイプラインを使用しているという事実は別として、彼らは通常、すべての初期化、状態変更、および描画を1つのソースファイルにスローします。これは限られた範囲のチュートリアルには適していますが、完全なゲームにスケールアップする方法を見つけるのに苦労しています。

OpenGLの使用をファイル間でどのように分割しますか?概念的には、たとえば、純粋に画面に素材をレンダリングするレンダリングクラスを持つことの利点を見ることができますが、シェーダーやライトのようなものはどのように機能しますか?ライトやシェーダーなどのクラスを個別に用意する必要がありますか?


1
オープンソースのゲームと、より多くのコードを含む大規模なチュートリアルがあります。それらのいくつかをチェックして、コードがどのように構成されているかを確認してください。
マイケルハウス

レンダリングエンジンに関しては、初心者ですか?
サマールサ

この質問は、範囲をある程度狭めることなく合理的に答えることはできません。何を構築しようとしていますか?どんな種類のゲーム、どんな種類のグラフィックスなどがありますか?
ニコルボーラス

1
@サリバン:「この種の概念はほとんどすべてのゲームに当てはまると思いました。」彼らはしません。Tetrisを作成するように依頼された場合、OpenGLの周りに大きなラッパーレイヤーや何かを作成することはありません。直接使用してください。Mass Effectのようなものを作成するように頼まれた場合、レンダリングシステムの周囲に複数の抽象化レイヤーが必要になります。テトリスでアンリアルエンジンを投げることは、ショットガンを使用してハエを狩ります。タスクを直接手作業でコーディングするよりもはるかに難しくなります。必要なだけシステムを構築する必要があり、それ以上は大きくありません。
ニコルボーラス

1
@サリバン:あなたの質問が示唆する唯一の複雑さは、複数のファイルに分割することについて話す場所です。それは私がテトリスでさえすることです。そして、テトリスとアンリアルエンジンの間には多くのレベルの複雑さがあります。繰り返しになりますが、どちらについて質問していますか?
ニコルボーラス

回答:


6

OO OpenGLはそれほど必要ではないと思います。シェーダー、モデルなどのクラスについて話すときは異なります。

基本的に、最初にゲーム/エンジンの初期化を行います(その他のこと)。次に、テクスチャ、モデル、およびシェーダーをRAM(必要な場合)およびバッファーオブジェクトにロードし、シェーダーをアップロード/コンパイルします。その後、データ構造またはシェーダーのクラス、モデルに、シェーダー、モデル、およびテクスチャバッファーオブジェクトのint IDがあります。

ほとんどのエンジンにはエンジンコンポーネントがあり、全員が特定のインターフェイスを持っていると思います。私が調べたすべてのエンジンには、RendererやSceneManager、またはその両方などのコンポーネントがあります(ゲーム/エンジンの複雑さに依存します)。あなたが持つことができるよりRendererインターフェースを実装するOpenGLRendererクラスおよび/またはDXRendererをます。その後、SceneManagerRendererを使用している場合、次のことを実行できます。

  • SceneManagerをトラバースし、レンダリングのために各オブジェクトをレンダラーに送信します
  • SceneManagerメソッドで大文字をカプセル化する
  • SceneManagerを送信するレンダラーにて処理する

レンダラーはおそらくオブジェクトの描画関数を呼び出し、それが構成されている各メッシュの描画関数を呼び出し、メッシュはテクスチャオブジェクトをバインドし、シェーダーをバインドし、OpenGL描画関数を呼び出してから、シェーダー、テクスチャ、オブジェクトデータバッファーオブジェクトを使用しません。

注:これは単なる例です。勉強する必要があります 。SceneManagerを詳細に調べ、ユースケースを分析して、最適な実装オプションを確認してください。

もちろん、MemoryManagerなどのエンジンの他のコンポーネントもあります。ResourceLoaderなど、ビデオとRAMの両方のメモリ使用量ため、必要に応じて特定のモデル/シェーダー/テクスチャをロード/アンロードできます。この概念には、メモリキャッシング、メモリマッピングなどが含まれます。各コンポーネントに関する詳細と概念は多数あります。

他のゲームエンジンの詳細な説明をご覧ください。多くのゲームエンジンがあり、それらのドキュメントはほとんど入手可能です。

しかし、はい、クラスは生活を楽にします。それらを完全に使用し、カプセル化、継承、インターフェイス、その他のクールなものについて覚えておく必要があります。


これは私が探していた答えです。しかし、「...テクスチャ、モデル、シェーダーをRAM(必要に応じて)およびバッファーオブジェクトにロードし、シェーダーをアップロード/コンパイル...」と言うと、元の質問に戻ります。オブジェクトを使用して、モデルやシェーダーなどをカプセル化する必要がありますか?
サリバン

オブジェクトはクラスのインスタンスであり、「完全に使用する必要があります」。
エディンm

申し訳ありませんが、「オブジェクトの使用方法」を尋ねるつもりでした。私の悪い。
サリバン

まあ、それはあなたのクラスのデザインに依存します。いくつかの基本的な例は、次のような直感的なものです。object3d(クラス)にはメッシュ(クラス)があります。各メッシュにはマテリアル(クラス)があります。各マテリアルには、テクスチャ(クラス、または単にid)とシェーダ(クラス)があります。ただし、各コンポーネントについて読むと、SceneManager、Renderer、MemoryManagerを作成する方法は異なりますが、等しいアプローチがあります(これらはすべて、単一クラスまたは複数クラス、継承など)。このトピック(ゲームエンジンアーキテクチャ)については何十冊もの本が書かれており、質問に詳細に答えるために書くことができます。
エディンm

これが私が得ようとしている最高の答えだと思います。ご協力ありがとうございます:)
サリバン

2

OpenGLには、すでにいくつかの「オブジェクト」の概念があります。

たとえば、IDを持つものはすべてオブジェクトとして通過できます(具体的には「オブジェクト」という名前のものもあります)。バッファ、テクスチャ、頂点バッファオブジェクト、頂点配列オブジェクト、フレームバッファオブジェクトなど。少しの作業で、クラスをクラスでラップできます。また、コンテキストが拡張機能をサポートしていない場合、古い非推奨のOpenGL関数にフォールバックする簡単な方法を提供します。たとえば、VertexBufferObjectはglBegin()、glVertex3f()などの使用にフォールバックできます。

従来のOpenGLの概念から離れるには、いくつかの方法があります。たとえば、バッファに関するメタデータをバッファオブジェクトに保存する場合などです。たとえば、バッファに頂点が格納されている場合。頂点の形式は何ですか(つまり、位置、法線、Texcoordsなど)。使用するプリミティブ(GL_TRIANGLES、GL_TRIANGLESTRIPなど)、サイズ情報(格納される浮動小数点数、それらが表す三角形の数など)。それらを配列の描画コマンドに簡単にプラグインできるようにするためです。

OGLplusをご覧になることをお勧めします。OpenGL用のC ++バインディングです。

またglxx、これは拡張機能のロード専用です。

OpenGL APIのラッピングに加えて、その上に少し高いレベルの1つのビルドを作成することを検討する必要があります。

たとえば、すべてのシェーダーを担当し、それらをロードして使用するマテリアルマネージャークラス。また、プロパティをそれらに転送する責任があります。そうすれば、次のように呼び出すことができます。materials.usePhong(); material.setTexture(sometexture); material.setColor()。これにより、共有ユニフォームバッファーオブジェクトなどの新しいものを使用して、シェーダーが1ブロックで使用するすべてのプロパティを含む1つの大きなバッファーを使用できますが、サポートされていない場合は、各シェーダープログラムへのアップロードにフォールバックできるため、柔軟性が向上します。1つの大きなモノリシックシェーダーを使用し、サポートされている場合は均一なルーチンを使用して異なるシェーダーモデル間で交換できます。また、多数の異なる小さなシェーダーを使用することもできます。

シェーダーコードを記述するためのGLSL仕様からの支出も確認できます。たとえば、#includeは非常に便利で、シェーダーの読み込みコードに非常に簡単に実装できます(ARB拡張機能もあります)。また、サポートされている拡張機能に基づいてコードをオンザフライで生成することもできます。たとえば、共有ユニフォームオブジェクトを使用するか、通常のユニフォームを使用するようにフォールバックします。

最後に、シーングラフ、特殊効果(ぼかし、グロー)などの処理、シャドウ、ライティングなどの複数のレンダリングパスを必要とする処理を行う、高レベルのレンダリングパイプラインAPIが必要になります。それに加えて、グラフィックスAPIとは関係なく、世界のオブジェクトのみを扱うゲームAPIです。


2
「OGLplusをご覧になることをお勧めします。これはOpenGLのC ++バインディングです。」私はそれに対してお勧めます。RAIIは大好きですが、ほとんどのOpenGLオブジェクトにはまったく不適切です。OpenGLオブジェクトは、グローバルコンストラクト(OpenGLコンテキスト)に関連付けられています。したがって、コンテキストを取得するまでこれらのC ++オブジェクトを作成することはできません。また、コンテキストが既に破棄されている場合、これらのオブジェクトを削除することはできません。また、グローバル状態を変更せずにオブジェクトを変更できるという錯覚を与えます。これは嘘です(EXT_DSAを使用している場合を除く)。
ニコルボーラス

@NicolBolas:コンテキストがあるかどうかを確認して、初期化するだけではできませんか?または、OpenGLコンテキストを必要とするオブジェクトの作成のみをマネージャーに許可しますか?---ところで、素晴らしいチュートリアルセット(プロファイル内のリンク)!OpenGL / Graphicsを検索するとき、どういうわけか私はそれらに出くわしませんでした。
サマウルサ

@サマールサ:何のために?OpenGLオブジェクトのマネージャーがいる場合は、...オブジェクトに自分で対処する必要はありません。マネージャーは彼らのためにそれを行うことができます。また、コンテキストが存在するときにのみ初期化する場合、適切に初期化されていないオブジェクトを使用しようとするとどうなりますか?コードベースに脆弱性が生じるだけです。また、グローバル状態に触れることなくこれらのオブジェクトを変更する機能について私が言ったことは何も変わりません。
ニコルボーラス

@NicolBolas:「コンテキストを取得するまで、これらのC ++オブジェクトを作成することはできません」...それは、裸のOpenGLコンストラクトを使用することとは異なりますか?私の目では、oglplus::Contextクラスはこの依存関係を非常に目に見えるようにします-それは問題でしょうか?新しいOpenGLユーザーが多くの問題を回避するのに役立つと思います。
xtofl

1

最新のOpenGLでは、異なるvaosおよびシェーダープログラムを使用して、レンダリングされたオブジェクトを互いにほぼ完全に分離できます。そして、1つのオブジェクトの実装でさえ、多くの抽象化レイヤーに分離できます。

たとえば、テレインを実装する場合は、そのコンストラクターがテレインの頂点とインデックスを作成し、それらを配列バッファーに設定するTerrainMeshを定義できます。属性位置を指定すると、データをシェーピングします。また、レンダリングの方法を知っている必要があり、レンダリングをセットアップするために行ったすべてのコンテキスト変更を元に戻すように注意する必要があります。このクラス自体は、レンダリングするシェーダープログラムについては何も知らず、シーン内の他のオブジェクトについても何も知らないはずです。このクラスの上に、シェーダーコードを認識するテレインを定義できます。その仕事は、シェーダーとTerrainMesh間の接続を作成することです。これは、属性と均一な位置を取得し、テクスチャをロードすることなどを意味するはずです。このクラスは、テレインの実装方法、使用するLoDアルゴリズムについては何も知らないようにする必要があり、テレインをシェーディングするだけです。この上で、振る舞いや衝突検出などの非OpenGL機能を定義できます。

要するに、OpenGLは低レベルで使用するように設計されていますが、抽象化の独立したレイヤーを構築することができます。これにより、Unrealゲームのサイズでアプリケーションにスケールアップできます。しかし、必要な/必要なレイヤーの数は、本当に必要なアプリケーションのサイズに依存します。

ただし、このサイズについて嘘をつかないでください。10kラインアプリケーションでUnityのオブジェクトモデルを模倣しようとしないでください。結果は完全な災害になります。必要に応じて、抽象化レイヤーの数を増やすだけで、レイヤーを徐々に構築します。


0

ioDoom3はおそらく優れた出発点です。というのも、Carmackに頼って優れたコーディング慣行に従うことができるからです。また、彼はDoom3でメガテクスチャリングを使用していないと思うので、レンダーパイプとしては比較的簡単です。


6
「素晴らしいコーディングプラクティスに従うためにCarmackに頼ることができるので」ああ、それは良いことです。Carmackは、優れたC ++コーディングプラクティスに従います。それは暴動です!ああ...あなたは冗談ではなかった。うーん...実際に彼のコードをたことがありますか?彼はCプログラマーであり、それが彼の考え方です。Cではこれで問題ありませんが、問題はC ++についてです
ニコルボーラス

私はCのバックグラウンドを持っているので、彼のコードは私にとって非常に理にかなっています。
クリスバーンズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.