回到我使用 HLSL 的那一天,我开发了一个小着色器系统,它允许我通过数据指定所有参数,这样我就可以编辑一种包含参数列表和着色器代码的 XML 文件,然后保存,引擎会自动重新加载它,重新绑定所有参数等。
与 UDK 中的内容相比,这没什么,但非常方便,我猜您正在尝试实现类似的东西?
我是,那么这里有一些事情要做。首先,您需要创建一个类来抽象着色器参数处理(绑定、设置等)。沿着这些思路:
class IShaderParameter
{
protected:
IShaderParameter(const std::string & name)
: m_Uniform(-1)
, m_Name(name)
{}
GLuint m_Uniform;
std::string m_Name;
public:
virtual void Set(GLuint program) = 0;
};
然后,对于静态参数,您可以像这样简单地创建一个重载:
template < typename Type >
class StaticParameter
: public IShaderParameter
{
public:
StaticParameter(const std::string & name, const Type & value)
: IShaderParameter(name)
, m_Value(value)
{}
virtual void Set(GLuint program)
{
if (m_Uniform == -1)
m_Uniform = glGetUniformLocation(program, m_Name.c_str());
this->SetUniform(m_Value);
}
protected:
Type m_Value;
void SetUniform(float value) { glUniform1f(m_Uniform, value); }
// write all SetUniform specializations that you need here
// ...
};
并且按照同样的想法,您可以创建“动态着色器参数”类型。例如,如果您希望能够将灯光的参数绑定到着色器,请创建一个专门的参数类型。在其构造函数中,传递灯光的 id,以便它知道如何在 Set 方法中检索灯光。通过一些工作,您可以拥有一大堆参数,然后您可以自动绑定到引擎的实体(材质参数、灯光参数等)
最后要做的是创建一个小的自定义文件格式(我使用 xml)来定义你的各种参数和一个加载器。例如,就我而言,它看起来像这样:
<shader>
<param type="vec3" name="lightPos">light_0_position</param>
<param type="vec4" name="diffuse">material_10_diffuse</param>
<vertexShader>
... a CDATA containing your shader code
</vertexShader>
</shader>
在我的引擎中,“light_0_position”表示灯光参数,0 是灯光的 ID,位置是要获取的参数。参数和实际值之间的绑定是在加载期间完成的,因此没有太多开销。
无论如何,我不会回答你的问题,也不要太认真地对待这些示例代码(HLSL 和 OpenGL 着色器的工作方式完全不同,我不是 OpenGL 专家 ^^)但希望它能给你一些导致:)