为什么我可以使用OpenGL着色器类,而不是VAO类?

时间:2015-09-02 01:22:58

标签: c++ macos opengl

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

着色器不返回任何错误,VAO和着色器是有效的OpenGL对象。

完整回购(见简化版底部) https://github.com/nunziotocci/stackoverflow-question-1

更新

问题在于这一行:

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

正如评论中提到的@BDL,我想到了,我意识到,它应该是:

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

2 个答案:

答案 0 :(得分:2)

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

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

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

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

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

答案 1 :(得分:1)

尽管规范说明,对于某些驱动程序,您必须先启用着色器,然后才能获得属性或制服的位置。这可能是造成问题的原因。

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

std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
    os << "[";
    auto first = true;
    for (const auto &i : v) {
        if (!first) {
            os << " ";
        } else {
            first = false;
        }
        os << i;
    }
    os << "]";
    return os;
}

在:

shader->use();

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

在顶点着色器中,您可以使用以下内容:

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

然后在您的网格类中,您只需要:

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