像CryEngine3,虚幻引擎3这样的Seriouse图形引擎有自定义的着色器语言和效果系统。在尝试为我的小图形框架找到一些效果系统时,看起来nvidia CgFx是唯一的选择(似乎Khronos有一个名为glFx的项目,但项目页面现在是404)。
我有几个理由来制作我自己的效果系统:
所以我想知道如何创建效果系统?我是否需要从头开始编写语法分析器,或者已经有一些代码/工具能够做到这一点?
PS:我在GLSL和CG上使用OpenGL。
答案 0 :(得分: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
// ...
};
根据相同的想法,您可以创建“动态着色器参数”类型。例如,如果您希望能够将灯光的参数绑定到着色器,请创建专用参数的类型。在它的构造函数中,传递light的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是要获取的参数。参数和实际值之间的绑定是在加载期间完成的,因此没有太多开销。
无论如何,如果这回答你的问题,我不会这样做,并且不要太认真地对待这些示例代码(HLSL和OpenGL着色器工作方式完全不同,我不是OpenGL专家^^)但希望它能给出你有几个线索:)
答案 1 :(得分:0)
你能详细说明一下吗?通过直接使用OpenGL,您可以完全控制传递给GPU的参数。你究竟错过了什么?
(和3.)GLSL 支持重用代码。您可以拥有一个提供不同功能的着色器库。为了使用任何函数,您只需在客户端着色器(vec4 get_diffuse();
)中预先声明它,并在链接之前将实现该函数的着色器对象附加到着色器程序。