如何创建类似CgFx的效果系统



严肃的图形引擎,如CryEngine3,虚幻引擎3有他们自定义的着色器语言和效果系统。当我试图为我的小图形框架找到一些效果系统时,看起来nvidia CgFx是唯一的选择(似乎Khronos有一个名为glFx的项目,但项目页面现在是404)。

我有几个理由来建立我自己的效果系统:

  1. 我需要更多的控制如何以及何时传递着色器参数。
  2. 为了重用着色器片段,我想创建一些c++宏机制。使用宏来做一些条件编译也是很有用的,这也是CryEngine用来产生各种效果的方式。
  3. 看起来GLSL没有这样的效果系统

所以我想知道如何创建一个效果系统?我是否需要从头开始编写语法解析器,或者已经有一些代码/工具能够做到这一点?

PS:我使用OpenGL与GLSL和CG。

在我使用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, position是要获取的参数。参数和实际值之间的绑定是在加载期间完成的,因此没有太多的开销。

无论如何,如果我不回答你的问题,不要把这些示例代码太当回事(hsl和OpenGL着色器的工作方式完全不同,我不是OpenGL专家^^),但希望它能给你一些线索:)

  1. 你能详细说明一下吗?通过直接使用OpenGL,你可以完全控制传递给GPU的参数。你到底错过了什么?

  2. (3)。GLSL 支持重用代码。你可以有一个着色器库来提供不同的功能。为了使用任何函数,你只需要在客户端着色器(vec4 get_diffuse();)中预先声明它,并在链接之前将实现该函数的着色器对象附加到着色器程序中。

相关内容

  • 没有找到相关文章

最新更新