gpt4 book ai didi

opengl - GLSL-将属性绑定(bind)到语义

转载 作者:行者123 更新时间:2023-12-02 01:08:35 27 4
gpt4 key购买 nike

我在堆栈溢出中已经看到了有关此主题的许多问题和答案。从这些答案中,我提出了将GLSL属性绑定到用户定义的语义的可能解决方案。我想就此进行一些投入和讨论,并检查它是否是一个有效的想法。

首先,假设我们有一些用户定义的语义列表:

enum VertexElementSemantic
{
POSITION, NORMAL, AMBIENT, DIFFUSE, SPECULAR,
TEX_COORD0, TEX_COORD1, TEX_COORD2, TEX_COORD3,
INDICES
};


以及一种封装设置顶点属性指针所需的数据的结构。

struct VertexElement
{
unsigned int m_source;
unsigned int m_offset;
unsigned int m_stride;
}


现在,一些RenderOperation类将包含VertexElementSemantics到VertexElements的映射。格式,大小以及VertexElement是否已规范化可以通过其语义确定。

为了设置此指针,我们需要的最后信息是属性位置本身。这是我们要将VertexElementSemantic绑定到特定位置的地方。

the first answer to this question中,我们了解到可以显式声明每个属性的所需位置,如下所示:

layout(location = 0) in vec3 position;


因此我们可以将语义映射到这些硬编码的位置,但是然后我们要求在每个着色器中对该位置进行硬编码。对这些位置的任何更改都要求我们仔细检查并编辑每个着色器。

但是,Shader源根本不需要提供此值。从 the answer to this question中,我们了解到可以在外部向着色器添加#define,如下所示:

char *sources[2] = { "#define FOO\n", sourceFromFile };
glShaderSourceARB(shader, 2, sources, NULL);


使用此方法,我们可以构建一个字符串,为每个语义的所需位置#定义变量。例如,我们可以构建一个字符串,最终将以下内容插入到每个着色器的开头:

#define POSITION_LOCATION 0
#define NORMAL_LOCATION 1
#define AMBIENT_LOCATION 2
...


回到显式说明我们的属性位置,我们现在应该可以这样声明它们:

layout(location = POSITION_LOCATION) in vec3 position;
layout(location = NORMAL_LOCATION) in vec3 normal;
layout(location = AMBIENT_LOCATION) in vec4 ambient;


这种方法将使我们能够在代码中设置每个语义的所需属性位置。它也为着色器本身提供了一种语义绑定感。这样的系统是否朝着正确的方向迈出了一步,以解决为属性位置提供含义的问题?

最佳答案

让我们考虑一下这种想法的后果。


我们可以构建一个字符串,为每个语义的所需位置#define变量。例如,我们可以构建一个字符串,最终将以下内容插入到每个着色器的开头:


好吧,这在两个方面都是不好的。首先,存在#version问题。如果要使用1.10以外的任何GLSL版本,则必须提供#version声明。并且该声明必须是着色器中除注释和空格之外的第一件事。

通过将这些#define放入着色器源中(无论是通过字符串连接,还是通过使用多个字符串),都必须接受某些后果。通常,每个单独的着色器文件都有其自己的#version声明,指定其使用的GLSL版本。但是,如果您想使用GLSL 1.10以外的其他功能,则无法做到这一点。您必须在#version之前让C ++源代码生成#define

这意味着您的着色器源现在已从其编译版本分离。这是可行的,但是这意味着您的着色器源现在不清楚,而不清楚它是什么版本。您可以通过其他方式传达版本,例如使用文件名(例如,lit_transform_330.vert将使用版本3.30)。但是您必须设计这样的系统。

现在已经解决了版本问题,接着是下一个问题:您正在做的事是多余的。

您使用诸如“语义”之类的术语,这些术语对OpenGL没有意义。似乎您正在尝试为某种特定的顶点属性分配某种名称,以便您可以在着色器和C ++代码中看到该名称的用法,从而知道该属性的用途。

也就是说,您要定义“名称”和“属性索引”之间的映射。您希望将其定义在一个位置,以便将其自动传播到每个着色器,并在整个C ++源代码中一致使用。

好了,我们已经在名称和属性索引之间建立了映射。它称为“属性名称和属性索引之间的映射”。每个着色器必须为其属性提供一个名称。这是您在诸如in vec4 position;之类的定义中看到的字符串名称,该属性的名称为position。这就是GLSL在使用变量时所称的变量。

如您链接到的答案中所述,您可以在链接程序之前将特定的属性名称与C ++代码中的属性索引相关联。这是通过the glBindAttribLocation function完成的。您可以设置任意数量的映射。链接程序时,将为指定位置分配与指定位置匹配的属性。

您只需要列出“语义”(aka:属性索引)和需要着色器用于这些属性的字符串名称。

您可能会说:“好吧,我希望着色器可以自由地随意调用变量。”我的回答是……有什么区别?您建议的方案已经要求用户遵守特定的命名约定。只是他们必须使用的名称不是变量的名称。它是您在声明时与变量关联的某些标签的名称。

那么到底有什么区别呢?着色器的作者必须遵守顶点属性变量名称的命名方案吗?所有着色器中相同概念的统一名称不是一件好事吗?

一个区别是,如果他们在您的方案下错误键入了“语义”,则将得到着色器编译错误(因为错误键入的“语义”名称将与任何实际的#define不匹配)。而如果他们输错属性名称,则只有在使用属性时不输错该名称时,他们才会收到编译器错误。

有很多方法可以捕捉到这一点。它要求使用program introspection遍历活动属性列表,并对照期望的属性名称进行检查。

您可以将其简化为一组非常简单的约定。使用您的“语义”定义:

enum VertexElementSemantic
{
POSITION, NORMAL, AMBIENT, DIFFUSE, SPECULAR,
TEX_COORD0, TEX_COORD1, TEX_COORD2, TEX_COORD3,
INDICES, NUM_SEMANTICS
};

//in the C++ file you use to link your shaders
const char *AttributeNames[] =
{
"position", "normal", "ambient", "diffuse", "specular",
"tex_coord0", "tex_coord1", "tex_coord2", "tex_coord3",
"indices",
}

static_assert(ARRAY_COUNT(AttributeNames) == NUM_SEMANTICS); //Where `ARRAY_COUNT` is a macro that computes the number of elements in a static array.

GLuint CreateProgram(GLuint vertexShader, GLuint fragmentShader)
{
GLuint prog = glCreateProgram();
//Attach shaders
for(int attrib = 0; attrib < NUM_SEMANTICS; ++attrib)
{
glBindAttribLocation(prog, attrib, AttributeNames[attrib]);
}

glLinkProgram(prog);

//Detach shaders
//Check for linking errors

//Verify that attribute locations are as expected.
//Left as an exercise for the reader.

return prog;
}


就个人而言,我只会使用数字。无论您使用什么,编写着色器的人都必须遵守一些约定。这意味着当他们去编写一个需要位置的顶点着色器时,他们将不得不查找如何说“这是一个位置”。因此,无论如何,他们都必须在某个地方的表中查找内容。

在这一点上,它取决于最可能出现的问题。最可能出现的问题是认为自己知道答案但实际上是错误的人(即:没有查找答案),或者是输入错误答案的人。键入数字确实很困难(尽管肯定会发生),而键入 POSITION_LOCATION则容易得多。前一个问题可能会或多或少地相等。

因此在我看来,如果您的约定基于数字而不是字词,那么您会遇到较少的约定不匹配问题。

关于opengl - GLSL-将属性绑定(bind)到语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15826884/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com