I'm trying to create a Mesh class that can generate a model for me and then calling that model in the createTriangle
function. However, whenever I try creating the meshObj1
and meshObj2
and then pushing it to the meshVector
, it does not want to render? Why is this happening?
Mesh.h
#ifndef MESH_H
#define MESH_H
#include "GL/glew.h"
class Mesh {
public:
Mesh();
~Mesh();
void createMesh(GLfloat *vertices, unsigned int *indices, unsigned int numOfVertices, unsigned int numOfIndices);
void renderMesh();
void clearMesh();
private:
GLuint VAO, VBO, IBO;
GLsizei indexCount;
};
#endif
Mesh.cpp
#include "Mesh.h"
Mesh::Mesh() {
VAO = 0;
VBO = 0;
IBO = 0;
indexCount = 0;
}
Mesh::~Mesh() {
clearMesh();
}
void Mesh::createMesh(GLfloat* vertices, unsigned int* indices, unsigned int numOfVertices, unsigned int numOfIndices) {
indexCount = numOfIndices;
//Binding
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
//Information
//VBO Information
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0] * numOfVertices), vertices, GL_STATIC_DRAW);
//IBO Information
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * numOfIndices, indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
//Unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Mesh::renderMesh() {
//Binding
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
//Rendering
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
//Unbinding
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Mesh::clearMesh() {
if (VAO != 0) {
glDeleteVertexArrays(1, &VAO);
VAO = 0;
}
if (VBO != 0) {
glDeleteBuffers(1, &VBO);
VBO = 0;
}
if (IBO != 0) {
glDeleteBuffers(1, &IBO);
IBO = 0;
}
indexCount = 0;
}
Main.cpp
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include <iostream>
#include <vector>
#include <memory>
#include "Mesh.h"
//Window dimensions
const GLint SCREEN_WIDTH = 1280, SCREEN_HEIGHT = 900;
GLuint shader, uniformModel, uniformProjection;
bool isMovingLeft = true;
float triOffset = 0.f;
float triMaxOffset = 0.7;
float triIncrement = 0.005;
std::vector<Mesh*> meshVector;
//Vertex shader
static const char* vShader = " \n\
#version 460 \n\
\n\
layout(location = 0) in vec3 pos; \n\
\n\
out vec4 vColor; \n\
\n\
uniform mat4 model; \n\
uniform mat4 projection; \n\
\n\
void main() { \n\
gl_Position = projection * model * vec4(pos, 1.0); \n\
vColor = vec4(clamp(pos, 0.f, 1.f), 1.f); \n\
}; \n\
";
//Fragment shader
static const char* fShader = " \n\
#version 460 \n\
\n\
in vec4 vColor; \n\
\n\
out vec4 color; \n\
\n\
void main() { \n\
color = vColor; \n\
}; \n\
";
void createTriangle() {
unsigned int indices[] = {
0, 3, 1,
1, 3, 2,
2, 3, 0,
0, 1, 2
};
//Points of the triangle
GLfloat vertices[] = {
-1.f, -1.f, 0.f,
0.f, -1.f, 1.f,
1.f, -1.f, 0.f,
0.f, 1.f, 0.f
};
Mesh* meshObj1 = new Mesh();
meshObj1->createMesh(vertices, indices, 12, 12);
meshVector.push_back(meshObj1);
Mesh* meshObj2 = new Mesh();
meshObj2->createMesh(vertices, indices, 12, 12);
meshVector.push_back(meshObj2);
}
void addShader(GLuint theProgram, const char* shaderCode, GLenum shaderType) {
GLuint theShader = glCreateShader(shaderType);
const GLchar* theCode[1];
theCode[0] = shaderCode;
GLint codeLength[1];
codeLength[0] = strlen(shaderCode);
glShaderSource(theShader, 1, theCode, codeLength);
glCompileShader(theShader);
//Getting error information for linking
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetShaderiv(theShader, GL_COMPILE_STATUS, &result);
if (result != GL_TRUE) {
glGetShaderInfoLog(theShader, sizeof(eLog), NULL, eLog);
std::cout << "Error compiling the " << shaderType << ' ' << eLog << '\n';
}
glAttachShader(theProgram, theShader);
}
void compileShaders() {
shader = glCreateProgram();
if (shader != GL_TRUE) {
std::cout << "Shader program error!\n";
}
//Adding shaders
addShader(shader, vShader, GL_VERTEX_SHADER);
addShader(shader, fShader, GL_FRAGMENT_SHADER);
//Getting error information for linking
GLint result = 0;
GLchar eLog[1024] = { 0 };
//Linking shader
glLinkProgram(shader);
//Shader linking status
glGetProgramiv(shader, GL_LINK_STATUS, &result);
if (result != GL_TRUE) {
glGetProgramInfoLog(shader, sizeof(eLog), NULL, eLog);
std::cout << "Error linking program! " << eLog << '\n';
}
//Gets shader ID and then binds it with the variable inside shader
uniformModel = glGetUniformLocation(shader, "model");
uniformProjection = glGetUniformLocation(shader, "projection");
}
int main() {
//Initialize GLFW
if (glfwInit() != GLFW_TRUE) {
std::cout << "GLFW init failed\n";
glfwTerminate();
}
//Setup GLFW window properties
//OpenGL version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); //Large version
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); //Small version
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //Detects any old OpenGL code, this will throw an error
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //Allows forward compatibility (between differnt OS)
//Creating window
GLFWwindow* window;
window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "OpenGL Test Window", NULL, NULL);
glfwSetWindowPos(window, 250, 100);
if (window == NULL) {
std::cout << "GLFW window creation failed!\n";
glfwTerminate();
}
//Get buffer size information
int bufferWidth, bufferHeight;
glfwGetFramebufferSize(window, &bufferWidth, &bufferHeight);
//Set context for GLEW to use (can change between which window)
glfwMakeContextCurrent(window);
//Allow modern extension features
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cout << "Glew init failed!\n";
glfwDestroyWindow(window);
glfwTerminate();
}
glEnable(GL_DEPTH_TEST);
//Setup viewport size
glViewport(0, 0, bufferWidth, bufferHeight);
createTriangle();
compileShaders();
glm::mat4 projection = glm::perspective(45.f, (GLfloat)bufferWidth / (GLfloat)bufferHeight, 0.1f, 100.f);
//Main game loop
while (!glfwWindowShouldClose(window)) {
//Get + Handle user input events
glfwPollEvents();
//Left-Right
if (isMovingLeft) {
triOffset += triIncrement;
}
else {
triOffset -= triIncrement;
}
if (abs(triOffset) >= triMaxOffset) {
isMovingLeft = !isMovingLeft;
}
//Clear window
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader);
//Matrix 4x4
glm::mat4 model(1.f);
model = glm::translate(model, glm::vec3(triOffset, 0.f, -2.5f));
model = glm::scale(model, glm::vec3(0.4f, 0.4f, 1.f));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(uniformProjection, 1, GL_FALSE, glm::value_ptr(projection));
meshVector[0]->renderMesh();
model = glm::mat4(1.f);
model = glm::translate(model, glm::vec3(-triOffset, 1.f, -2.5f));
model = glm::scale(model, glm::vec3(0.4f, 0.4, 1.f));
meshVector[1]->renderMesh();
glUseProgram(0);
glfwSwapBuffers(window);
}
}
I expect two pyramids to form with color.
The GL_ELEMENT_ARRAY_BUFFER
target binding is stored in the Vertex Array Object . See Index buffers .
This means, that the instruction
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
breaks the former binding of IBO
to the vertex array object VAO
. Remove this instruction from your code, to solve the issue.
Note, GL_ARRAY_BUFFER
and the GL_ELEMENT_ARRAY_BUFFER
behave differently. The current GL_ARRAY_BUFFER
binding is a global state, but the GL_ELEMENT_ARRAY_BUFFER
binding is stated in the current Vertex Array Object.
Also the GL_ARRAY_BUFFER
is stated in the state vector of the VAO, but this happens when glVertexAttribPointer
is called. When glVertexAttribPointer
is called, then the buffer which is currently bound to the target GL_ARRAY_BUFFER
is associated to the vertex attribute with the specified index.
That causes the difference in the behavior of GL_ELEMENT_ARRAY_BUFFER
and GL_ARRAY_BUFFER
. A VAO can only refer to 1 index (element) buffer, but it can refer to multiple array buffers. Each attribute (index) can be associated to a different buffer.
Before you render the 2nd mesh, you've the set the corresponding model matrix to the default uniform block of the installed program:
glUseProgram(shader);
glUniformMatrix4fv(uniformProjection, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 model(1.f);
model = glm::translate(model, glm::vec3(triOffset, 0.f, -2.5f));
model = glm::scale(model, glm::vec3(0.4f, 0.4f, 1.f));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
meshVector[0]->renderMesh();
model = glm::mat4(1.f);
model = glm::translate(model, glm::vec3(-triOffset, 1.f, -2.5f));
model = glm::scale(model, glm::vec3(0.4f, 0.4, 1.f));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model)); // <---
meshVector[1]->renderMesh();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.