最も実用的なアプローチは、直接適用できない (遅い、ハードウェア アクセラレーションがない、またはハードウェアに適合しなくなった) OpenGL 機能のほとんどを無視することです。
OOP であろうとなかろうと、いくつかのシーンをレンダリングするために、それらは通常持っているさまざまなタイプとエンティティです。
ジオメトリ(メッシュ)。ほとんどの場合、これは頂点の配列とインデックスの配列です (つまり、三角形ごとに 3 つのインデックス、別名「三角形リスト」)。頂点は、任意の形式にすることができます (たとえば、float3 位置のみ、float3 位置 + float3 法線、float3 位置 + float3 法線 + float2 texcoord など)。したがって、必要なジオメトリの一部を定義するには:
- その頂点フォーマットを定義します (ビットマスク、フォーマットのリストからの列挙型の可能性があります; ...)、
- コンポーネントがインターリーブされた頂点の配列を持つ (「インターリーブ配列」)
- 三角形の配列があります。
OOP ランドにいる場合は、このクラスをMeshと呼ぶことができます。
マテリアル- ジオメトリの一部がどのようにレンダリングされるかを定義するもの。最も単純なケースでは、これはオブジェクトの色などです。または、ライティングを適用するかどうか。または、オブジェクトをアルファ ブレンドするかどうか。または、使用するテクスチャ (またはテクスチャのリスト)。または使用する頂点/フラグメント シェーダー。など、可能性は無限大です。必要なものを材料に入れることから始めます。OOP ランドでは、そのクラスを (驚き!) Materialと呼ぶことができます。
シーン- ジオメトリの断片、マテリアルのコレクション、シーンの内容を定義する時間があります。単純なケースでは、シーン内の各オブジェクトは次のように定義できます。 - 使用するジオメトリ (メッシュへのポインタ) - レンダリング方法 (マテリアルへのポインタ) - 配置場所。これは、4x4 変換行列、または 4x3 変換行列、またはベクトル (位置)、クォータニオン (方向)、および別のベクトル (スケール) である可能性があります。これを OOP ランドのノードと呼びましょう。
カメラ。カメラは、「配置された場所」(ここでも 4x4 または 4x3 マトリックス、または位置と向き) にいくつかの投影パラメータ (視野、縦横比など) を加えたものにすぎません。
基本的にはそれだけです!メッシュとマテリアルを参照する一連のノードであるシーンがあり、ビューアがどこにあるかを定義するカメラがあります。
さて、実際の OpenGL 呼び出しをどこに配置するかは、設計上の問題にすぎません。私は、OpenGL の呼び出しを Node、Mesh、または Material クラスに入れないでください。代わりに、シーンを横断してすべての呼び出しを発行できるOpenGLRendererのようなものを作成します。または、さらに良いことに、OpenGL とは無関係にシーンを横断するものを作成し、OpenGL 依存クラスに低レベルの呼び出しを配置します。
そうです、上記のすべてはほとんどプラットフォームに依存しません。このように進むと、glRotate、glTranslate、gluLookAt などはまったく役に立たないことがわかります。すべての行列が既にあるので、それらを OpenGL に渡すだけです。とにかく、これは実際のゲーム/アプリケーションの実際のコードのほとんどがどのように機能するかです。
もちろん、上記はより複雑な要件によって複雑になる可能性があります。特に、マテリアルは非常に複雑になる場合があります。メッシュは通常、多くの異なる頂点フォーマットをサポートする必要があります (効率のためにパックされた法線など)。シーン ノードを階層に編成する必要がある場合があります (これは簡単です。ノードに親/子ポインターを追加するだけです)。一般に、スキン メッシュとアニメーションは複雑さを増します。等々。
しかし、主なアイデアは単純です。ジオメトリがあり、マテリアルがあり、シーンにオブジェクトがあります。次に、いくつかの小さなコードでそれらをレンダリングできます。
OpenGL の場合、メッシュを設定すると、VBO オブジェクトが作成/アクティブ化/変更される可能性が高くなります。ノードをレンダリングする前に、行列を設定する必要があります。また、マテリアルの設定は、残りの OpenGL 状態 (ブレンド、テクスチャリング、ライティング、コンバイナー、シェーダーなど) のほとんどに影響します。