【问题标题】:How to create a CgFx like effect system?如何创建类似 CgFx 的效果系统?
【发布时间】:2011-10-18 03:06:32
【问题描述】:

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

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

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

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

PS:我在 GLSL 和 CG 中都使用 OpenGL。

【问题讨论】:

    标签: opengl glsl shader game-engine cg


    【解决方案1】:

    在我使用 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 专家 ^^)但希望它会给你有几个线索:)

    【讨论】:

    • 感谢您的建议。你的实现(XML 方式)看起来很像 CryEngine 人构建他们的材料系统的方式。
    【解决方案2】:
    1. 您能详细说明一下吗?通过直接使用 OpenGL,您可以完全控制传递给 GPU 的参数。你到底错过了什么?

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

    【讨论】:

    猜你喜欢
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多