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

标签 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 会绘制矩形,而在使用局部参数时却不会?

最佳答案

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)无法告诉您数组实际有多长。但是,如果您使用全局变量,那么编译器可以看到定义 float vertices[12]即使在 configureVBO 内功能,所以在那种情况下sizeof()会如您所愿。

对于刚开始使用 C 和 C++ 的人来说,这是一个非常常见的混淆。我真的建议使用 std::vector相反(出于多种原因,这只是其中一个原因),但也值得一读数组和指针在 C 和 C++ 中的工作方式。

关于c++ - OpenGL 似乎没有读取我的顶点/索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35971435/

相关文章:

c++ - OpenGL 透明效果在 Meego 上显示的很糟糕

C++队列多线程等待作业完成

c++可能的空指针取消引用

c - 从C中的指针数组中删除元素

opengl - Piston 中的 InvalidEnum 错误

c++ - OpenGL 更新顶点数组/缓冲区

c++ - QDialog - 更改默认标志以排除?按钮

c++ - 未指定字符串化运算符的评估顺序

c++ - ‘nullptr’ 之前的预期不合格 ID

C - 可以提升变量位置吗?