2017-09-23 9 views
0

シェイダープログラムのクラスを設計しようとしています。 シェーダプログラムは、異なるタイプの複数のシェーダオブジェクトで構成されている場合があります。 すべてのコンビネーションで異なるコンターを作成したり、セッターを作成したり、この呼び出し元メンバー関数の後にプログラムを作成したりすることは望ましくありません。私は良い解決策を見つけようとするか、デザインパターンを使用しようとしますが、良いことは分かりません。 私は5種類のシェーダを持っており、常にシェーダプログラムに少なくとも2つ(常に頂点シェーダとフラグメントシェーダ)する必要があります。シェーダプログラムを作成するためだけにシェイダーが必要ですが、これ以降は必要ありません。パラメータの組み合わせでオブジェクトを作成する

オプション#1:

ShaderPogram(VertexShader vs, FragmentShader fs); 
ShaderPogram(VertexShader vs, GeometryShader geometry, FragmentShader fs); 

オプション#2:

struct Collection { 
VertexShader vs; GeometryShader gs; FragmentShader fs; 
}; 

ShaderProgram(Collection c); 

オプション#3:

class ShaderProgram { 
public: 
void SetVertexShader(VertexShader vs); 
void SetGeometryShader(GeometryShader gs); 
void SetFragmentShader(FramgentShader fs); 
}; 

たぶん誰かが他の解決策を提案することができますか?

答えて

0

オプション#2と#3はちょうど良いようです。オプション#3を除いて、頂点シェーダとフラグメントシェーダが常に必要とされているので、クラスには、これらの2つの型とセッタをオプションの型だけに使用するコンストラクタを与えます。

しかし、実際にクラスのユーザーにとってもっと簡単にするには、テンプレートの作業によっては1つのコンストラクタしか使用できず、有効なシェーダ引数のセットを任意の順序で渡すことができます以下のような:

#include <type_traits> 

namespace ShaderProgramDetail { 
    template <typename Type, typename... TypeList> struct type_in_list; 
    template <typename Type> 
    struct type_in_list<Type> 
     : public std::false_type {}; 
    template <typename Type, typename... Rest> 
    struct type_in_list<Type, Type, Rest...> 
     : public std::true_type {}; 
    template <typename Type, typename First, typename... Rest> 
    struct type_in_list<Type, First, Rest...> 
     : public std::integral_constant<bool, 
      type_in_list<Type, Rest...>::value> {}; 

    template <typename... Types> struct types_unique; 
    template <> 
    struct types_unique<> : public std::true_type {}; 
    template <typename Type1, typename... Rest> 
    struct types_unique<Type1, Rest...> 
     : public std::integral_constant<bool, 
      !type_in_list<Type1, Rest...>::value && 
      types_unique<Rest...>::value> {}; 

    template <bool... B> struct all_of; 
    template <> 
    struct all_of<> : public std::true_type {}; 
    template <bool... B> 
    struct all_of<false, B...> : public std::false_type {}; 
    template <bool... B> 
    struct all_of<true, B...> 
     : public std::integral_constant<bool, all_of<B...>::value> {}; 
} 

class ShaderProgram 
{ 
public: 
    template <typename... Shaders> 
    explicit ShaderProgram(Shaders&& ... shaders) { 
     using namespace ShaderProgramDetail; 
     static_assert(types_unique<std::decay_t<Shaders>...>::value, 
      "Cannot provide two shaders of the same type"); 
     static_assert(all_of<type_in_list<std::decay_t<Shaders>, 
      VertexShader, FragmentShader, GeometryShader> 
      ::value...>::value, 
      "Invalid argument type"); 
     static_assert(type_in_list<VertexShader, std::decay_t<Shaders>...>::value, 
      "Missing VertexShader argument"); 
     static_assert(type_in_list<FragmentShader, std::decay_t<Shaders>...>::value, 
      "Missing FragmentShader argument"); 
     using int_arr = int[]; 
     (void) int_arr{ (init_shader(std::forward<Shaders>(shaders)), 0)... }; 
    } 
private: 
    void init_shader(VertexShader vs) { vertex_shader = std::move(vs); } 
    void init_shader(FragmentShader fs) { fragment_shader = std::move(fs); } 
    void init_shader(GeometryShader gs) { geometry_shader = std::move(gs); } 

    VertexShader vertex_shader; 
    FragmentShader fragment_shader; 
    GeometryShader geometry_shader; 
}; 

私が検証するコンストラクタで4つのstatic_assertステートメントを使用しました注:

  • シェーダのいかなる種類は複数回渡されません。
  • すべての引数はサポートされているシェーダタイプです。 (おそらくそこで使用されている有効なタイプのリストを展開したいと思うでしょう)
  • 必要なタイプはVertexShaderです。
  • 必要なタイプはFragmentShaderです。

namespace ShaderProgramDetailのクラステンプレートはかなり一般的です。他の場所でそれらを再利用すると思われる場合は、それらを独自のヘッダーファイルに入れ、名前空間の名前をより適切な名前に変更することができます。

上記は有効なC++ 14コードです。あなたがCを使用している場合

template <typename T> 
using decay_t = typename std::decay_t<T>::type; 

++:

あなたがC++ 11で立ち往生している場合は、独自のdecay_ttypename std::decay<X>::typeとすべてのstd::decay_t<X>を交換するのいずれかの必要がある、または定義します17の場合はShaderProgramDetail::all_ofの代わりにstd::conjunctionを使用できます。コンストラクタの最後の2行をもっと簡単に書くことができます:

init_shader(std::forward<Shaders>(shaders)), ... ; 
関連する問題