我有一个工具,允许用户编辑glsl的统一变量值,我需要将所有数据存储在std :: vector中。
由于所有变量的值都有不同的变量类型(vec2,vec3,vec4,mat2等),因此将它们存储在单个容器中是一个挑战。我决定采用这种方法
class BaseData
{
public:
};
template <typename T>
class Data: public BaseData
{
public:
Data(TypeEnum enumType, T valueIN): value(valueIN), type(enumType)
{
}
T GetValue()
{
return value;
}
TypeEnum GetType()
{
return type;
}
private:
T value;
TypeEnum type;
};
class Material
{
Material(std::vector<Base*> valueVec)
{
for(auto i : valueVec)
{
switch(i->GetType())
{
case BaseColor:
SetBaseColor(i->GetValue());//need something like this
break;
case BaseTexture:
SetBaseTexture(i->GetValue());//need something like this
break;
case EmissionColor:
SetEmissionFactor(i->GetValue());//need something like this
break;
case EmissionTexture:
SetEmissionTexture(i->GetValue());//need something like this
break;
case Material_nProps_NormalTexture:
SetNormalMap(i->GetValue());//need something like this
}
}
}
}
int main()
{
std::vector<BaseData*> uniformValue;
uniformValue.push_back(new Data(BaseColor, glm::vec4(1,2,3,4)));
uniformValue.push_back(new Data(BaseTexture, 0));
uniformValue.push_back(new Data(EmissionColor, glm::vec3(1,1,1)));
uniformValue.push_back(new Data(BaseTexture, 1));
Material PBR(uniformValue);
}
但是问题出在哪里,现在如何从基本指针获取 value 而不将其转换为正确的派生类型指针?
答案 0 :(得分:0)
正如评论中已经提到的那样,如果不使用std::variant
或等效的boost
类,就不可能实现所需的设计。关键是,虚拟机制允许在编译时决定要调用哪个成员函数,而在运行时不能决定变量的类型。因此,无论类型i->getValue()
返回什么,您都不能在运行时决定将结果存储在变量的类型。如果您决定将Derive<T>::getValue
设计为void Derive<T>::getValue(T& x) { x = value; }
,也会发生同样的情况:在循环内,您将无法声明局部变量x
传递给getValue
。
考虑到这些,请参见讨论Can objects be created based on type_info?
作为一般建议:您应尝试尽可能在Derive
内插入要执行的任务,并在Base
中仅提供抽象接口。
答案 1 :(得分:0)
如果不想进行强制转换,则可以使用命令模式,其中每个GLSL属性类都将收到一个指向Material对象的指针并执行适当的操作。每个命令都需要访问Material的某些内部组件。下面的代码说明了这一点。 (请注意,为简单起见,所有内容都是公开的。)
struct Material; // forward declaration
struct GlslPropertyBase {
virtual ~GlslPropertyBase() {}
virtual void Execute(Material* m) = 0;
};
struct Material {
void SetBaseColor(Vec3 col) { /* Do something */ }
void SetBaseTexture(GLuint uid) { /* Do something */ }
Material(std::vector<GlslPropertyBase*> properties) {
for (GlslPropertyBase* property : properties)
property->Execute(this);
}
};
struct GlSlBaseColor : GlslPropertyBase {
Vec3 color;
GlSlBaseColor(float r, float g, float b) : color(r, g, b) {}
void Execute(Material* m) { m->SetBaseColor(color); }
};
struct GlSlBaseTexture : GlslPropertyBase {
GLuint uid;
GlSlBaseTexture(GLuint uid) : uid(uid) {}
void Execute(Material* m) { m->SetBaseTexture(uid); }
};
int main() {
std::vector<GlslPropertyBase*> properties;
properties.push_back(new GlSlBaseColor(1, 2, 3));
properties.push_back(new GlSlBaseTexture(1));
Material PBR(properties);
// delete heap objects...
}
这只是一种简单的方法(和实现),可以处理存储在单个向量中的异构glsl属性,而无需强制转换,而且可能是{francesco在his answer结尾处建议的内容。