【问题标题】:OpenGL : Why can't I pass a single float from vertex shader to fragment shader?OpenGL:为什么我不能将单个浮点数从顶点着色器传递到片段着色器?
【发布时间】:2014-08-14 07:29:00
【问题描述】:

编辑:请参阅最后关于该主题的新调查。

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

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

  • 一个将一个浮点数(只有一个,这很重要)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 );
}

我发现这更像是“破解”而不是解决方案。我应该怎么做才能正确解决这个问题?

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

编辑:

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

【问题讨论】:

  • 不,没有这样的最小值。我对您的描述的第一个猜测是您的客户端 GL 代码中的错误,尤其是属性和/或统一位置。
  • @derhass 感谢您的关注!我用属性和制服仔细检查了我在代码中所做的事情,并检查了这些位置是否都正常。这样做,我发现了更多关于这个问题的信息,它似乎与属性具有“0”位置的事实有关(根据规范这是合法的,非法位置是-1)。请参阅我在问题中的编辑以了解更多信息。我还复制了我在程序中执行的 gl 调用。
  • 属性0本身没有问题。您是否在代码中的某处使用旧的 glVertex* 或 glVertexPointer 调用?该内置顶点属性是别名属性 0。
  • @derhass 我的应用程序中唯一的 glVertex* 调用是 glVertexAttrib 和 glVertexAttribPointer。评论中的别名是什么意思?
  • 我的意思是使用旧的、已弃用的 glVertex.. 和 glVertexPointer 命令将等同于使用属性索引为 0 的现代通用属性函数。但是由于您不使用那些旧的东西,这应该不是问题。

标签: opengl glsl parameter-passing shader gpu


【解决方案1】:

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

out float fragAlpha;
in float fragAlpha;

进入:

out flat float fragAlpha;
in flat float fragAlpha;

因为float 默认是插值的。同样mat3默认不插值,如果你想插值那么使用smooth而不是flat ...

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

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

【讨论】:

  • 我现在才看到这个答案,我现在无法测试它,但它似乎有道理!谢谢
  • @iMajuscule 是的,新的答案通知并不总是有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多