Objects placed inside classes to be rendered with OpenGL - c++

I began to learn OpenGL about a week ago and I now want to create a mesh class. The code I'm about to show gives me a black screen (that's the color I fill it with).
I basically stripped the code from my main function and placed it inside a class, it worked inside main.
mesh.cpp
#include "mesh.h"
mesh::mesh(std::vector<GLfloat> vertices, std::vector<GLuint> indices)
{
this->vertices = vertices;
this->indices = indices;
glGenVertexArrays(1, &vertexArrayObject);
glGenBuffers(1, &vertexBuffer);
glGenBuffers(1, &triangleBuffer);
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(GLfloat), this->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), this->indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
}
mesh::~mesh()
{
glDeleteBuffers(1, &triangleBuffer);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(1, &vertexArrayObject);
}
void mesh::update(){
glBindVertexArray(vertexArrayObject);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
mesh.h
#ifndef MESH_H
#define MESH_H
#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
class mesh
{
public:
mesh(std::vector<GLfloat> vertices, std::vector<GLuint> triangles);
~mesh();
void update();
protected:
private:
GLuint vertexArrayObject, vertexBuffer, triangleBuffer;
std::vector<GLfloat> vertices;
std::vector<GLuint> indices;
};
#endif // MESH_H
According to this, this should be the correct way to do it (?).
BTW, all this code is a mashup from this and open.gl sites, here are the variables I pass into the constructor.
For the vertices:
std::vector<GLfloat> vertices = {
// Position Color Texcoords
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-left
};
and the indices:
std::vector<GLuint> elements = {
0, 1, 2,
2, 3, 0
};
Also please note that I changed the code snippets according to Anton's suggestions, that didn't seem to work

You have two problems that immediately come to mind:
this->triangles.size() * sizeof(GLfloat)
This problem will not affect anything because GLfloat has the same size as GLuint, but if that was not a typo, it indicates to me you may be thinking about the index buffer wrong.
Make this triangles.size () * sizeof (GLuint) for consistency.
glDrawElements(GL_TRIANGLES, this->vertices.size(), GL_UNSIGNED_INT, 0);
You have two separate lists in your class, vertices and triangles, and this call only cares about the size of one of those.
triangles is an array of indices that makes a list of triangles (3 indices per-triangle).
When you draw your elements array, you pass the number of elements in that list, not the number of vertices in your mesh.
While not technically a problem, I think you use this-> a little bit too much when you write your code.
It is useful when you have variables at one scope that have the same name as members in your class (which one could argue builds a case for inadequately descriptive names), but completely unnecessary in functions like mesh::~mesh(). It makes your code harder to read (for me anyway) because the lines are much longer.
Following the theme of inadequately descriptive names, by calling your index array "triangles" you have inadvertently limited this mesh class to drawing triangles. That might be a good variable name for a specialized constructor that builds a triangle mesh, but not so much for a class member. If you use indices instead, that gets rid of the name collision and the need to qualify everything using this->.

Related

Draw 2D HUD elements over 3D rendered scene

I searched for this and only found a post from 2014 asking about a somewhat similar situation. However, as I couldn't understand what was done there, I'm asking again, specifically for my implementation, hoping this sheds some light on the topic in general as well. I am fairly new to c++ and openGL, so please be so kkind as to excuse stupid mistakes.
I'm trying to implement a simple 2D HUD for my 3D game. Now, my game is fully rendered, due to having a bloom effect in my game, I even rendered my game on a screen quad.
What I now want to do ist placing a HUD over this rendered scene, I, however, can't seem to do that.
My screen quad for the game is drawn like so:
unsigned int quadVAO = 0;
unsigned int quadVBO;
void renderQuad()
{
if (quadVAO == 0)
{
float quadVertices[] = {
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// texCoords
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
// setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
What I tried to do, ist change my renderQuad method to a renderHUDquad one by basically just changing the dimensions of the quad to make it appear in the bottom left corner of the screen.
The code looks as follows:
unsigned int HUDquadVAO = 0;
unsigned int HUDquadVBO;
void renderHUDQuad()
{
if (HUDquadVAO == 0)
{
float HUDquadVertices[] = {
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// texCoords
0.0f, 0.02f,
0.0f, 0.0f,
0.2f, 0.0f,
0.0f, 0.02f,
0.2f, 0.0f,
0.2f, 0.02f
};
// setup plane VAO
glGenVertexArrays(1, &HUDquadVAO);
glGenBuffers(1, &HUDquadVBO);
glBindVertexArray(HUDquadVAO);
glBindBuffer(GL_ARRAY_BUFFER, HUDquadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(HUDquadVertices), &HUDquadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
}
glBindVertexArray(HUDquadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
As this only needs to be a small green quad, i.e. a health bar for the player, I was thinking about just assigning it a green texture or sth..
However, when drawing my two quads like this:
// Third pass = Combined bloom pictures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
bloomShader->use();
// Set uniform for multiple layout uniforms
bloomShader->setUniform("scene", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorAndLightBuffers[0]);
// Set uniform for multiple layout uniforms
bloomShader->setUniform("bloomBlur", 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, pingpongBuffer[horizontal == 0 ? 1 : 0]);
bloomShader->setUniform("bloom", bloom);
bloomShader->setUniform("exposure", exposure);
renderQuad();
renderHUDQuad();
// Swap buffers
glfwSwapBuffers(window);
I only get the HUD element without any of the stuff I drew before as if the rest of the screen was rendered black. I thought I could just add this to the old buffer, as there a way to do this?
You did screw up your GL state very badly:
void renderHUDQuad() {
if (HUDquadVAO == 0)
{
[...]
glGenVertexArrays(1, &quadVAO);
You actually use quadVAO in the rest of this function, so you overwrite your fullscreen quad by the smaller one, which means the rest of your scene will be scaled down to this quad from the next frame on...

OpenGL shader not drawing anything - bad sprite class

I'm trying to encapsulate OpenGL rendering in a renderer class.
I'm pretty sure my window class works fine (I've checked for errors) but I think the error is in my sprite class but I have no idea what it is.
This is my sprite class:
sprite_renderer.hpp
#ifndef SPRITE_RENDERER_H
#define SPRITE_RENDERER_H
#include <GL/glew.h>
#include "shader.hpp"
class SpriteRenderer
{
public:
SpriteRenderer(Shader &shader);
~SpriteRenderer();
void DrawSprite();
private:
Shader shader;
GLuint quadVAO;
void initRenderData();
};
#endif
sprite_renderer.cpp
#include "sprite_renderer.hpp"
SpriteRenderer::SpriteRenderer(Shader &shader)
{
this->shader = shader;
this->initRenderData();
}
SpriteRenderer::~SpriteRenderer()
{
glDeleteVertexArrays(1, &this->quadVAO);
}
void SpriteRenderer::DrawSprite()
{
this->shader.Use();
glBindVertexArray(this->quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
void SpriteRenderer::initRenderData()
{
GLuint VBO;
GLfloat vertices[] = {
// Pos
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
};
glGenVertexArrays(1, &this->quadVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(this->quadVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
I'm using it like this in my main.cpp:
int main()
{
Window window = Window();
Shader shader = ResourceManager::LoadShader("./assets/shaders/sprite.vert", "./assets/shaders/sprite.frag", "sprite");
SpriteRenderer* renderer = new SpriteRenderer(shader);
while (window.IsOpen())
{
window.BeginDraw();
renderer->DrawSprite();
window.EndDraw();
}
glfwTerminate();
return 0;
}
Where window.BeginDraw() and window.EndDraw() are just:
void Window::BeginDraw()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void Window::EndDraw()
{
glfwSwapBuffers(window);
glfwPollEvents();
}
Just to rule out the obvious, try sticking a print statement in the destructor of your Shader class. Judging by the design of your Shader class, you should find it extremely easy to end up calling glDeleteProgram prior to actually using the shader.
In general, if you have a wrapper around a GLSL shader or program, you probably want to delete the copy constructor and assignment operator (or implement a ref counting system).
\edit to delete the copy ctor & assignment operator....
Shader(const Shader&) = delete;
Shader& operator = (const Shader&) = delete;
You probably want to manage these shaders somewhere (possibly ref counted), and only store pointers to them within your SpriteRenderer.
I can't see any other problem with the code you've posted above, so the issue may be within your shader, or how you are passing any uniform variables you're using.

Glfw glDrawElements drawing triangle weird

Runs only once
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
GLuint triangles[] = {0,1,2};
int lengthV = 3; //Number of vertices
int lenfthT = 1; //Number of triangles
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
glGenBuffers(vaoID, &verticesVBOID);
glBindBuffer(GL_ARRAY_BUFFER, verticesVBOID);
glBufferData(GL_ARRAY_BUFFER, lengthV*sizeof(GLfloat)*3, vertices, GL_STATIC_DRAW);
glGenBuffers(vaoID, &trianglesVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, trianglesVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, lengthT*sizeof(GLuint)*3, triangles, GL_STATIC_DRAW);
Runs once per frame
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, verticesVBOID);
glVertexAttribPointer(0, lengthV, GL_FLOAT, GL_FALSE, 0, nullptr);
glUseProgram(program);
//glDrawArrays(GL_TRIANGLES, 0, verticeCount*3);
glDrawElements(GL_TRIANGLES, lengthT,GL_UNSIGNED_INT, nullptr);
glDisableVertexAttribArray(0);
glfwSwapBuffers(window);
When I run this, this renders, which is right.
When I change the number of vertices to 4 to try and render a quad eventually.
int lengthV = 4;
This happens.
I don't understand why this is happening because I only changed the number of vertices.
Ive Tried to find an answer but I could not. I have looked at this persons problem and his code looks the same as mine after applying the answer.
No display from glDrawElements
You missinterpret the second parameter of glVertexAttribPointer.
The size parameter specifies the number of components of an attribute (which basically is the number of floats it gets). Since you still have a vec3 (3 floats) per vertex when drawing a quad, this number shouldn't be changed.

VAO not rendering colors OpenGL?

I was hoping to get some help on an OpenGL question concerning the creation and rendering of VAOs. The goal here is simply to take this:
glBegin(GL_TRIANGLES);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex3f(-0.5f, 0.5f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
glVertex3f(0.5f, -0.5f, 0.0f);
glVertex3f(-0.5f, 0.5f, 0.0f);
glVertex3f(0.5f, -0.5f, 0.0f);
glVertex3f(0.5f, 0.5f, 0.0f);
glEnd();
which renders a red square in the middle of the window, and turn it into a VAO with vertices, colors, and indices. Now, this is what I have so far as far as creating the VAO (sorry if this is a bit long for the code):
//initialize all data
verts_amt = 6;
Vertex* verts = (Vertex*)malloc(sizeof(Vertex) * verts_amt);
int* indices = (int*)malloc(sizeof(int) * verts_amt);
verts[0] = createVertex(-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
verts[1] = createVertex(-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
verts[2] = createVertex(0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
verts[3] = createVertex(-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
verts[4] = createVertex(0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
verts[5] = createVertex(0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
int i;
for(i = 0; i < 6; i ++)
indices[i] = i;
unsigned int vbo, ibo;
//create, bind, set data, and then unbind for the vbo and ibo
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, verts_amt * sizeof(Vertex), verts, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, verts_amt * sizeof(int), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
//create vao, bind vao, bind and set data for vbo, bind ibo, then unbind vao
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), NULL);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, r));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBindVertexArray(0);
in case you are wondering, Vertex is just a struct made up of seven floats in the order x, y, z, r, g, b, a. After looking through similar questions on this topic, I'm still not seeing what I'm missing and/or not doing right, because when I render it with these simple lines:
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, verts_amt, GL_UNSIGNED_INT, NULL);
it renders just a competey white square. Keep in mind I'm not changing anything else about my rendering loop except of course getting rid of the Vertex3f, glBegin/glEnd, and Color4f calls. I should also mention that I'm not using a shader program, I'm not entirely sure if that changes anything drastically here. Any help on this would be much appreciated!
I should also mention that I'm not using a shader program.
You cannot use glVertexAttribPointer without a shader. These functions cannot interface with the OpenGL fixed function pipeline (FFP).
If you want to use the FFP and still use buffer objects, then you should use the appropriate functions. glVertexPointer (no "Attrib") and glColorPointer are the array equivalents to glVertex and glColor. These work with VAOs just fine.
So the only thing you need to change is your two glVertexAttribPointer calls to be glVertexPointer and glColorPointer (and of course adjusting the parameters accordingly).

Rectangle instances with different texture UVs

I am new to modern OpenGL VBO/VAO and I struggle with one thing: I have coded a RectangleAsset based on this tutorial, but I am not sure how to move information about texture UVs to the RactangleAssetInstance (my rectangles can have different textures).
Do I have to create new VAO for it or can I just pass the UVs by some other means? Or add second VBO for UVs? And most imporantly: what would be best practice solving this?
struct RectangleAsset {
GLuint VBO;
GLuint VAO;
};
struct RectangleAssetInstance { //this is actually more complex class in my code
RectangleAsset rect; //but tried to extract the most imporatant code
glm::mat4 transform;
Texture * texture;
void UpdateTransform(int,int,int,int);
private:
int x,y,width,height;
};
and function loading the RectangleAsset:
void GUIRenderer::init()
{
image = new Program ("vs.glsl", "fs.glsl");
glGenVertexArrays(1, &rect.VAO);
glBindVertexArray(rect.VAO);
glGenBuffers(1, &rect.VBO);
glBindBuffer(GL_ARRAY_BUFFER, rect.VAO);
GLfloat vertexData[] = {
// X Y Z U V
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(image->attrib("vert"));
glVertexAttribPointer(image->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), NULL);
glEnableVertexAttribArray(image->attrib("vertTexCoord"));
glVertexAttribPointer(image->attrib("vertTexCoord"), 2, GL_FLOAT, GL_TRUE, 5*sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));
glBindVertexArray(0);
}
NOTE: I plan to use RectangleAssetInstances only at one place, in one std::vector for GUI rendering(non-static gui). Might it be good idea to merge all rectangles in one VBO and VAO (and re-create it whenever UIElement is added/removed)?
Any advices learning best practices with OpenGL are welcomed.
VAOs store both the format of input data and the location that that input data is sourced from. This is actually two separate concepts. If you want to change where the UVs come from you must call glVertexAttribPointer again. This call would look something like glVertexAttribPointer(uvLoc, GL_FLOAT, false, sizeof(float) * 5, (const GLvoid*)(sizeof(float) * 3)) Note that this will NOT change the VBO that your position information is coming from.
Now you mentioned that you wanted to do this because your rectangle instances may have different textures. You need not change the UVs in order to make this happen. In general positions, UVs, and normals are all part of the mesh and you only need one copy of them. To change the texture just call glActiveTexture(GL_TEXTURE0 + i) followed by glBindTexture(GL_TEXTURE_2D, tex) and then set the sampler uniform in your shader to use the correct image unit with glUniform1i(samplerLoc, i)
There is also the ARB_vertex_attrib_binding extension, which became core in OpenGL 4.3. This allows you to separate attribute layout from data location. The article at the OpenGL wiki provides information on how to do this, but again it is probably better to author all the textures for a given mesh using the same UVs.
In regards to your question about merging everything into one VAO and VBO: If you only want rectangles than this is not necessary, since you can get any kind of rectangle you would like using an affine transform with non-uniform scaling component. Thus you only need one VAO and one VBO in total, and there is no need to merge anything.