首页 > 解决方案 > 解耦自定义用户数据

问题描述

我有一个自定义着色器生成:

class My_UniformInt { public:
    std::string idName;
    int glsl_id;  //<-- userData-like field
};
class My_Shader{ public:
    My_UniformInt textureCoordinate;
    public: My_Shader(){
        textureCoordinate.idName="textureCoordinate";
    }
};
void registerUniform( My_Shader& shader, My_UniformInt & uniInt){
    uniInt.glsl_id=5; 
    //vec3.glsl_id=glGetUniformLocation(uniInt.idName);
}
void passUniformInt( My_Shader& shader, My_UniformInt & uniInt,int k){
    std::cout<<"successfully pass name="<<uniInt.idName<<" va="<<k<<std::endl;
    //glUniform1i(uniInt.glsl_id,k);
}

我可以生成着色器并像这样使用它:

int main(){
    My_Shader shader;
    registerUniform( shader , shader.textureCoordinate ) ;
    //.. several frame later
    passUniformInt( shader , shader.textureCoordinate ,  5 ) ;
    return 0;
}

它工作且快速(MCVE),但存在不合需要的耦合。
1.My_UniformInt缓存 glsl 特定的变量 ( glsl_id)。
2.My_UniformInt也有感情上的glGetUniformLocation

如何在My_UniformInt不牺牲速度的情况下更独立?

我有几个有类似问题的案例。不幸的是,最明显的选择通常似乎是添加更多类似 userData 的字段。它增加了耦合。

我糟糕的解决方案:

  1. make glsl_idas void* userData,然后 assignuserData=new int()
    很不酷 + 有一点成本 + 需要稍后删除。

  2. 创建地图std::map<My_UniformInt*,int glsl_id>。不过我负担不起费用。

标签: c++design-patternsshaderdecoupling

解决方案


这是我的评论作为答案:

我认为您应该尝试将使用 API 的代码包装在其自己的空间中,以便以后可以轻松交换 - 创建一个为您执行 API 访问的类,如果您想切换后端,只需调整该类。以不使用任何 API 特定代码或变量的方式构建其余代码,而是使用您的包装器与之交互。

我认为这通常是处理任何类型的库或任何东西的好方法。它允许您通过不依赖于它们提供的任何类型的界面,而仅依赖于您自己的界面来快速适应其中的变化。挑战在于以提供良好抽象的方式编写包装器,因此您可以理想地使用另一个使用完全不同接口的后端,但尽量保持原生以确保低开销。


推荐阅读