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

时间:2014-08-14 07:29:00

标签: opengl glsl parameter-passing shader gpu

编辑:最后查看有关该主题的新调查。

我的着色器一直遇到奇怪的行为。简而言之,我发现很奇怪,要将一个浮点数从顶点着色器传递到片段着色器,我还必须传递一个假变量,我正在寻找这种行为的解释。

更多细节:我写了两个简约着色器

  • 一个顶点着色器,它将一个float(只有一个,这很重要)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,并忽略传递的值。

经过调查,我发现了一个“黑客”来解决这个问题。我发现碎片着色器“看到”了碎片传递的值只有在假冒(未使用)值传递给它时(取决于平台(osx / NVidia GeForce 9400,Windows笔记本电脑/英特尔高清显卡),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 );
}

我觉得这更像是一个“黑客”,而不是一个解决方案。我该怎么做才能妥善解决这个问题?

根据可以从顶点着色器传递到片段着色器的数据大小,是否存在“每驱动程序制造商最低阈值”?

编辑:

阅读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);

1 个答案:

答案 0 :(得分:0)

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

out float fragAlpha;
in float fragAlpha;

成:

out flat float fragAlpha;
in flat float fragAlpha;

因为float是默认插值的。同样,默认情况下不会插入mat3,如果您想对其进行插值,请使用smooth代替flat ...

如果我没记错的话,默认情况下会插入Scalars(int,float,double)和向量(vec?,dvec?),而矩阵(mat?)则不会。

不确定您的平面变量中将设置哪个属性我的赌注是原始传递的最后一个顶点上设置的属性...如果您需要在某个指定顶点上计算它,那么您应该将计算移动到几何着色器。