私はC++でアニメーションライブラリを構築しています。図書館には、場面のモデリングとレンダリングのためのシステムが含まれています。システムの要件はのモデリングとレンダリングのC++でカプセル化されているが拡張可能なアニメーションライブラリを構築する
- 分離されています。シーンの状態に関する情報は、シーンをレンダリングする手順とは別に保存する必要があります。
- 拡張可能なモデリングとレンダリング。ライブラリ自体に
node
クラスが定義されている場合、ライブラリのユーザはnode
の機能を拡張する新しいタイプcustom_node
を定義できなければなりません(おそらく継承を通じて、しかし他の手段を介して)。ユーザーはcustom_node
をレンダリングするためのカスタムプロシージャーを指定できるはずです。そうすることで、ユーザーは何とかライブラリーに既に存在するレンダリング手順を利用できるはずです。ユーザは、ライブラリノードをレンダリングするための新しいプロシージャを定義することもできるはずです。 追加:ユーザーは、全体のレンダリングシステムを定義し、シーンをレンダリングするために使用するレンダリングシステムを選択できる必要があります。たとえば、ライブラリにフォトリアリスティックレンダリングシステムが含まれているとしますが、ユーザはベアボーンの概略レンダリングシステムでシーンをレンダリングする必要があるとします。ユーザは、アニメーションライブラリがアニメーションループ(フレームのレンダリング、シーンの更新、次のフレームのレンダリングなど)中にフードの下でアニメーションライブラリが使用する共通のレンダリングインターフェイスを使用して、そのようなレンダラを実装できる必要があります。 - ライブラリーのカプセル化。ライブラリの機能をカスタム
node
に拡張してレンダリングするには、ライブラリの基礎となるコードを編集する必要はありません。
失敗したアプローチ:シーンのモデルとしてnode
のツリーを使用します。サブクラスnode
を使用して新しいノードタイプを作成します。実行時まではノードの子の型が分からないため、ノードの子はvector<std::shared_ptr<node>>
に格納されます。 トップレベルrenderer
クラスを定義し、特定の種類のレンダリングを提供するサブクラスrenderer
も定義します。
class image;
class node {
virtual image render(renderer &r) {return r.render(*this);}
std::vector<std::shared_ptr<node>> children;
std::weak_ptr<node> parent;
// ...
}
class renderer {
image render(node &n) {/*rendering code */}
// ...
}
シーンをレンダリングするには、レンダラを定義
renderer r{};
やお気に入りのトラバーサル方法でノードのツリーをトラバース。あなたは、各std::shared_ptr<node>
n
が発生したとして、このアプローチは、モデリングとレンダリングを分離
n->render(r);
呼び出して、それが拡張することができます。我々はcustom_node
をレンダリングするカスタム手段を提供しようとするまでcustom_node
を作成するには、図書館の利用者は、単にnode
class custom_node : public node {
virtual image render(renderer &r) override {return r.render(*this)}
}
をサブクラスこのアプローチは、正常に動作します。それ自体で、これは動作しません
class custom_renderer : public renderer {
image render(custom_node &n) {/*custom rendering code*/}
}
:そうするために、我々は、サブクラス化renderer
とrender
方法をオーバーロードしてみてください。考えてみましょう:
renderer &r = custom_renderer{};
std::shared_ptr<node> n = std::make_shared<custom_node>{};
n->render(r); // calls renderer::render(node &)
をcustom_renderer ::レンダリング(custom_node & n)は、必要に応じて、我々は、元のレンダラークラスに仮想過負荷を追加する必要が呼び出すために:
class renderer {
image render(node &n) {/*rendering code */}
virtual image render(custom_node &n) = 0;
}
残念ながら、この破棄をライブラリクラスの1つを編集したので、ライブラリのカプセル化。
どのようにすれば、3つの要件すべてを満たすシステムを設計できますか?
この方法でカスタムレンダリングを処理するにはどうすればよいですか?標準レンダリングシステムと大胆なレンダリングシステムがあるとします。私たちは次のようなものを望んでいます: render(standard、printing_node {{"hello"}}); // "hello"を印刷します レンダリング(太字、print_node {{"hello"}}); // "HELLO"を印刷 カスタムの大文字のコードはどこに行きますか? – Chad