为啥我可以有 OpenGL 着色器类,但不能有 VAO 类?

Posted

技术标签:

【中文标题】为啥我可以有 OpenGL 着色器类,但不能有 VAO 类?【英文标题】:Why can I have an OpenGL shader class, but not a VAO class?为什么我可以有 OpenGL 着色器类,但不能有 VAO 类? 【发布时间】:2015-09-02 01:22:57 【问题描述】:

我一直在摆弄制作游戏/渲染引擎,我发现我可以为着色器对象创建一个类,但如果我将 VAO 包装在一个类中,它就不会渲染。

着色器没有返回错误,并且 VAO 和着色器是有效的 OpenGL 对象。

更新

问题出在这一行:

glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);

正如@BDL 在 cmets 中建议的那样,我想了想,我意识到,应该是:

glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * intNumVertex * 3, arrFVertex, GL_STATIC_DRAW);

更新 2 作为对被搁置的回应,这里有一个最低限度的完整和可验证的示例:

#include <OpenGL/gl3.h>
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

SDL_Window *window = NULL;
SDL_GLContext openGLRenderer;
bool bolRunning = true;
int intGLVersionMajor, intGLVersionMinor;

GLfloat arrFVertex[] = 
     0.5f,  0.5f, 0.0f,  // Top Right
     0.5f, -0.5f, 0.0f,  // Bottom Right
    -0.5f,  0.5f, 0.0f,  // Top Left 
    
     0.5f, -0.5f, 0.0f,  // Bottom Right
    -0.5f, -0.5f, 0.0f,  // Bottom Left
    -0.5f,  0.5f, 0.0f   // Top Left 
;
GLuint intVAO;
GLuint intVBO;
GLuint intShaderAttribPosition;
GLuint intShaderProgram;
GLuint intNumVertex = 6;

void loadShaders(const char *strVertexShaderSource, const char *strFragmentShaderSource) 
    intShaderProgram = glCreateProgram();
    
    GLuint intVertexShader;
    intVertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(intVertexShader, 1, &strVertexShaderSource, NULL);
    glCompileShader(intVertexShader);
    
    GLuint intFragmentShader;
    intFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(intFragmentShader, 1, &strFragmentShaderSource, NULL);
    glCompileShader(intFragmentShader);
    
    glAttachShader(intShaderProgram, intVertexShader);
    glAttachShader(intShaderProgram, intFragmentShader);
    glLinkProgram(intShaderProgram);
    
    glDeleteShader(intVertexShader);
    glDeleteShader(intFragmentShader);


void buildVAO(GLfloat *arrFVertex) 
    intShaderAttribPosition = glGetAttribLocation(intShaderProgram, "f3Position");
    
    glGenVertexArrays(1, &intVAO);
    glBindVertexArray(intVAO);
    
    glGenBuffers(1, &intVBO);
    glBindBuffer(GL_ARRAY_BUFFER, intVBO);
    
    glVertexAttribPointer(intShaderAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
    glEnableVertexAttribArray(intShaderAttribPosition);
    glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
    
    glBindVertexArray(0);


int main(int argc, char **argv) 
    SDL_Init(SDL_INIT_EVERYTHING);
    
    window = SDL_CreateWindow("GSEngine",
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              640, 480,
                              SDL_WINDOW_OPENGL);
    
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    
    if (window == NULL) 
        printf("Could not create window: %s\n", SDL_GetError());
        exit(1);
    
    
    openGLRenderer = SDL_GL_CreateContext(window);
    
    SDL_GL_MakeCurrent(window, openGLRenderer);
    glViewport(0, 0, 640, 480);
    
    loadShaders("#version 330 core\n\
                in vec3 f3Position;\n\
                void main() \n\
                    gl_Position = vec4(f3Position, 1.0);\n\
                ", "#version 330 core\n\
                out vec4 f4Color;\n\
                void main() \n\
                    f4Color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n\
                ");
    
    buildVAO(arrFVertex);
    
    while (bolRunning) 
        SDL_Event event;
        while (SDL_PollEvent(&event)) 
            if (event.type == SDL_QUIT) 
                bolRunning = false;
            
        
        
        SDL_GL_MakeCurrent(window, openGLRenderer);
        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        glUseProgram(intShaderProgram);
        glDrawArrays(GL_TRIANGLES, 0, intNumVertex);
        
        SDL_GL_SwapWindow(window);
    
    
    glDeleteBuffers(1, &intVBO);
    glDeleteVertexArrays(1, &intVAO);
    glDeleteShader(intShaderProgram);
    
    SDL_GL_DeleteContext(openGLRenderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    
    return 0;

【问题讨论】:

只要调用了所有正确的 OpenGL 命令,是否将代码包装在一个类中没有任何区别。我认为您真的应该尝试创建MCVE,而不是期望我们下载您的整个存储库。此外,当您更改其中的代码时,这些问题对于未来的读者来说变得毫无价值。 我原本打算不理会那个 repo,但我不知道如何使它更小,但我会尝试。 好的,很公平。您提到将您的 VAO 包装在一个类中时它不起作用。这是否意味着您尝试了没有 VAO 类的版本并且它有效?如果是这样,查找该代码中的差异可能会很有用。 是的,我已经尝试过不使用封装 VAO 的类,并且渲染效果很好。另外,我已经多次寻找差异,我现在再看看我是否遗漏了什么。你想要一个没有 VAO 类的例子吗? 查看sizeof(arrFVertex) 返回的内容。 【参考方案1】:

问题与 VAO 无关,而与 VBO 有关。由于您将指针传递给构造函数:

void GSMesh::build(GLfloat *arrFVertex, GSShader *shader, int _intNumVertex)

    glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);

sizeof(arrFVertex) = sizeof(GLfloat*) 这是指针的大小,而不是指向的数组的大小。正确的代码如下所示:

glBufferData(GL_ARRAY_BUFFER,
             sizeof(GLfloat) * _intNumVertex * 3, arrFVertex,
             GL_STATIC_DRAW);

总的来说,我必须补充一点,这不是在 SO 上提出问题的方式。如果您在问题中至少包含代码的相关部分,那就太好了。

【讨论】:

我做一个 github repo 的唯一原因是我没有把问题写得太长,而且我不确定具体是什么功能问题,但你已经向我展示了,而且现在超级明显。 通过回答他们,你鼓励人们提出这样的问题。【参考方案2】:

不管规范怎么说,对于某些驱动程序,您必须先启用着色器,然后才能获取属性或制服的位置。这可能是导致您的问题的原因。

在您的代码中,这意味着在您的 GSMesh::build 方法中添加:

shader->use();

之前:

intShaderAttribPosition = glGetAttribLocation(shader->intShaderProgram, "f3Position");

如果您使用的 OpenGL 版本支持Vertex Attribute Indexes,我个人会使用它们。

在顶点着色器中你可以有类似的东西:

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coords;

然后在你的网格类中你所需要的就是:

struct Vertex

    glm::vec3 position;
    glm::vec2 tex_coords;
;

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position);

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tex_coords));

【讨论】:

以上是关于为啥我可以有 OpenGL 着色器类,但不能有 VAO 类?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个在opengl中绘制三角形的着色器不会多次运行

OpenGL 着色器有时可以编译,有时不能

为啥 glColorPointer 不给三角形着色 - 以及 opengl es 的其他奇怪的东西

尝试为opengl创建像素化着色器失败

为啥调用 glCreateShader 时这个 OpenGL 着色器分段错误?

Opengl为啥这个着色器不起作用?