Rad*_*094 37 opengl glsl rendering-engine
我正在使用GLSL着色器编写一个小型渲染引擎:
每个网格(井,子网格)都有一些顶点流(例如位置,法线,纹理,切线等)到一个大的VBO和一个MaterialID中.
每个材质都有一组纹理和属性(例如镜面反射颜色,漫反射颜色,颜色纹理,法线贴图等)
然后我有一个GLSL着色器,它的制服和属性.让我们说:
uniform vec3 DiffuseColor;
uniform sampler2D NormalMapTexture;
attribute vec3 Position;
attribute vec2 TexCoord;
Run Code Online (Sandbox Code Playgroud)
我试图为GLSL着色器设计一种方法来定义属性和制服的流映射(语义),然后将顶点流绑定到适当的属性.
对网格说法的内容:"将您的位置流放在属性"位置"中,将您的tex坐标放在"TexCoord"中.还将材质的漫反射颜色放在"DiffuseColor"中,将材质的第二个纹理放在"NormalMapTexture"中
目前我正在使用硬编码的名称作为属性(即顶点pos始终是"位置"等)并检查每个统一和属性名称以了解着色器使用它的内容.
我想我正在寻找一种创建"顶点声明"的方法,但也包括制服和纹理.
所以我只是想知道人们如何在大型渲染引擎中做到这一点.
编辑:
回顾建议的方法:
1.属性/统一语义由变量名称给出 (我现在正在做什么)为每个可能的属性使用预定义的名称.GLSL绑定器将查询每个属性的名称并基于该属性链接顶点数组.变量名称:
//global static variable
semantics (name,normalize,offset) = {"Position",false,0} {"Normal",true,1},{"TextureUV,false,2}
...when linking
for (int index=0;index<allAttribs;index++)
{
glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);
semantics[index]= GetSemanticsFromGlobalHardCodedList(name);
}
... when binding vertex arrays for render
for (int index=0;index<allAttribs;index++)
{
glVertexAttribPointer(index,size[index],type[index],semantics[index]->normalized,bufferStride,semantics[index]->offset);
}
Run Code Online (Sandbox Code Playgroud)
2.每个语义的预定义位置
GLSL绑定器将始终将顶点数组绑定到相同的位置.着色器可以使用相应的名称进行匹配.(这看起来非常类似于方法1,但除非我误解,否则这意味着绑定所有可用的顶点数据,即使着色器不使用它)
.. when linking the program...
glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");
Run Code Online (Sandbox Code Playgroud)
3.来自Material,Engine globals,Renderer和Mesh的可用属性的字典
维护活动材质,引擎全局,当前渲染器和当前场景节点发布的可用属性列表.
例如:
Material has (uniformName,value) = {"ambientColor", (1.0,1.0,1.0)}, {"diffuseColor",(0.2,0.2,0.2)}
Mesh has (attributeName,offset) = {"Position",0,},{"Normals",1},{"BumpBlendUV",2}
Run Code Online (Sandbox Code Playgroud)
然后在着色器中:
uniform vec3 ambientColor,diffuseColo;
attribute vec3 Position;
Run Code Online (Sandbox Code Playgroud)
将顶点数据绑定到着色器时,GLSL绑定器将遍历attrib并绑定到字典中找到的(或不是?):
for (int index=0;index<allAttribs;index++)
{
glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);
semantics[index] = Mesh->GetAttributeSemantics(name);
}
Run Code Online (Sandbox Code Playgroud)
和制服一样,只查询活动材料和全局变量.
kva*_*ark 16
属性:
您的网格有许多数据流.对于每个流,您可以保留以下信息:( 名称,类型,数据).
链接后,您可以在GLSL程序中查询活动属性并为该程序形成属性字典.这里的每个元素都是(名称,类型).
当您使用指定的GLSL程序绘制网格时,您将浏览程序属性字典并绑定相应的网格流(或在出现不一致时报告错误).
制服:
让着色器参数字典为(名称,类型,数据链接)的集合.通常,您可以使用以下词典:
链接之后,GLSL程序被赋予一组参数字典,以便使用以下元素格式填充它自己的字典:( 位置,类型,数据链接).通过查询活动制服列表和匹配(名称,类型)对与字典中的一对来完成此填充.
结论: 此方法允许传递任何自定义顶点属性和着色器制服,而不会在引擎中使用硬编码名称/语义.基本上只有loader和render知道特定的语义:
根据我的经验,OpenGL没有定义属性或制服语义的概念.
您所能做的就是定义您自己的语义映射到OpenGL变量的方法,使用您可以控制这些变量的唯一参数:它们的位置.
如果您不受平台问题的限制,您可以尝试使用"新" GL_ARB_explicit_attrib_location(OpenGL 3.3中的核心,如果我没有记错的话),它允许着色器明确表示哪个位置适用于哪个属性.这样,您可以硬编码(或配置)要绑定到哪个属性位置的数据,并在编译后查询着色器的位置.看来这个功能尚未成熟,可能会遇到各种驱动程序中的错误.
另一种方法是使用glBindAttribLocation绑定属性的位置.为此,您必须知道要绑定的属性的名称以及要为其分配的位置.
要找出着色器中使用的名称,您可以:
我不建议使用GLSL解析方式(尽管如果你的语境足够简单,它可能适合你的需要):解析器很容易被预处理器击败.假设您的着色器代码变得有些复杂,您可能想要开始使用#includes,#define,#ifdef等.强大的解析假设您有一个强大的预处理器,这可能会成为一个非常重要的设置.
无论如何,使用您的活动属性名称,您必须为它们分配位置(和/或语义),为此,您将独自使用您的用例.
在我们的引擎中,我们很乐意将预定义名称的位置硬编码为特定值,例如:
glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");
...
Run Code Online (Sandbox Code Playgroud)
在此之后,着色器编写器必须符合属性的预定义语义.
AFAIK是最常用的做事方式,例如OGRE使用它.这不是火箭科学,但在实践中运作良好.
如果你想添加一些控件,你可以提供一个API来在着色器的基础上定义语义,甚至可以将这个描述放在一个附加文件中,易于解析,生活在着色器源代码附近.
除了"更新"的扩展允许您强制GLSL统一块到与您的应用程序兼容的内存布局之外,我不会进入情况几乎相同的制服.
我自己并不满足于此,所以我很乐意有一些相互矛盾的信息:)