将顶点着色器中的浮点数组传递给glsl 3.3中的片段着色器

kku*_*llo 1 opengl shader glsl

我想通过

out float texture_contribs[16]
Run Code Online (Sandbox Code Playgroud)

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

但是,无论顶点着色器中的值如何,frament着色器中的值始终为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];
    }
}
Run Code Online (Sandbox Code Playgroud)

这是片段着色器代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

And*_*man 5

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

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

const int gl_MaxVertexAttribs = 16; // Minimum: 16 Vertex Attribute Slots
Run Code Online (Sandbox Code Playgroud)

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

GLuint max_vtx_attribs;
glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &max_vtx_attribs);
Run Code Online (Sandbox Code Playgroud)

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

没有太多实际应用需要超过16个每顶点属性,并且通常依赖于更适合存储大量数据的东西,例如纹理/着色器存储缓冲区对象.


使用当前编写的GLSL顶点着色器时,事情会变得混乱.

OpenGL 3.3核心规范规范 - 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核心配置文件规范 - 2.11.3顶点属性 - 第55页

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

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


这里的问题是你的每个标量都浪费了3个组件的存储空间.

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

然后您的存储要求变为:

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

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