【问题标题】:Passing array of floats from vertex shader to fragment shader in glsl 3.3在 glsl 3.3 中将浮点数组从顶点着色器传递到片段着色器
【发布时间】:2014-04-30 22:40:49
【问题描述】:

我正在尝试通过

out float texture_contribs[16]

使用 glsl 3.3 从顶点着色器到帧着色器

但是,无论顶点着色器中的值如何,帧着色器中的值始终为 0.0。

这是我的顶点着色器代码:

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatrix;

layout(location = 0) in vec4 in_position;
layout(location = 1) in vec4 in_colour;
layout(location = 2) in vec2 in_coord;
layout(location = 3) in vec3 in_normal;
layout(location = 4) in float texture_contributions[16];

out vec2 texcoord;
out vec4 pass_colour;
out float texture_contribs[16];

smooth out vec3 vNormal;

void main()
{
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_position;
    texcoord = in_coord;
    vec4 vRes = normalMatrix*vec4(in_normal, 0.0); 
    vNormal = vRes.xyz;
    pass_colour = in_colour;
    for (int i = 0; i < 16; i++)
    {
        texture_contribs[i] = texture_contributions[i];
    }
}

这是片段着色器代码:

uniform sampler2D texture[16];

in vec2 texcoord;
in vec4 pass_colour;
in float texture_contribs[16];

smooth in vec3 vNormal;

out vec4 out_colour;

struct SimpleDirectionalLight
{
   vec3 vColor;
   vec3 vDirection;
   float fAmbientIntensity;
};

uniform SimpleDirectionalLight sunLight;

void main()
{
    vec4 vTexColor = texture2D(texture[2], texcoord) * texture_contribs[2] + texture2D(texture[3], texcoord) * texture_contribs[3];
    if(vTexColor.a < 0.1)
        discard;
    float fDiffuseIntensity = max(0.0, dot(normalize(vNormal), -sunLight.vDirection));
    out_colour = vTexColor*pass_colour*vec4(sunLight.vColor*(sunLight.fAmbientIntensity+fDiffuseIntensity), 1.0);
}

我尝试将数组拆分为单独的变量并分别传递它们,它们的值仍然在片段着色器中消失。

【问题讨论】:

  • 这个:layout(location = 4) in float texture_contributions[16]; 让我觉得非常不寻常。这需要 16 个属性槽,并且大多数实现将您限制为总共 16 个。您可以使用layout(location = 4) in mat4 texture_contributions; 做同样的事情,同时只占用 4 个属性槽。它将分配给属性槽 4,5,6,7。
  • 你真的在检查这个着色器的编译器日志吗?标量与vec4s 使用相同的存储空间,因此当您将它们聚合到这样的数组中而不是打包到vec4mat4s 中时,您就是在玩火。
  • 是的,我检查了编译器日志,它很干净。我考虑将它们打包成 mat4 但决定以这种方式尝试以获得更清晰的语法。我将尝试将其切换到 mat4 看看是否有帮助
  • @AndonM.Coleman 我能够按照您的建议使用 mat4 使其工作,然后在顶点着色器中将值传输到 float[16] 并将其传递给片段着色器。将 mat4 传递给片段着色器无法正常工作。我假设 opengl 不会以我需要的方式插入矩阵。
  • 我会选择你所拥有的。这允许您规避的 16 个属性限制仅适用于 input 顶点数据。您可以按照自己的方式从顶点着色器中输出构建数据,不限于 16 个。

标签: opengl glsl shader


【解决方案1】:

OpenGL 3.3 至少需要 16 个顶点属性位置。

顶点属性限制(由GLSL定义):

const int gl_MaxVertexAttribs = 16; // Minimum: 16 Vertex Attribute Slots

顶点属性限制(在OpenGL中查询):

GLuint max_vtx_attribs;
glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &max_vtx_attribs);

据我所知,AMD 是唯一一家提供超过 16 个属性的供应商(他们在某些驱动程序/硬件组合上提供 29-32 个属性)。 Intel、Apple、NVIDIA 和 Mesa 都给你 16 个。如果你想编写可移植的代码,你应该尝试定位不超过 16 个顶点属性。否则,你必须为不同的供应商编写不同的代码路径,这很不好玩。

没有多少实际应用程序需要超过 16 个每个顶点属性,而那些通常依赖于更适合存储大量数据的应用程序,例如纹理/着色器存储缓冲区对象。


您的 GLSL 顶点着色器目前的编写方式会变得一团糟。

OpenGL 3.3 Core Profile Specification - 2.7 顶点规范 - 第 26 页

顶点着色器(参见 2.11 节)访问 4 组件通用顶点属性 的数组。该数组的第一个槽编号为 0,数组的大小由依赖于实现的常量 GL_MAX_VERTEX_ATTRIBS 指定。

GLSL 3.3 中的每个顶点属性位置都能够存储单个 vec4,大于 vec4 的数据类型(例如 mat4)将跨越多个位置。小于vec4 的数据类型会占用整个位置,这就是着色器开始出现问题的地方。您已经声明了一个 16 元素的标量数组,每个标量都有自己的顺序位置,从 4 开始。这意味着数组占用位置 4 - 19,但大多数实现没有 20 个位置可供分配。

OpenGL 3.3 Core Profile Specification - 2.11.3 顶点属性 - pp. 55

如果编译器和链接器确定在执行着色器时可以访问该属性,则认为通用属性变量是活动的。在顶点着色器中声明但从未使用过的属性变量将不计入限制。在编译器和链接器无法做出决定性决定的情况下,属性将被视为活动的。 如果活动顶点属性的数量超过GL_MAX_VERTEX_ATTRIBS,程序对象将无法链接。

前 4 个顶点属性 (0-3) 是活动的,标量数组创建的 16 个也是活动的。您的 GLSL 程序(应该)无法链接到任何不提供至少 20 个顶点属性的实现。如果没有,那么您的实现不合规。


这里的问题是您的每个标量都在浪费 3 个分量的存储空间。

您实际上并不需要消耗 16 个属性槽来存储所有逐顶点数据。如果将 float 的 16 元素数组替换为 vec4 的 4 元素数组或单个 mat4,则只需使用 4 个属性槽即可存储相同数量的数据。

那么你的存储需求变成:

  4 (in_position, in_colour, in_coord, in_normal) + 4 (texture_contributions) = 8

这也大大简化了顶点指针的设置,因为您只需要 8 个而不是 20 个。

【讨论】:

  • 内容丰富的详细答案。代码已更新并按预期工作,使用 mat4 存储纹理贡献数据。使用的 opengl 实现来自 ATI,支持 29 个属性位置,但为了兼容性,我将尝试将其限制为 16 个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多