OpenGL : 为什么我不能将单个浮点数从顶点着色器传递到片段着色器?



编辑:见文末有关该主题的新调查。

我的着色器一直在经历一个奇怪的行为。简而言之,我发现这是非常奇怪的,通过一个单一的浮动从顶点着色器到片段着色器,我也必须通过一个假变量,我正在寻找这种行为的解释。

在更多的细节:我写了两个极简的着色器

  • 一个顶点着色器,传递一个浮点数(只有一个,这是重要的),vertAlpha,片段着色器,像这样:

    #version 150
    uniform float alphaFactor;
    uniform mat4 cameramodel;
    in float vertAlpha;
    in vec3 vert;
    in vec3 vertScale;
    in vec3 trans;
    out float fragAlpha;
    void main()
    {
        fragAlpha = alphaFactor * vertAlpha;
        gl_Position = cameramodel * vec4( trans + ( vert * vertScale ), 1.0f );
    }
    
  • 和使用传入变量的片段着色器:

    #version 150
    in float fragAlpha;
    out vec4 finalColor;
    void main()
    {
       finalColor = vec4( 0.0f, 0.0f, 0.0f, fragAlpha );
    }
    

但这不起作用,屏幕上没有出现任何东西,似乎在片段着色器中,fragAlpha保持它的初始化值为0,并忽略传递的值。

经过调查,我找到了一个"hack"来解决这个问题。我发现片段着色器"看到"fragAlpha的传递值只有当一个假的(未使用的)值与它一起传递(取决于平台(osx/NVidia GeForce 9400, Windows笔记本电脑/Intel HD Graphics), vec3或vec2是足够的)。

所以这个顶点着色器解决了这个问题:

#version 150
uniform float alphaFactor;
uniform mat4 cameramodel;
in vec3 vertFake;
in float vertAlpha;
in vec3 vert;
in vec3 vertScale;
in vec3 trans;
out float fragAlpha;
out vec3 fragFake;
void main()
{
    fragAlpha = alphaFactor * vertAlpha;
    fragFake = vertFake;
    gl_Position = cameramodel * vec4( trans + ( vert * vertScale ), 1.0f );
}

我觉得这更像是一个"hack"而不是一个解决方案。我该怎么做才能正确解决这个问题?

在可以从顶点着色器传递到片段着色器的数据大小方面是否存在"每个驱动程序制造商最小阈值"?

编辑:

看完derhass注释后,我回到我的代码,看看我是否做错了什么。

经过更多的调查,我发现这个问题不是固有的事实,我传递属性值片段着色器。我改变了顶点着色器中属性声明的顺序,看到具有"0"位置的属性(由glGetAttribLocation返回的位置)没有通过调用glVertexAttribute更新,它的值保持在0。

如果在所有其他属性之前声明"trans"属性,就会发生这种情况。在我的着色器中引入一个假属性只修复了这个问题,因为假属性占用了位置"0"。

在任何情况下,glGetError都不会返回任何错误。

我使用glDrawElements来渲染,与包含顶点位置的vbo,也许我使用它不充分…或者我的硬件不支持它?

为了给出更多的上下文,我在这里复制我对opengl的调用,用于设置和渲染:

设置:

GLuint vao, vbo;    
glGenBuffers(1, &vbo);    
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

GLfloat vertexData[] = {
    //  X     Y     Z
    0.0f, 0.0f, 1.0f, // 0
    1.0f, 0.0f, 1.0f, // 1
    0.0f, 0.0f, 0.0f, // 2
    1.0f, 0.0f, 0.0f, // 3
    0.0f, 1.0f, 1.0f, // 4
    1.0f, 1.0f, 1.0f, // 5
    1.0f, 1.0f, 0.0f, // 6
    0.0f, 1.0f, 0.0f  // 7
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
GLint vert = glGetAttribLocation(p, "vert")
glEnableVertexAttribArray(vert);
glVertexAttribPointer(vert, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(0);

渲染:

glUseProgram(p)
aphaFactor = glGetUniformLocation(p,"alphaFactor");
glUniform1f(alphaFactor, 1.0f);
cameramodel = glGetUniformLocation(p,"cameramodel");
glm::mat4 mat = gCamera.matrix();
glUniformMatrix4fv(cameramodel, 1, GL_FALSE, glm::value_ptr(mat); //
glBindVertexArray(vao);
GLubyte indices[36] =
{
    3, 2, 6, 7, 6, 2, 6, 7, 4, 2, 4, 7, 4, 2, 0, 3, 0, 2, 0, 3, 1, 6, 1, 3, 1, 6, 5, 4, 5, 6, 5, 4, 1, 0, 1, 4
};
GLint trans = glGetAttribLocation(p, "trans");
GLint alpha = glGetAttribLocation(p, "vertAlpha");
GLint scale = glGetAttribLocation(p, "vertScale");
loop over many entities:
glVertexAttrib3f(trans, m_vInstTransData[offset], m_vInstTransData[offset + 1], m_vInstTransData[offset + 2]);
glVertexAttrib1f(alpha, m_vInstTransData[offset + 3]);
glVertexAttrib3f(scale, m_vInstTransData[offset + 4], m_vInstTransData[offset + 5], m_vInstTransData[offset + 6]);
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
end loop                
glBindVertexArray(0);

您需要为此指定插值器,以防止相同原语更改的片段之间的插值:

out float fragAlpha;
in float fragAlpha;

为:

out flat float fragAlpha;
in flat float fragAlpha;

,因为float是默认内插的。类似地,默认情况下mat3不会被插入,如果你想插入它,那么使用smooth而不是flat

如果我没记错的话,标量(int,float,double)和向量(vec?,dvec?)是默认插值的,矩阵(mat?)不是。

不确定将在您的平面变量中设置哪个属性,我打赌是在原始通道的最后一个顶点上设置的一个…如果你需要在某个指定的顶点上进行计算,那么你应该将计算移到几何着色器中。

最新更新