c++ - glVertexAttrib3f 在一台机器上的奇怪行为

标签 c++ visual-c++ opengl glsl shader

我有一个非常奇怪的问题,我的简单 OpenGL 应用程序无法在我女朋友的机器上运行。起初我想到了我的代码的各种问题,但我最终可以将其分解为这段代码不起作用(不起作用意味着:三角形绘制正确,但是黑色,即没有正确的颜色):

#include <stdio.h>
#include <stdlib.h>
#include <string>

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>

#include "../common/shader.h"


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


glm::mat4 MVP;
glm::mat4 vp;


const char *vertexSource =
        "#version 150\n"
        "layout(location = 0) in vec3 position;"
        "layout(location = 1) in vec3 color;"
        "out vec3 fragColor;"
        "uniform mat4 MVP;"
        "void main() {"
        "gl_Position = MVP * vec4(position, 1.0);"
        "fragColor = color;"
        "}";

const char *fragmentSource =
        "#version 150\n"
        "in vec3 fragColor;"
        "out vec4 outColor;"
        "void main() {"
        "outColor = vec4(fragColor, 1.0);"
        "}";


// Key callback: exit on ESCAPE
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
        if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
                glfwSetWindowShouldClose(window, GL_TRUE);
}


// Initialize and return a window with GLFW
GLFWwindow *initGLWindow(int width, int height, int samples, const char *title, GLFWkeyfun keycb)
{
        if (!glfwInit())
        {
                fprintf(stderr, "Failed to initialize GLFW\n");
                return NULL;
        }
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_SAMPLES, samples);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        GLFWwindow *w = glfwCreateWindow(width, height, title, NULL, NULL);
        if (!w)
        {
                glfwTerminate();
                return NULL;
        }

        glfwMakeContextCurrent(w);
        glfwSetKeyCallback(w, keycb);

        glewExperimental = true;
        if (glewInit() != GLEW_OK)
        {
                fprintf(stderr, "Failed to initialize GLEW\n");
                return NULL;
        }

        return w;
}


int main()
{
        // Initialize the OpenGL window
        GLFWwindow *window = initGLWindow(1024, 768, 2, "Schnuff", key_callback);

        // Load and use the shaders
        GLuint programID = LoadShaders(vertexSource, fragmentSource);
        glUseProgram(programID);

        // Get the attribute locations
        GLuint posAttrib = glGetAttribLocation(programID, "position");
        printf("posAttrib = %d\n", posAttrib);
        GLuint colAttrib = glGetAttribLocation(programID, "color");
        printf("colAttrib = %d\n", colAttrib);
        //GLint normAttrib = glGetAttribLocation(programID, "normal");
        //printf("normAttrib = %d\n", normAttrib);
        GLuint mvpID = glGetUniformLocation(programID, "MVP");

        // Vertex array object
        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

        // Vertex buffer object
        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(reticle_vertices), reticle_vertices, GL_STATIC_DRAW);

        glEnableVertexAttribArray(posAttrib);
        glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

        // Hide the cursor
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        glEnable(GL_CULL_FACE);

        glClearColor(0.0f, 0.0f, 0.2f, 1.0f);
        glm::mat4 m = glm::mat4(1.0f);

        // Main loop
        do
        {
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                glUniformMatrix4fv(mvpID, 1, GL_FALSE, &m[0][0]);
                glVertexAttrib3f(colAttrib, 1.0f, 0.0f, 0.0f);
                glDrawArrays(GL_TRIANGLES, 0, 3);

                glfwSwapBuffers(window);
                glfwPollEvents();
        }
        while (!glfwWindowShouldClose(window));

        glDeleteProgram(programID);
        glfwDestroyWindow(window);
        glfwTerminate();
        return 0;
}

据我所知,问题发生的原因如下:在她的机器上,posAttrib = 1,colAttrib = 0,而在我的机器上事实恰恰相反。我尝试使用

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;

然后就可以正常工作了!虽然一旦我交换了这些数字(我还没有用其他值和#version 330 core\n测试它,但她的笔记本电脑目前处于离线状态),它又停止工作了......

我什至发现了以下未解答的问题 here on SO ,这似乎密切相关。

你们中是否有人遇到过类似的行为,或者知道如何在不使用 layout(location = x) 的情况下解决整个情况?因为我认为在一个较大的项目中,手动设置每个位置可能会很乏味或不必要(如果我错了,请纠正我,这实际上是首选的方法!)。

尚未测试:0 或 1 以外的其他值以及 #version 内容,因为在我的机器上我什至无法使用 layout(location = x)没有#version 330 core(这又很奇怪,因为它显然在她的机器上做了一些事情,使其工作)。

我是 OpenGL 的新手,因此在这里完全困惑! :-)

最佳答案

看起来像 driver bug在我的 AMD 卡上。

对颜色数组使用 VBO 是可行的:

#include <vector>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>

// GLSL shader program loader
struct Program
{
    static GLuint Load( const char* vert, const char* geom, const char* frag )
    {
        GLuint prog = glCreateProgram();
        if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
        if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
        if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE, len = 10;
        if( glIsShader(obj) )   glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) )  glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        if( glIsShader(obj) )   glGetShaderiv( obj, GL_INFO_LOG_LENGTH, &len );
        if( glIsProgram(obj) )  glGetProgramiv( obj, GL_INFO_LOG_LENGTH, &len );
        std::vector< char > log( len, 'X' );
        if( glIsShader(obj) )   glGetShaderInfoLog( obj, len, NULL, &log[0] );
        if( glIsProgram(obj) )  glGetProgramInfoLog( obj, len, NULL, &log[0] );
        std::cerr << &log[0] << std::endl;
        exit( -1 );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};
#define GLSL(version, shader) "#version " #version "\n" #shader

const char* vert = GLSL
    (
    150 core,
    in vec3 position;
    in vec3 color;
    out vec3 fragColor;
    uniform mat4 MVP;
    void main() 
    {
        fragColor = color;
        gl_Position = MVP * vec4(position, 1.0);
    }
);

const char* frag = GLSL
    (
    150 core,
    in vec3 fragColor;
    out vec4 outColor;
    void main()
    {
        outColor = vec4(1.0);
    }
);


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

const GLfloat colors[] =
{
    1.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f
};


// Key callback: exit on ESCAPE
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}


// Initialize and return a window with GLFW
GLFWwindow *initGLWindow(int width, int height, int samples, const char *title, GLFWkeyfun keycb)
{
    if (!glfwInit())
    {
        fprintf(stderr, "Failed to initialize GLFW\n");
        return NULL;
    }
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_SAMPLES, samples);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *w = glfwCreateWindow(width, height, title, NULL, NULL);
    if (!w)
    {
        glfwTerminate();
        return NULL;
    }

    glfwMakeContextCurrent(w);

    glfwSetKeyCallback(w, keycb);

    glewExperimental = true;
    if (glewInit() != GLEW_OK)
    {
        fprintf(stderr, "Failed to initialize GLEW\n");
        return NULL;
    }
    while( glGetError() != GL_NO_ERROR ) {}

    return w;
}


int main()
{
    // Initialize the OpenGL window
    GLFWwindow *window = initGLWindow(1024, 768, 2, "Schnuff", key_callback);

    // Hide the cursor
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);

    // Load and use the shaders
    GLuint programID = Program::Load( vert, NULL, frag );
    glUseProgram(programID);

    // Vertex array object
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Vertex buffer object
    GLuint posVbo;
    glGenBuffers(1, &posVbo);
    glBindBuffer(GL_ARRAY_BUFFER, posVbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(reticle_vertices), reticle_vertices, GL_STATIC_DRAW);

    GLuint colorVbo;
    glGenBuffers(1, &colorVbo);
    glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glEnable(GL_CULL_FACE);

    // Main loop
    while( !glfwWindowShouldClose(window) )
    {
        glClearColor(0.0f, 0.0f, 0.2f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glm::mat4 m = glm::mat4(1.0f);
        GLuint mvpID = glGetUniformLocation(programID, "MVP");
        glUniformMatrix4fv(mvpID, 1, GL_FALSE, &m[0][0]);

        GLuint posPos = glGetAttribLocation( programID, "position" );
        glEnableVertexAttribArray( posPos );
        glBindBuffer(GL_ARRAY_BUFFER, posVbo);
        glVertexAttribPointer( posPos, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );

        GLuint colorPos = glGetAttribLocation( programID, "color" );
        // broken
        //glDisableVertexAttribArray( colorPos );
        //glVertexAttrib3f( colorPos, 1.0f, 0.0f, 0.0f );
        // works
        glEnableVertexAttribArray( colorPos );
        glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
        glVertexAttribPointer( colorPos, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );

        glDrawArrays(GL_TRIANGLES, 0, 3);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteProgram(programID);
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

关于c++ - glVertexAttrib3f 在一台机器上的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18321980/

相关文章:

c++ - 为什么模板测试不丢弃片段?

performance - GLSL:为什么 const int 数组比普通数组慢这么多?

c++ - 为什么我们不能声明一个 void 类型的变量?

c++ - OpenCV 4.2.0 FileStorage段错误

c++ - 编译 C++ 代码时出现编译错误

visual-c++ - 如何在不四舍五入小数点值的情况下获得精确的小数精度值?

OpenGL 4.1 学习资源

c++ - 从 PSD 文件构建层复合

c++ - 分析性能测量中的峰值

c++ - 应用程序编译过程中出现奇怪的单词