简体   繁体   English

为什么我可以拥有 OpenGL 着色器类,而不能拥有 VAO 类?

[英]Why can I have an OpenGL shader class, but not a VAO class?

I have been fiddling around with making a game/rendering engine, and I have found that I can have a class for a shader object, but if I wrap a VAO in a class, it won't render.我一直在摆弄一个游戏/渲染引擎,我发现我可以有一个着色器对象的类,但是如果我将一个 VAO 包装在一个类中,它就不会渲染。

The shaders return no errors, and the VAO and shaders are valid OpenGL objects.着色器不会返回任何错误,并且 VAO 和着色器是有效的 OpenGL 对象。

UPDATE更新

The problem is this line:问题是这一行:

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

As @BDL suggested in the comments, I thought about it and I realized, it should be:正如@BDL 在评论中所建议的那样,我考虑了一下,意识到应该是:

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

UPDATE 2 In response to being put on hold, here is a Minimum Complete and Verifiable Example:更新 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;
}

The problem has nothing to do with the VAO, but with the VBO.问题与VAO无关,而是与VBO有关。 Since you pass a pointer to the constructor:由于您将指针传递给构造函数:

void GSMesh::build(GLfloat *arrFVertex, GSShader *shader, int _intNumVertex)
{
    glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
}

sizeof(arrFVertex) = sizeof(GLfloat*) which is the size of the pointer, not the size of the array pointed to. sizeof(arrFVertex) = sizeof(GLfloat*)这是指针的大小,而不是指向的数组的大小。 The correct code will look like this:正确的代码如下所示:

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

In general I have to add, that this is not the way how questions should be asked on SO.总的来说,我必须补充一点,这不是在 SO 上提问的方式。 It would have been good if you would have included at least the relevant parts of the code in your question.如果您至少在问题中包含代码的相关部分,那就太好了。

Despite what the spec says, with some drivers you must enable the shader before you can get the location of an attribute or uniform.不管规范怎么说,对于某些驱动程序,您必须先启用着色器,然后才能获取属性或制服的位置。 This may be what is causing your problems.这可能是导致您出现问题的原因。

In your code that would mean in your GSMesh::build method adding:在您的代码中,这意味着在您的 GSMesh::build 方法中添加:

shader->use();

Before:前:

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

Personally if the version of OpenGL that you are using has support for Vertex Attribute Indexes I'd use them instead.就个人而言,如果您使用的 OpenGL 版本支持顶点属性索引,我会改用它们。

In the vertex shader you could have something like:在顶点着色器中,你可以有这样的东西:

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

And then in your mesh class all you need is:然后在您的网格类中,您只需要:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM