3Dレンダリングコンポーネントの抽象化のレベルは正しいですか?


8

私はこの領域の周りにたくさんの質問を見てきましたが、この正確な質問ではないので、これが重複している場合はお詫びします。

小さな3Dゲームを作っています。正直なところ、それはほんの少しの趣味のプロジェクトであり、実際のゲームにはならない可能性があります。素敵なグラフィックデモを作成し、3DレンダリングとC ++デザインについて学びたいと思います。

私の意図は、レンダリングにdirect3d9を使用することです。これについては少し経験があり、私の要件を満たしているようです。ただし、プログラマーとして1つのことを学んだ場合、「このコンポーネントが別の実装に置き換えられる可能性があると考えられる理由はありますか」と答えます。答えが「はい」の場合、適切な抽象化とそのコンポーネントへのインターフェイスを設計する必要があります。 。そのため、d3d9を実装するつもりでも、d3d11、openglに実装できる3dインターフェイスを設計する必要があります...

私の質問は、これを行うのに最適なレベルは何ですか?作成して後で描画できるインターフェースだと思います

  • 頂点バッファーとインデックスバッファー
  • テクスチャー
  • 頂点とピクセルの「シェーダー」
  • 描画状態のいくつかの表現(ブレンドモードなど...)

言い換えれば、たとえばアニメーションモデルを描画するためのコードが、抽象頂点バッファーなどを取得するためにインターフェイスを使用するかなり低レベルのインターフェイスです。低すぎるので、必要なすべての機能を抽象化できないのではないかと心配しています。

別の方法は、インターフェイスがオブジェクト、アニメーション、風景などを描画し、各システムに実装できる、より高いレベルでこれを行うことです。これはもっと手間がかかっているように見えますが、私はもっと柔軟だと思います。

だから、それが私の質問です。描画システムを抽象化するとき、どのレベルのインターフェイスが最適ですか。


それはあなたの質問に完全に答えるわけではないかもしれませんが、OGREやIrrlichtのようなDirectX + OpenGLエンジンのソースを調べて、それらがどのようにそれを抽象化したかを確認することをお勧めします。
共産主義者ダック

回答:


8

この回答の長さについてお詫び申し上げます。

「このコンポーネントが別の実装に置き換えられる可能性があると考えられる理由はありますか」。答えが「はい」の場合、そのコンポーネントへの適切な抽象化とインターフェースを設計する必要があります。

「考えられる理由」というのは、あまりにも極端なスタンスです。ほとんどすべての関数を何らかの方法でパラメーター化でき、すべてのモジュールにいくつかの異なる戦略またはポリシーを与え、すべての定数を微調整しました。これらのそれぞれに追加の抽象化レベルを提供すると、すぐに利益が得られない2倍のコードが作成されてしまいます。その柔軟性が必要になった場合は、潜在的な利益にすぎません。

インターフェースを提供するルートをたどって、これらのそれぞれがいくつかの異なるオプションの1つのファサードになる可能性がある場合は、デフォルトを含むこれらの異なるオプションをどのように提供するか、そしていつそれを簡単にするかを決定する必要があります。元のオブジェクトと同じように、多くの場合、追加のレイヤー全体が上に配置されていました。これは、現実の多くの「エンタープライズ」ソフトウェアで不条理になる可能性があります(実際にそうです)。多くの場合、悲しいことに家に近づきすぎているこの風刺作品を読むことをお勧めします:フレームワークが嫌いな理由

これに対する最大の議論は複雑さです。2つの3DレンダリングAPIに等しく適用できる優れたインターフェースが存在し、誰かがこれをここで回答で説明できるという(おそらく正しくない)仮定を立てましょう。次に、このインターフェイスを操作します。これは、その多目的の性質により、DX9が使用しない要素を間違いなくカバーします。たとえば、OpenGLで利用可能だがDirectX 9では利用できないAPI拡張機能の多さです。コードの理解と維持を難しくし、学習プロセスを遅くする追加の複雑さ。SDLなどの既存のマルチプラットフォームライブラリを使用する場合は、1つのプラットフォームで何かを修正するためだけに存在する奇妙な関数や制限にいつまでも遭遇するため、それは十分に悪いことです。dインターフェースのその部分が存在する理由だけでなく、現在作成しようとしている部分とどのように相互作用するかどうかを知る必要もあります。例えば。コアレンダリングコードで必要なOpenGL拡張機能の側面をカプセル化する抽象オブジェクトを作成することになりますが、まだそれらを使用する方法はありません。

ただし、将来的には、DX9システムがどのように動作するかを熟知したら、OpenGLシステムの動作を調べることができます。次に、両方のパーツを機能させるために既存のシステムをどのように適合させる必要があるかを確認し、リファクタリングが正しいことを確認するための効果的な単体テストとして既存のDX9コードパスを手軽に利用できるようにします。

あなたは幸運なことに、エンジニアリングで知られている最も流動性があり順応性のある材料の1つであるソースコードをコンピューターデータとして保存して作業しています。その祝福を受け入れるには、必要なことがわかっているときに変更を加えることで、数か月前にそれらを行い、その間にまだ得ていない抽象化に書き込む必要があるために負担がかかるのではありません。


これは私が感じる方法ですが、同時に、共通のアドバイスとして、ゲームのプラットフォーム固有のコードを抽象化するのは簡単で、実行する必要があるということです...どうすればよいかわかりません。
宮坂玲

5

ただし、プログラマーとして1つのことを学んだ場合は、「このコンポーネントが別の実装に置き換えられる可能性があると考えられる理由はありますか」と答え、答えが「はい」の場合、そのコンポーネントへの適切な抽象化とインターフェイスを設計する必要があります。 。

これは本当にあなたの質問に答えるものではありませんが、プログラマーとしての私の経験から、時期尚早な一般化は時期尚早な最適化と同じくらい悪いです。あなたはめったに何も得ず、プロジェクトの過程でそれを維持する必要があります。

私のアドバイスは、プロジェクトでD3D9クライアントコードをまっすぐに使用し、インターフェイスを切り替える必要があると判断した場合は、現在使用しているすべてのものとのインターフェイスを作成することです。プログラマーは何が必要になるかを予測するのにひどいです。あなたが資料にあまり精通していない場合には、二重にそうなるので、この方法であなたは最小限の仕事をしています。

参照:http : //c2.com/xp/YouArentGonnaNeedIt.html


これに関する問題は、後で抽象化を行わなければならない場合、すべてのインターフェースコードを書き直さなければならないことです。また、D3D9が彼のプロジェクト全体にグローバルに含まれていた場合、そのすべてのコードをリファクタリングするのは非常に困難です。
DeadMG

1
とはいえ、とにかく今やっていることを前提にしていないユースケースがあるときは、とにかくすべてを書き直さなければならないでしょう。特に学習プロジェクトでは、リファクタリングを採用する必要があります。
テトラッド、2011年

私は事件を少し詳しく調べています。私も不必要な抽象化を嫌っています。しかし、この場合、実際には別の実装でこれを実行する可能性が高いと言えます...
JohnB

4

回答へのコメントを投稿するのに十分な評判がないようです。

KylotanとTetradの両方が素晴らしい答えを出しました。追加するのは、レンダリングコードをゲームロジックから分離することを提案することです。

  • あなたのコードはよりきれいになります
  • ゲームロジックの半分を毎回書き直すことなく、レンダラーを変更する方が簡単です。
  • 最終的には、完全に異なるレンダリングモジュールを提供する方がこの方法の方が簡単です

追加のボーナスとして、この方法では、プロジェクトで作業するときに徐々に抽象化を構築します。あなたが言うように、これは学習プロジェクトなので、簡単にしてシンプルにし、複雑さや抽象化を追加していきます。最初は正しい計画を立てるのに専門知識が足りないため(おそらくTetradも示唆しています)、計画を立てる必要はありません。


確かに!しかし、問題は、それをどのレベルに分けるかです。街全体を描くレベルで、それとも三角形を描くレベルで?または、その中間
JohnB

合理的な方法は、レンダリングAPI呼び出しを個別に保つことです。それはおそらくあなたの類推で「建物や車を描く」ことになるでしょう(あなたの建物と車は単一のオブジェクトであると考えると:))。例:オブジェクトをアニメーション化したい場合(簡単にするために、一度に1つしか再生できないと仮定しましょう)。ゲームオブジェクトは、使用可能なシーケンスとその長さのリストを持ち、レンダラーがレンダリングパーツを適切に管理しながら、アクティブなアニメーションとその速度を設定できます。レンダラーからデータを取得する必要がある場合もあります。たとえば、オブジェクトの衝突形状がアニメーション中に変化する場合があります。
ギレアデ

1

シェーダーの詳細はD3D9、11、OGLなどの間で完全に異なるため、この種のものについて低レベルの抽象化を書くことはできません。それは単に不可能です。

抽象化をレンダリングするために他の人が何をしたかを知りたい場合は、SFML、SDL、OGREなどで実装された抽象化をチェックすることができます。


シェーダーが抽象化の一部でない限り。
user253751 2015

1

D3DとOGLの両方を適切にラップするAPIを作成しようとしました。それは大きな仕事だと私は学びました。それらの違いの多くは調整できます。たとえば、シェーダーの読み込み。D3DおよびOGLシェーダーコードを自分の形式で効果的にカプセル化します。IE:D3Dでは、シェーダープロファイルを指定する必要があるため、ファイル自体にシェーダープロファイルが書き込まれます。カプセル化されたシェーダーソースがAPIに渡されると、適切なシェーダープロファイルなどを使用して、適切なD3Dシェーダー作成メソッドが呼び出されます。

ただし、まだ解決していない相違点はたくさんあります。私が解決できなかった違いはまだたくさんあります。私は、より高いレベルの抽象化が設計しやすく、私の要件を満足できると判断したためです。私は現在、D3DXEffectフレームワークに似たものに取り組んでいます。オブジェクトにはレンダーテクニックがあり、これにはレンダーパスが含まれ、レンダーステートのセットとシェーダーのセットがあり、特定の入力が必要です。これにより、より多くのAPIを抽象化できます。


1

このような質問がポップアップしたときに、なぜ人々が自動的に時期尚早な一般化/最適化にジャンプするのか、私にはわかりません。システムのコンポーネントがスワップアウトされる可能性が高いときに、プリエンプティブであり、それを実現することについて、言うべきことがあります。「変更する必要があるまで、コードを心配する必要はありません」に関するすべての回答は、実際には大きな変更をもたらすため、または異なる設計のコードを残してしまうため、一般に現実世界で問題を抱えます。で始まりますが、「機能する」ために残されました。事前に考えて、考えすぎずにどこでやめるべきかを知ること自体がスキルです。

完全に新しい実装(DXなど)をOGLで動作するように厳密にコード化されたシステムに導入するよりも、DX / OGL間の違いに対応するためにインターフェースをリファクタリングする方がはるかに簡単です。どこにでもグラフィックコードとゲームロジックコードを混ぜたり、コードを繰り返したりしたくないので、コードの抽象化はとにかくあるレベルで行われるべきです。私がゲームに取り組んでいてOpenGLで始めた場合(経験があるため)が、最終的にXbox / Windows(DX)でゲームを入手したい場合も、私にとってはばかげているでしょう。グラフィックAPIを設計するときは、それを考慮に入れません。ゲームのように複雑なものをリファクタリングし、新しいグラフィックAPIを導入するというアイデアは、面倒でエラーが発生しやすいものです。

APIをどのように使用するかを検討し、ゲームの開発プロセス中にニーズ/知識が変化するにつれて、APIを構築する必要があります。低レベルのOGL / DXを抽象化するのではなく、ジオメトリのロード、シェーダーのロード/コンパイル、テクスチャのロードなどを支援するAPIを自分で作成します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.