我正在关注一个OpenGL教程,在我现在的位置,它会教你编写一个Shader类。但是,有一些我不喜欢的东西,即允许你设置统一值的函数。本教程提供以下内容:
void Shader::setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
当我看到这个时,我的第一次尝试是:“必须做得更好,我认为模板可以帮助我”。所以我开始研究它,直到我有以下Shader类:
class Shader
{
public:
Shader();
Shader(std::string const& vertex_path, std::string const& fragment_path);
//Activates the shader
void use();
using size_type = unsigned int;
//Uniform utility functions
template<typename T>
void setUniform(std::string const& name, T const& v0) const
{
using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (Traits::IsValidType<RemovedRefCV> >())
{
auto location = glGetUniformLocation(name);
if constexpr(std::is_same_v<RemovedRefCV, int>)
{
glUniform1i(location, v0);
}
else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
{
glUniform1ui(location, v0);
}
else if constexpr (std::is_same_v<RemovedRefCV, float>)
{
glUniform1f(location, v0);
}
}
else
{
static_assert(false, "Shader::set<std::string const& name, T v0>: Type T must be int, unsigned int or float");
}
}
template<typename T>
void setUniform(std::string const& name, T const& v0, T const& v1) const
{
using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (Traits::IsValidType<RemovedRefCV> > ())
{
auto location = glGetUniformLocation(name);
if constexpr(std::is_same_v<RemovedRefCV, int>)
{
glUniform2i(location, v0, v1);
}
else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
{
glUniform2ui(location, v0, v1);
}
else if constexpr (std::is_same_v<RemovedRefCV, float>)
{
glUniform2f(location, v0, v1);
}
}
else
{
static_assert(false, "Shader::set<std::string const& name, T v0, T v1>: Type T must be int, unsigned int or float");
}
}
template<typename T>
void setUniform(std::string const& name, T const& v0, T const& v1, T const& v2) const
{
using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (Traits::IsValidType<RemovedRefCV> > ())
{
auto location = glGetUniformLocation(name);
if constexpr(std::is_same_v<RemovedRefCV, int>)
{
glUniform3i(location, v0, v1, v2);
}
else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
{
glUniform3ui(location, v0, v1, v2);
}
else if constexpr (std::is_same_v<RemovedRefCV, float>)
{
glUniform3f(location, v0, v1, v2);
}
}
else
{
static_assert(false, "Shader::set<std::string const& name, T v0, T v1, T v2>: Type T must be int, unsigned int or float");
}
}
template<typename T>
void setUniform(std::string const& name, T const& v0, T const& v1, T const& v2, T const& v3) const
{
using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (Traits::IsValidType<RemovedRefCV> > ())
{
auto location = glGetUniformLocation(name);
if constexpr(std::is_same_v<RemovedRefCV, int>)
{
glUniform4i(location, v0, v1, v2, v3);
}
else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
{
glUniform4ui(location, v0, v1, v2, v3);
}
else if constexpr (std::is_same_v<RemovedRefCV, float>)
{
glUniform4f(location, v0, v1, v2, v3);
}
}
else
{
static_assert(false, "Shader::set<std::string const& name, T v0, T v1, T v2, T v3>: Type T must be int, unsigned int or float");
}
}
template<typename T>
void setUniform(std::string const& name, size_type count, const T* v) const
{
}
private:
GLuint ID;
bool loaded;
class Traits
{
private:
template<typename T, typename = std::void_t<>>
struct IsValidTypeHelper : std::false_type
{
};
template<typename T>
struct IsValidTypeHelper<T, std::enable_if_t<std::is_same_v<decltype(T), float> ||
std::is_same_v<decltype(T), int> ||
std::is_same_v<decltype(T), unsigned int>
>
>
: std::true_type {};
template<typename T>
struct IsValidTypeT : IsValidTypeHelper<T>::type {};
public:
template<typename T> using IsValidType = typename IsValidTypeT<T>::type;
};
};
正如您所看到的,我已经为向量创建了一个重载,但我不确定如何实现它,因为我想尝试使用我的Shader :: setUniform()替换尽可能多的glUniform***()
调用功能尽可能。我查看过this个问题,但它没有完全解决我正在寻找的问题。