OpenGL似乎没有读取我的顶点/索引

时间:2016-03-13 14:25:50

标签: c++ pointers opengl

我一直在关注this tutorial以学习OpenGL。我有一些有用的东西,但只有我使用全局变量:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>

// float vertices[] = {
//     -0.5f, -0.5f, 0.0f,
//      0.5f, -0.5f, 0.0f,
//      0.0f,  0.5f, 0.0f
// };

float rectVertices[] = {
     0.5f,  0.5f, 0.0f,  // Top Right
     0.5f, -0.5f, 0.0f,  // Bottom Right
    -0.5f, -0.5f, 0.0f,  // Bottom Left
    -0.5f,  0.5f, 0.0f   // Top Left 
};

uint rectIndices[] = {
    0, 1, 3,   // First Triangle
    1, 2, 3    // Second Triangle
};  

const GLchar* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"

    "void main() {\n"
        "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
    "}\n";

const GLchar* fragmentShaderSource = "#version 330 core\n"
    "out vec4 color;\n"

    "void main() {\n"
        "color = vec4(1.0, 0.5, 0.2, 1.0);\n"
    "}\n";

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

void finalize() {
    glfwTerminate();
}

void programExit(int code) {
    finalize();
    exit(code);
}

void enforce(int success, const char* msg, const char* info) {
    if (!success) {
        std::cerr << msg << info << std::endl;
        exit(-1);
    }
}

// Initialise

// GLFW and OpenGL
void initialiseGLFW(int vMajor, int vMinor) {
    // Initialising GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, vMajor);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, vMinor);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
}

// Window Creation
GLFWwindow* createWindow(int width, int height, const char* title) {
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
    enforce(window != nullptr, "Failed to create GLFW window", nullptr);
    return window;
}

void initialiseGLEW(bool experimental) {
    glewExperimental = experimental;
    enforce(glewInit() == GLEW_OK, "Failed to initialise GLEW", nullptr);
}

GLFWwindow* initialise(int width, int height, const char* title) {
    initialiseGLFW(3, 3);

    // Creating GLFW Window
    GLFWwindow* window = createWindow(width, height, title);
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);

    // Initialising GLEW
    initialiseGLEW(true);
    glViewport(0, 0, 800, 600);

    return window;
}

// Creating Shaders

void checkCompilationError(uint shader) {
    int success;
    char infoLog[512];

    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    glGetShaderInfoLog(shader, 512, nullptr, infoLog);
    enforce(success, "Shader compilation error: ", infoLog);
}

void checkLinkingError(uint program) {
    int success;
    char infoLog[512];

    glGetProgramiv(program, GL_LINK_STATUS, &success);
    glGetProgramInfoLog(program, 512, nullptr, infoLog);
    enforce(success, "Program linking error: ", infoLog);
}

uint compileShader(GLenum type, const char* source, ushort count, int* lengths) {
    uint shader = glCreateShader(type);
    glShaderSource(shader, count, &source, lengths);
    glCompileShader(shader);
    checkCompilationError(shader);
    return shader;
}

uint createProgram(uint vShader, uint fShader) {
    uint program = glCreateProgram();
    glAttachShader(program, vShader);
    glAttachShader(program, fShader);
    glLinkProgram(program);
    checkLinkingError(program);
    return program;
}

// Subprocedure specific to this program
uint initialiseShaders(const char* vsSource, const char* fsSource) {

    // Initialising shaders
    uint vShader = compileShader(GL_VERTEX_SHADER, vsSource, 1, nullptr);
    uint fShader = compileShader(GL_FRAGMENT_SHADER, fsSource, 1, nullptr);

    // Link program
    GLuint shaderProgram = createProgram(vShader, fShader);

    // clean up
    glDeleteShader(vShader);
    glDeleteShader(fShader);

    return shaderProgram;
}

void configureVBO(float* vertices) {
    for (int i = 0; i < 12; i++) std::cout << vertices[i] << std::endl;
    glBufferData(
        GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW
    );
    // Tell OpenGL how to interpret the vertices
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*) 0);
    glEnableVertexAttribArray(0);
}

void configureEBO(uint* indices) {
    for (int i = 0; i < 6; i++) std::cout << indices[i] << std::endl;
    glBufferData(
        GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW
    );
}

uint intialiseVAO(float* vertices, uint* indices) {
    uint VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        configureVBO(vertices);

        if (indices != nullptr) {
            glGenBuffers(1, &EBO);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
            configureEBO(indices);
        }
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    return VAO;
}

void execGameLoop(GLFWwindow* window, uint shaderProgram, uint VAO) {
    while(!glfwWindowShouldClose(window)) {
        glfwPollEvents();

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Set the program to be used
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glfwSwapBuffers(window);
    }
}

int main() {

    // Config
        int width = 800, height = 800;
        const char* title = "Learn OpenGL";


    // Initialise GLFW and GLEW
    GLFWwindow* window = initialise(width, height, title);

    // Initialise Shader program
    uint shaderProgram = initialiseShaders(vertexShaderSource, fragmentShaderSource);

    // Configuring VAO, VBO and EBO
    uint VAO = intialiseVAO(rectVertices, rectIndices);

    execGameLoop(window, shaderProgram, VAO);

    finalize();
    return 0;
}

我的问题特别与:

有关
void configureVBO(float* vertices) {
    for (int i = 0; i < 12; i++) std::cout << vertices[i] << std::endl;
    glBufferData(
        GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW
    );
    // Tell OpenGL how to interpret the vertices
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*) 0);
    glEnableVertexAttribArray(0);
}

void configureEBO(uint* indices) {
    for (int i = 0; i < 6; i++) std::cout << indices[i] << std::endl;
    glBufferData(
        GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW
    );
}

在使用rectVertices/Indices全局变量时按预期工作,但在作为参数传递时不起作用。每个方法中的for循环打印数组,它们包含我期望的值。为什么OpenGL在使用全局变量时绘制矩形,但在使用局部参数时却不是这样?

1 个答案:

答案 0 :(得分:4)

void configureVBO(float* vertices) {
    for (int i = 0; i < 12; i++) std::cout << vertices[i] << std::endl;
    glBufferData(
        GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW
    );
    // Tell OpenGL how to interpret the vertices
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*) 0);
    glEnableVertexAttribArray(0);
}

这里的问题是sizeof(vertices)没有做你认为它做的事情。它没有告诉你数组中有多少个顶点 - 相反,它告诉你vertices类型的变量占用了多少字节。由于vertices是指针,因此根据您的系统,该数字可能为4或8 - 但重要的是,它与您实际打算上传的顶点数无关。

相反,您需要做的是告诉OpenGL您希望缓冲区有多大(以字节为单位)。您按number of vertices * sizeof(vertex_type)计算出来。因此,在您的情况下,12 * sizeof(float)

通常,您需要在函数中包含第二个参数,其中包括顶点数,或者使用std::vector<float>来保存顶点数据。例如,使用vector,这将成为:

void configureVBO(const std::vector<float>& vertices) {
    for (auto v : vertices) std::cout << v << "\n";
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float),
                 vertices.data(), GL_STATIC_DRAW);
    // etc...
}

使用全局变量时代码工作的原因与C ++将数组传递给函数的方式有关(反过来,它继承自C)。当你传递一个数组时,函数收到的只是一个指针到数组的开头 - 有关数组长度的信息已经丢失,所以sizeof(vertices)可以&#39 ;告诉你数组实际上有多长。但是,如果使用全局变量,那么即使在float vertices[12]函数内,编译器也可以看到定义configureVBO,因此在这种情况下sizeof()将执行您期望的操作。

对于开始使用C和C ++的人来说,这是一个非常常见的混淆。我真的建议使用std::vector代替(由于很多原因,这只是一个),但它也值得一读数组和指针如何在C和C ++中工作。