【问题标题】:The vertex shade bug - variables declaration order顶点阴影错误 - 变量声明顺序
【发布时间】:2021-04-22 12:45:59
【问题描述】:

我已经开始学习 C++/OpenGL 一年了,我偶然发现了 GLSL 语言的一个模糊错误。我想知道是否有人得到了类似的结果。

只有当我在顶点阴影中省略了layout(location = ?) 并且我必须手动为glVertexAttribPointerglEnableVertexArrayAttrib 指定通用顶点属性的索引时才会产生该错误,我的意思是,通过省略使用glGetAttribLocation 最终将从顶点阴影中获取顶点属性的索引位置。奇怪的是,以特定顺序声明输入和输出变量。在我的顶点阴影中,例如,如果我用这个顺序声明它们:

gl_Position = vec4(aVertex, 1.0);
color = aColor;

但它不会产生故障,如果我颠倒声明顺序,它会变得很明显。

幸运的是,我修复了它。但是我需要更多关于它的解释,尤其是在 GLSL 语言中,为什么变量声明顺序很重要。在 C/C++ 中,这似乎无关紧要。

这里是这个错误的完整示例:[我使用了 SFML/Glew 库]

#include <SFML/Window.hpp>
#include <GL/GLew.h>

//turn it ON/OFF e.g Enable_Bug [1|0]
#define Enable_Bug 1 // to produce the Bug, we should omit glGetAttribLocation(), 

// shader sources
static const GLchar* vert_R = R"(#version 440 core
// We have a Bug! 

#define Enable_Bug_GLSL 0   // here the catch, if we turned this OFF by turning [Enable_Bug_GLSL 0] 
                            // and both [Enable_Bug_GLSL_Attrib | Enable_Bug] are ON, it will fix the Bug!! weird

#define Enable_Bug_GLSL_Attrib 1 // to produce the Bug, we should omit layout(location = ?)

#if Enable_Bug_GLSL_Attrib
    in vec3 aVertex;
    in vec4 aColor;
#else
    layout(location = 0) in vec3 aVertex;
    layout(location = 1) in vec4 aColor;
#endif

    out vec4 color;

    void main()
    {
#if Enable_Bug_GLSL
        color = aColor;
        gl_Position = vec4(aVertex, 1.0);
#else
        gl_Position = vec4(aVertex, 1.0);
        color = aColor;
#endif
    }
)";

static const GLchar* frag_R = R"(#version 440 core
    in vec4 color;
    layout(location = 0) out vec4 FragColor;
    void main()
    {
        FragColor = color;
    }
)";

static void checkStatus(GLuint obj)
{
    GLint status = GL_FALSE;

    if (glIsShader(obj))   glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
    if (glIsProgram(obj))  glGetProgramiv(obj, GL_LINK_STATUS, &status);
    if (status == GL_TRUE) return;
    glDeleteShader(obj);
    obj = 0;
}

static void attachShader(GLuint program, GLenum type, const GLchar* src)
{
    GLuint shader = glCreateShader(type);

    glShaderSource(shader, 1, &src, NULL);
    glCompileShader(shader);
    checkStatus(shader);
    glAttachShader(program, shader);
    glDeleteShader(shader);
}

static GLuint loadShader(const GLchar* vert, const GLchar* frag, const GLchar* geom = nullptr)
{
    GLuint progam = glCreateProgram();
    if (vert) attachShader(progam, GL_VERTEX_SHADER, vert);
    if (geom) attachShader(progam, GL_GEOMETRY_SHADER, geom);
    if (frag) attachShader(progam, GL_FRAGMENT_SHADER, frag);
    glLinkProgram(progam);
    checkStatus(progam);
    return progam;
}

int main()
{
    sf::Window window(sf::VideoMode(800, 600), "OpenGL");

    //Initialize GLEW
    glewExperimental = GL_TRUE;
    GLenum err = glewInit();

    //If GLEW hasn't initialized
    if (err != GLEW_OK)
    {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        throw std::runtime_error("Failed to initialize GLEW\n");
        return -1;
    }

    GLfloat position[] = {
        -1.0f, -1.0f, 0.0f,
         1.0f, -1.0f, 0.0f,
        -1.0f,  1.0f, 0.0f,
         1.0f,  1.0f, 0.0f,
    };

    GLfloat color[] = {
        1.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 1.0f,

    };

    GLuint program = loadShader(vert_R, frag_R);
    glUseProgram(program);
    GLint location;

#if Enable_Bug
    location = 0;
#else
    location = glGetAttribLocation(program, "aVertex");
#endif

    glEnableVertexAttribArray(location);
    glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, position);

#if Enable_Bug
    location = 1;
#else
    location = glGetAttribLocation(program, "aColor");
#endif

    glEnableVertexAttribArray(location);
    glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, color);

    // Initialize clear colors
    glClearColor(0.f, 0.f, 0.f, 1.f);

    while (window.isOpen())
    {
        sf::Event windowEvent;
        while (window.pollEvent(windowEvent))
        {
            if (windowEvent.type == sf::Event::Closed)
                window.close();
        }

        // render
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        window.display();
    }
    return 0;
}

【问题讨论】:

  • 我认为当您省略 layout(location = 时,您需要调用 glBindAttribLocation

标签: c++ opengl glsl shader vertex-shader


【解决方案1】:

如果您没有通过layout qualifiers 指定属性索引,则不指定属性索引并且可以具有任何值。不保证顺序,也不保证索引是 0 和 1。
链接程序后必须获取glGetAttribLocation的属性索引,或者链接程序前必须指定glBindAttribLocation的属性索引。

【讨论】:

    【解决方案2】:

    如果您在 GLSL 中省略这些位置,OpenGL 将按照它认为合适的方式分配它们。因此,如果您甚至不使用glGetAttribLocation 查询它们并假设aVertex 为0,aColor 为1,那么如果编译器不同意,当然会有故障。

    GLSL 链接器完全有可能根据第一次使用来分配位置,但同样不能保证。我认为明确设置位置没有缺点,O

    【讨论】:

      猜你喜欢
      • 2019-08-13
      • 1970-01-01
      • 1970-01-01
      • 2016-05-12
      • 1970-01-01
      • 2014-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多