我一直在关注 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/