GLSL中的顶点着色器属性映射

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程序绘制网格时,您将浏览程序属性字典并绑定相应的网格流(或在出现不一致时报告错误).

制服:

让着色器参数字典为(名称,类型,数据链接)的集合.通常,您可以使用以下词典:

  • 材料(漫射,镜面,光泽等) - 取自材料
  • 引擎(相机,型号,灯光,计时器等) - 取自发动机单件(全球)
  • 渲染(与着色器创建者相关的自定义参数:SSAO半径,模糊量等) - 由着色器创建者类(渲染)专门提供

链接之后,GLSL程序被赋予一组参数字典,以便使用以下元素格式填充它自己的字典:( 位置,类型,数据链接).通过查询活动制服列表和匹配(名称,类型)对与字典中的一对来完成此填充.

结论: 此方法允许传递任何自定义顶点属性和着色器制服,而不会在引擎中使用硬编码名称/语义.基本上只有loader和render知道特定的语义:

  • Loader填写网格数据流声明和材料字典.
  • 渲染使用了解名称的着色器,提供其他参数并选择要绘制的正确网格.


rot*_*lup 8

根据我的经验,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统一块到与您的应用程序兼容的内存布局之外,我不会进入情况几乎相同的制服.

我自己并不满足于此,所以我很乐意有一些相互矛盾的信息:)