1

像 CryEngine3、Unreal Engine 3 这样的 Seriouse 图形引擎都有自己定制的着色器语言和效果系统。在尝试为我的小型图形框架寻找一些效果系统时,看起来 nvidia CgFx 是唯一的选择(似乎 Khronos 有一个名为 glFx 的项目,但项目页面现在是 404)。

我有几个理由制作自己的效果系统:

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

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

PS:我同时使用 OpenGL 和 GLSL 和 CG。

4

2 回答 2

4

回到我使用 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 专家 ^^)但希望它能给你一些导致:)

于 2011-10-18T14:18:55.587 回答
0
  1. 你能详细说明一下吗?通过直接使用 OpenGL,您可以完全控制传递给 GPU 的参数。你到底错过了什么?

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

于 2011-10-18T21:21:07.670 回答