I'm trying to implement model loading, but I'm stuck with one problem. When i try to draw a mesh (a single textured quad written by hand for test purposes) for some reason duplicated data associated with the first vertex is passed to the vertex shader
(RenderDoc screen).
Here is an example using a stripped down version of my class that still exhibits this behaviour:
#define TEST_MESH
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
struct Vertex {
float position[3];
float color[3];
};
class Mesh {
public:
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices);
~Mesh();
Mesh(const Mesh&) = delete;
Mesh& operator=(const Mesh&) = delete;
Mesh(Mesh&& other);
Mesh& operator=(Mesh&& other);
void Draw(unsigned int program_id);
std::vector<Vertex> m_Vertices;
std::vector<unsigned int> m_Indices;
private:
unsigned int m_VAO, m_VBO, m_EBO;
void Setup();
void Release();
};
int main() {
//GLFW INIT
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//GLFW Window setup
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Mesh Test", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//GLAD INIT
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//Shader setup:
const char* vertex = "#version 460 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aCol;\n"
"out vec3 vColor;\n"
"void main() {\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" vColor = aCol;\n"
"}\0";
const char* fragment = "#version 460 core\n"
"in vec3 vColor;\n"
"out vec4 FragColor;\n"
"void main() {\n"
" FragColor = vec4(vColor, 1.0);\n"
"}\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertex, NULL);
glCompileShader(vertexShader);
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragment, NULL);
glCompileShader(fragmentShader);
unsigned int program;
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//Data:
float floats[24] = {
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 1.0f, 1.0f ,0.0f };
unsigned int uints[6] = { 0, 1, 2, 2, 3, 0 };
#ifdef TEST_MESH
//Mesh assembly
std::vector<Vertex> vertices;
for (int i = 0; i < 4; i++)
vertices.push_back(Vertex{ floats[6 * i], floats[6 * i + 1], floats[6 * i + 2],
floats[6 * i + 3], floats[6 * i + 4], floats[6 * i + 5] });
std::vector<unsigned int> indices{ 0, 1, 2, 2, 3, 0 };
Mesh mesh(vertices, indices);
#else
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(floats), &floats[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uints), &uints[0], GL_STATIC_DRAW);
//Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//Colors
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
#endif
//Render loop
while (!glfwWindowShouldClose(window)) {
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
#ifdef TEST_MESH
mesh.Draw(program);
#else
glUseProgram(program);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
#endif
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices) {
m_Vertices = vertices;
m_Indices = indices;
Setup();
}
Mesh::Mesh(Mesh&& other)
: m_VAO(other.m_VAO), m_VBO(other.m_VBO), m_EBO(other.m_EBO)
, m_Vertices(other.m_Vertices), m_Indices(other.m_Indices)
{
other.m_VAO = 0;
other.m_VBO = 0;
other.m_EBO = 0;
}
Mesh& Mesh::operator=(Mesh&& other) {
if (this != &other) {
Release();
std::swap(m_VAO, other.m_VAO);
std::swap(m_VBO, other.m_VBO);
std::swap(m_EBO, other.m_EBO);
m_Vertices = other.m_Vertices;
m_Indices = other.m_Indices;
}
return *this;
}
Mesh::~Mesh() {
Release();
}
void Mesh::Release() {
glDeleteVertexArrays(1, &m_VAO);
glDeleteBuffers(1, &m_VBO);
glDeleteBuffers(1, &m_EBO);
}
void Mesh::Setup() {
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
glGenBuffers(1, &m_EBO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), &m_Vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_Indices.size() * sizeof(unsigned int), &m_Indices[0], GL_STATIC_DRAW);
//Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
//Colors
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Mesh::Draw(unsigned int program_id) {
glUseProgram(program_id);
glBindVertexArray(m_VAO);
glDrawElements(GL_TRIANGLES, m_Indices.size(), GL_UNSIGNED_INT, 0);
}
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int
height) {
glViewport(0, 0, width, height);
}
In your Mesh::Setup you have this line at the end:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
This unbinds your EBO from your VAO. Your implementation seems to treat undefined reads as zero, therefore all you see is the 0th vertex replicated six times.
Once you bound the EBO you don't need to unbind it.
(Note: unbinding GL_ARRAY_BUFFER, on the other hand, is OK. This is because the VBO is attached to the VAO at the time you call any of the *Pointer functions, not at the time you bind it to GL_ARRAY_BUFFER.)
(Note: Since you use the latest OpenGL version, I strongly recommend that you use the Direct State Access (DSA) functions. In this case you would bind the EBO with
glVertexArrayElementBuffer(m_VAO, m_EBO);
call, which I think would make the mistake much more obvious. See a quick reference of VAO state and the recommended functions to use to manipulate it.)
Related
As the title says, I'm trying to draw a square from two triangles for class. I've tried everything I can think of but I cannot figure out why it just displays a black screen. Here is my code so far. I have the project and libraries set up correctly. I've looked over it a dozen times and can't seem to find the issue.
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
static unsigned int CompileShader(unsigned int type, const std::string& source) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
return id;
}
static unsigned int CreateShader(const std::string& vrtxShader, const std::string& fragShader) {
unsigned int program = glCreateProgram();
//compile shaders
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vrtxShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragShader);
//attach shaders to program
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
//delete shaders
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
//sets up GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Module 3", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
//Initialize GLEW
if (glewInit() != GLEW_OK)
std::cout << "Error!" << std::endl;
float vertPositions[] = {
// index 0
-0.5f, -0.5f, 0.0f,
1.0f, 0.0f, 0.0f,
// index 1
-5.0f, 0.5f, 0.0f,
0.0f, 0.0f, 1.0f,
// index 2
0.5f, -0.5f, 0.0f,
0.0f, 1.0f, 0.0f,
// index 3
0.5f, 0.5f, 0.0f,
1.0f, 0.0f, 0.0f,
};
float indices[] = { 0, 1, 2, 1, 2, 3 };
//creates vertex buffer object
unsigned int vbo;
unsigned int ebo;
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertPositions), vertPositions, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//attribute location and layout to gpu.
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
// Vertex Shader Program Source Code
std::string vertexShaderSource = "#version 440 core\n"
"layout (location = 0) in vec4 aPos;\n"
"layout (location = 1) in vec4 aColor;\n"
"out vec4 colorOut;\n"
"void main()\n"
"{\n"
" gl_Position = aPos;\n"
" colorOut = aColor;\n"
"}\n\0";
// Fragment Shader Program Source Code
std::string fragmentShaderSource = "#version 440 core\n"
"in vec4 colorOut;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
"fragColor = colorOut;\n"
"}\n\0";
unsigned int shader = CreateShader(vertexShaderSource, fragmentShaderSource);
glUseProgram(shader);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
//draw the shapes
glDrawElements(GL_TRIANGLES, 6, GL_FLOAT, nullptr);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Why using a core profile OpenGL Context (GLFW_OPENGL_CORE_PROFILE) it is mandatory to create a Vertex Array Object. There is no default VAO when using a core profile.
e.g.:
unsigned int vao, vbo, ebo;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertPositions), vertPositions, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
Further more the type of the indices must be integral. e.g:
unsigned int indices[] = { 0, 1, 2, 1, 2, 3 };
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
I have written a very basic test setup to render a quad with glfw/glad.
I would expext it to draw a black quad in the middle of the window.
#include <iostream>
#include <array>
#include <cinttypes>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
using uint32 = std::uint32_t;
using gl_shader_id = GLuint;
gl_shader_id get_shader() {
constexpr auto vertex_shader_source = R"(
#version 460 core
layout (location = 0) in vec3 position;
void main() {
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}
)";
constexpr auto fragment_shader_source = R"(
#version 460 core
out vec4 color;
void main() {
color = vec4(0.0, 0.0, 0.0, 1.0f);
}
)";
const auto vertex_shader = glCreateShader(GL_VERTEX_SHADER);
const auto fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
auto success = 0;
glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success) {
auto info_log = std::string{};
info_log.reserve(512);
glGetShaderInfoLog(vertex_shader, 512, nullptr, info_log.data());
std::cout << info_log << '\n';
assert(false); // Vertex shader compilation failed
}
glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr);
glCompileShader(fragment_shader);
if (!success) {
auto info_log = std::string{};
info_log.reserve(512);
glGetShaderInfoLog(fragment_shader, 512, nullptr, info_log.data());
std::cout << info_log << '\n';
assert(false); // Vertex shader compilation failed
}
const auto shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
glDetachShader(shader_program, vertex_shader);
glDetachShader(shader_program, fragment_shader);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return shader_program;
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
auto handle = glfwCreateWindow(800, 600, "Hello World", nullptr, nullptr);
glfwMakeContextCurrent(handle);
gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress));
const auto shader_id = get_shader();
const auto vertices = std::array<glm::vec3, 4>{
glm::vec3{ -0.5f, -0.5f, 0.0f },
glm::vec3{ -0.5f, 0.5f, 0.0f },
glm::vec3{ 0.5f, -0.5f, 0.0f },
glm::vec3{ 0.5f, 0.5f, 0.0f }
};
const auto indices = std::array<uint32, 6>{
0, 1, 2,
1, 3, 2
};
auto vertex_array = 0u;
auto vertex_buffer = 0u;
auto index_buffer = 0u;
glGenVertexArrays(1, &vertex_array);
glBindVertexArray(vertex_array);
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
glEnableVertexArrayAttrib(vertex_array, 0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), nullptr);
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint32), indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(handle)) {
glfwPollEvents();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vertex_array);
glUseProgram(shader_id);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, nullptr);
glUseProgram(0);
glBindVertexArray(0);
glfwSwapBuffers(handle);
}
glfwDestroyWindow(handle);
glfwTerminate();
return 0;
}
The program and the shader code compile with no error/warnings.
When i execute the program i get the window which is cleared with the right color.
But the quad that i specified with the vertices and indices is not showing up.
I figgured it out after some fiddeling.
For anyone stumbeling uppon this problem.
You have to unbing the vertex array before unbinding the vertex buffer and index buffer.
Otherwise the binding stored inside the vertex array are going to be set to 0 and this nothing can be drawn
This question already has an answer here:
Why is the sprite not rendering in OpenGL?
(1 answer)
Closed 2 years ago.
I'm trying to render a square using two triangles, and then applying some transformations, but for whatever reason it isn't showing up. Here is the code:
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
#define WINDOW_TITLE "Modern OpenGL 3D Cube"
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version "\n" #Source
#endif
GLint shaderProgram, windowWidth = 800, windowHeight = 600;
GLuint VBO, VAO, EBO, texture;
void UResizeWindow(int, int);
void URenderGraphics(void);
void UCreateShader(void);
void UCreateBuffers(void);
const GLchar* vertexShaderSource = GLSL(330,
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
out vec3 mobileColor;
uniform mat4 shaderTransform;
void main() {
gl_Position = shaderTransform * vec4(position, 1.0f);
mobileColor = color;
});
const GLchar* fragmentShaderSource = GLSL(330,
in vec3 mobileColor;
out vec4 gpuColor;
void main() {
gpuColor = vec4(mobileColor, 1.0);
});
//main program
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(windowWidth, windowHeight);
glutCreateWindow(WINDOW_TITLE);
glutReshapeFunc(UResizeWindow);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
cout << "Failed to initialize GLEW" << endl;
return -1;
}
UCreateShader();
UCreateBuffers();
glUseProgram(shaderProgram);
glClearColor(0, 0, 0, 1);
glutDisplayFunc(URenderGraphics);
glutMainLoop();
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
return 0;
}
void UResizeWindow(int w, int h) {
windowWidth = w;
windowHeight = h;
glViewport(0, 0, windowWidth, windowHeight);
}
void URenderGraphics(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO);
glm::mat4 currentTransform;
currentTransform = glm::translate(currentTransform, glm::vec3(0.0f, 0.5f, 0.0f));
currentTransform = glm::rotate(currentTransform, 45.0f, glm::vec3(0.0f, 0.0f, 1.0f));
currentTransform = glm::scale(currentTransform, glm::vec3(0.5f, 0.5f, 0.5f));
GLuint transformLocation = glGetUniformLocation(shaderProgram, "shaderTransform");
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, glm::value_ptr(currentTransform));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glutSwapBuffers();
}
void UCreateShader() {
GLint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void UCreateBuffers() {
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1, 0, 0, //top right vertex 0
0.5f, -0.5f, 0.0f, 0, 1, 0, //bottom right vertex 1
-0.5f, -0.5f, 0.0f, 0, 0, 1, //bottom left vertex 2
-0.5f, 0.5f, 0.0f, 1, 0, 1 //top left vertex 3
};
GLuint indices[] = {
0, 1, 3, //triangle 1
1, 2, 3 //triangle 2
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
It compiles and runs just fine, but it only opens a blank window. No graphics are shown on that window like it normally would. The output is supposed to look like a slightly rotated square rotated about its z-axis, but nothing appears at all. All help appreciated.
Some common things I check, when I get the infamous blank screen:
forgetting to call glUseProgram(shaderID) before you start passing uniforms (done)
pass the model matrix as an identity matrix.
double checking if the VBO/EBO are laid out in memory correctly (also, simplifying them during this step, ie. removing the color attribute, just pass position, and hard code the color in the fragment shader)
doing some error checking to see if there is a problem with the shader compilation using glGetShaderInfoLog and glGetProgramInfoLog.
The model matrix variable glm::mat4 currentTransform has to be initialized by the Identity matrix.
The OpenGL Mathematics (GLM) API documentation is based on OpenGL Shading Language (GLSL) and refers to The OpenGL Shading Language specification.
5.4.2 Vector and Matrix Constructors
[...] If there is a single scalar parameter to a matrix constructor, it is used to initialize all the components on the matrix's diagonal, with the remaining components initialized to 0.0.
An Identity matrix can be initialized by the single parameter 1.0:
glm::mat4 currentTransform;
glm::mat4 currentTransform(1.0f);
An OpenGL project can't display any object anymore. I tried to remake everything from scratch but it still doesn't works.
Main Code
#include <vector>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <imgui.h>
#include <imgui_impl_glfw_gl3.h>
#include "Loader.h"
void on_error(int error, const char* description)
{
std::cout << "GLFW error " << error << " : \"" << description << "\"" << std::endl;
}
int main()
{
//Init glfw
glfwSetErrorCallback(on_error);
if (!glfwInit()) return -1;
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//Init window
auto window = glfwCreateWindow(1920, 1080, "gl_Crane", NULL, NULL);
if (!window) { glfwTerminate(); return -1; }
glfwMakeContextCurrent(window);
//Init glew
glewExperimental = true;
if (glewInit() != GLEW_OK) { glfwTerminate(); return -1; }
//Some opengl options
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEBUG_OUTPUT);
glDepthFunc(GL_LESS);
//glEnable(GL_CULL_FACE);
//matrices
std::vector<glm::vec3> vertices = {
{-.2f, -.2f, 0}, {0, .2f, 0}, {.2f, -.2f, 0}
};
std::vector<glm::vec3> colors = {
{1, 0, 0}, {0, 1, 0}, {0, 0, 1}
};
std::vector<GLushort> indexes = {
0, 1, 2
};
//vertexArray
GLuint vertex_array;
glGenVertexArrays(1, &vertex_array);
glBindVertexArray(vertex_array);
//vertexbuffer
GLuint vertex_buffer;
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), nullptr);
//colorbuffer
GLuint color_buffer;
glGenBuffers(1, &color_buffer);
glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * colors.size(), colors.data(), GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), nullptr);
//indexbuffer
GLuint index_buffer;
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indexes.size(), indexes.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
//Init shader
auto shader_program = new ShaderProgram;
shader_program->initFromFiles("../Crane/simple.vert", "../Crane/simple.frag");
//shader_program->addUniform("MVP");
ImGui_ImplGlfwGL3_Init(window, true);
glfwSwapInterval(1);
while (!glfwWindowShouldClose(window))
{
ImGui_ImplGlfwGL3_NewFrame();
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
//maj viewport
int display_w, display_h;
glfwGetFramebufferSize(window, &display_h, &display_w);
glViewport(0, 0, display_w, display_h);
//clear screen
glClearColor(.2f, .2f, .2f, 0);
glClear(GL_COLOR_BUFFER_BIT);
//draw stuff
shader_program->use();
glBindVertexArray(vertex_array);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//auto mvp = glm::mat4(1);
//glUniformMatrix4fv(shader_program->uniform("MVP"), 1, GL_FALSE, glm::value_ptr(mvp));
glDrawElements(GL_TRIANGLES, indexes.size(), GL_UNSIGNED_SHORT, nullptr);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
shader_program->disable();
ImGui::Render();
glfwSwapBuffers(window);
glfwPollEvents();
}
shader_program->disable();
ImGui_ImplGlfwGL3_Shutdown();
glfwTerminate();
return 0;
}
Fragment shader
#version 430
in vec3 fColors;
out vec4 fragColors;
void main()
{
fragColors = vec4(fColors, 1.0);
}
Vertex shader
#version 430
layout (location = 0) in vec4 vertexPosition;
layout (location = 1) in vec3 vertexColor;
out vec3 fColors;
void main()
{
fColors = vertexColor;
gl_Position = vertexPosition;
}
Additionally, I use the shader loader from here :
r3dux shader loader
In your program the Depth Test (glEnable(GL_DEPTH_TEST)).
The depth of a fragment is stored in a separate buffer. This buffer has to be cleared too, at the begin of every frame, as you do it with the color buffer. See glClear:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Of course, if you would disable the depth test, then you would "see" the triangle, too.
I'm learning OpenGL and I set up a Mesh class to render my shapes. Drawing only works without
glBindVertexArray(0);
at the end so I'm guessing I messed up something but I can't figure it out.
Here is the code: main.cpp
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <iostream>
#include "mesh.h"
#define WIDTH 1280
#define HEIGHT 720
// Vertex shader
const char* vs = "\n\
#version 330 \n\
layout (location = 0) in vec2 position; \n\
layout (location = 1) in vec3 color; \n\
out vec3 Color; \n\
\n\
void main() { \n\
Color = color; \n\
gl_Position = vec4(position, 0.0, 1.0); \n\
} \n\
\n\
";
// Fragment shader
const char* fs = "\n\
#version 330 \n\
in vec3 Color; \n\
out vec4 fragColor; \n\
\n\
void main() { \n\
fragColor = vec4(Color, 1.0); \n\
} \n\
";
bool checkShader(GLuint shader) {
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char buffer[512];
glGetShaderInfoLog(shader, 512, NULL, buffer);
std::cout << "Error compiling shader:" << buffer << std::endl;
return false;
}
return true;
}
bool compileShaders() {
// compile the vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vs, NULL);
glCompileShader(vertexShader);
if (!checkShader(vertexShader))
return false;
// compile the fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fs, NULL);
glCompileShader(fragmentShader);
if (!checkShader(fragmentShader))
return false;
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
return true;
}
int main() {
bool success = true;
bool running = true;
SDL_Window* window;
SDL_GLContext context;
// Initialize SDL/Glew
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "Video initialization failed:" << SDL_GetError() << std::endl;
success = false;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
window = SDL_CreateWindow("Game Title", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN |
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
context = SDL_GL_CreateContext(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "Problem initializing GLEW." << std::endl;
success = false;
}
SDL_Event e;
// Mesh setup
float vertices[] = { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f,-0.5f, 0.0f, 1.0f, 0.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f };
float vertices2[] = { -1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
GLuint elements[] = { 0, 1, 2 };
Mesh triangle(vertices, elements, sizeof(vertices), sizeof(elements));
Mesh triangle2(vertices2, elements, sizeof(vertices2), sizeof(elements));
if (!compileShaders())
success = false;
if (!success) {
std::cerr << "A problem ocurred during initialization, will exit." << std::endl;
exit(1);
}
while (running) {
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT)
running = false;
if (e.type == SDL_KEYDOWN)
if (e.key.keysym.sym == SDLK_ESCAPE)
running = false;
}
glClearColor(0.0f, 1.0f, 0.5f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
triangle.draw();
triangle2.draw();
SDL_GL_SwapWindow(window);
SDL_Delay(1);
}
SDL_GL_DeleteContext(context);
SDL_Quit();
return 0;
}
mesh.h
#ifndef MESH_H
#define MESH_H
#include <GL/glew.h>
class Mesh {
private:
GLuint IBO;
GLuint VBO;
GLuint VAO;
float* vertices;
GLuint* indices;
int sizeVertices;
int sizeIndices;
public:
Mesh(float* vertices, GLuint* indices, int sizeVertices, int sizeIndices);
void draw();
};
#endif //MESH_H
mesh.cpp
#include "mesh.h"
#define POSITION 0
#define COLOR 1
Mesh::Mesh(float* vertices, GLuint* indices, int sizeVertices, int sizeIndices) {
this->vertices = vertices;
this->indices = indices;
this->sizeVertices = sizeVertices;
this->sizeIndices = sizeIndices;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &IBO);
}
void Mesh::draw() {
glEnableVertexAttribArray(POSITION);
glVertexAttribPointer(POSITION, 2, GL_FLOAT, GL_FALSE,5*sizeof(float), 0);
glEnableVertexAttribArray(COLOR);
glVertexAttribPointer(COLOR, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(2*sizeof(float)));
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeVertices, vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeIndices, indices, GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
//glBindVertexArray(0); If I uncomment this, the mesh is not displayed
}
The calls to glVertexAttribPointer pointer refer to the VAO and VBO bound at the time of calling. In your code you're calling glVertexAttribPointer before the VAO and the VBO are bound. So the first iteration round those calls will fail. Without unbinding the VAO/VBO the next iteration the VAO/VBO state will happen (by circumstance) to the more or less right; actually you've swapped the VAO/VBO between the two triangle instances.
Update – fixed code
Mesh::Mesh(float* vertices, GLuint* indices, int sizeVertices, int sizeIndices) {
this->vertices = vertices;
this->indices = indices;
this->sizeVertices = sizeVertices;
this->sizeIndices = sizeIndices;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &IBO);
/* VAOs contain ARRAY_BUFFERS */
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeVertices, vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(POSITION);
glVertexAttribPointer(POSITION, 2, GL_FLOAT, GL_FALSE,5*sizeof(float), 0);
glEnableVertexAttribArray(COLOR);
glVertexAttribPointer(COLOR, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(2*sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(VAO);
/* ELEMENT_ARRAY_BUFFERS are not contained in VAOs */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeIndices, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void Mesh::draw() {
/* VAOs keep the glVertexAttribPointer bindings,
* so it's sufficient to just bind the VAO;
* no need for binding the VBOs (as long as you don't
want to change the pointers). */
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
/* Need to bind the ELEMENT_ARRAY_BUFFER though */
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}