opengl 2d game only drawing second sprite texture and not first - c++

I'm currently creating a 2d fighting game utilizing OpenGL and I have run into a problem where OpenGL is only drawing at my last initialized sprite position, regardless of how many sprites I initialize and try and draw. Even when I initialize a sprite1 and sprite2 but only draw sprite1, sprite is what will still be drawn. It starts with my sprite class where I initialize where on the screen I want my image as well as what image to use:
Sprite.cpp
Init(int screenCoordinateX, int screenCoordinateY, uint imageWidth, unsigned int imageHeight, std::string imageFilePath)
{
//casting to float since GLSL shader variables vec2,3,4 require vertex data to be in floats
this->x = static_cast<float>(x);
this->y = static_cast<float>(y);
this->width = static_cast<float>(width);
this->height = static_cast<float>(height);
glGenBuffers(1, &vboID);
Blz::Graphics::GLTexture texture(imageFilePath);
this->texture = texture;
float halfWidth = this->width / 2;
//Setting sprite origin at bottom middle of image by subtracting half width
this->vertexData.at(0).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y + this->height, 0.0f });//Top right corner
this->vertexData.at(1).SetPosition(glm::vec3{ this->x - halfWidth, this->y + height, 0.0f });//Top left corner
this->vertexData.at(2).SetPosition(glm::vec3{ this->x - halfWidth, this->y, 0.0f });//Bottom left corner
this->vertexData.at(3).SetPosition(glm::vec3{ this->x - halfWidth, this->y, 0.0f });//Bottom left corner
this->vertexData.at(4).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y, 0.0f });//Bottom right corner
this->vertexData.at(5).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y + this->height, 0.0f });//Top right corner
this->vertexData.at(0).SetUV(glm::vec2{ 1.0f, 1.0f });
this->vertexData.at(1).SetUV(glm::vec2{ 0.0f, 1.0f });
this->vertexData.at(2).SetUV(glm::vec2{ 0.0f, 0.0f });
this->vertexData.at(3).SetUV(glm::vec2{ 0.0f, 0.0f });
this->vertexData.at(4).SetUV(glm::vec2{ 1.0f, 0.0f });
this->vertexData.at(5).SetUV(glm::vec2{ 1.0f, 1.0f });
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, (sizeof(Vector3D) * this->vertexData.size()), &this->vertexData.front(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textureCoordinates));
//Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
I then try and render sprites passed in to renderer like so:
Renderer.cpp
void Renderer::Draw(Sprite& sprite)
{
glm::mat4 orthoProjection = glm::ortho(0.0f, static_cast<sfloat>(1024), 0.0f, static_cast<sfloat>(768));
GLuint transformationMatrixUniformLocation = this->shaderProgram.GetUniformLocation("transformationMatrix");
glUniformMatrix4fv(transformationMatrixUniformLocation, 1, GL_FALSE, &(orthoProjection[0][0]));
glBindTexture(GL_TEXTURE_2D, sprite.texture.id);
glBindBuffer(GL_ARRAY_BUFFER, sprite.vboID);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
I here is my main.cpp where I begin to call everything:
int main()
{
Blz::Graphics::Renderer renderer;
Blz::Window window;
Blz::Input input;
Scene scene;
window.Initialize();
renderer.Init();
Sprite sprite1;
sprite.Init(900, 300, 200, 200, "CharImage.png");
Sprite sprite2;
sprite2.Init(100, 100, 200, 200, "CharImage.png");
while (!input.IsKeyPressed(SDLK_ESCAPE))
{
window.ClearBuffers();
renderer.Draw(sprite1);
window.SwapBuffers();
}
return 0;
}
So even though I ask for sprite1 to be drawn, only sprite2's position at 100x 100y gets drawn to the screen. Even if I manually try and enter a vboID of 1 (which is the vboID of sprite1) within renderer.cpp, it still draws sprite2's position. What am I doing wrong?
Here are my Shaders if necessary:
VertexShader.glsl
#version 430
in vec3 vertexPosition;
in vec2 textCoord;
out vec2 TextureCoord;
uniform mat4 transformationMatrix;
void main()
{
vec4 position = vec4(vertexPosition, 1.0f);
gl_Position = transformationMatrix * position;
TextureCoord = textCoord;
};
FragmentShader.glsl
#version 430
out vec4 daColor;
in vec2 TextureCoord;
uniform sampler2D basicTexture;
void main()
{
vec4 texel = texture(basicTexture, TextureCoord);
daColor = texel;
};

So I guess this is a lesson for anyone aspiring to learn and use OpenGL. Anytime you are using VBOs and vbo ids to bind an OpenGL buffer to you also need to again specify your vertexattribpointers before drawing. So my new renderer.cpp file looks like this:
void Renderer::Draw(Sprite& sprite)
{
glm::mat4 orthoProjection = glm::ortho(0.0f, static_cast<sfloat>(1024), 0.0f, static_cast<sfloat>(768));
GLuint transformationMatrixUniformLocation = this->shaderProgram.GetUniformLocation("transformationMatrix");
glUniformMatrix4fv(transformationMatrixUniformLocation, 1, GL_FALSE, &(orthoProjection[0][0]));
glBindTexture(GL_TEXTURE_2D, sprite.texture.id);
glBindBuffer(GL_ARRAY_BUFFER, sprite.vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textureCoordinates));
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
This other SO answer gives a reason as to why: is VertexAttribPointer needed after each BindBuffer?. To avoid this, you would use the newer VAO's which store vertex attribute info so you don't have to specify vertexattribpointer functions everytime.

Related

Rotated GLSL texture is pixelated

I've made a program that displays some textures depending on the given input and can rotate, resize and move the textures depending on the given input. The program works perfectly fine but when I rotate the textures the edges appear to be pixelated, like this:
Is there a way for me to smoothen out these edges?
Here are my shaders and texture classes:
texture.vs:
#version 300 es
precision mediump float;
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0f);
ourColor = aColor;
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
texture.fs
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
Here is my texture.cpp:
Texture::Texture(int x, int y, int w, int h, int gw, int gh)
{
pos.TL_x = _VERTICIZE_X(x, gw);
pos.TL_y = -_VERTICIZE_Y(y, gh);
pos.TR_x = _VERTICIZE_X(x + w, gw);
pos.TR_y = -_VERTICIZE_Y(y, gh);
pos.BL_x = _VERTICIZE_X(x, gw);
pos.BL_y = -_VERTICIZE_Y(y + h, gh);
pos.BR_x = _VERTICIZE_X(x + w, gw);
pos.BR_y = -_VERTICIZE_Y(y + h, gh);
}
void set_max_z(int z)
{
max_z = z;
}
int Texture::init(float ang_rad, float z)
{
shader = Shader("./src/opengl/shaders/image.vs", "./src/opengl/shaders/image.fs");
this->angle = ang_rad;
// build and compile our shader zprogram
// ------------------------------------
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[32] = {
// positions // colors // texture coords
pos.TR_x, pos.TR_y, _VERTICIZE_Z(z, max_z), 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, // top right
pos.BR_x, pos.BR_y, _VERTICIZE_Z(z, max_z), 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, // bottom right
pos.BL_x, pos.BL_y, _VERTICIZE_Z(z, max_z), 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // bottom left
pos.TL_x, pos.TL_y, _VERTICIZE_Z(z, max_z), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
glEnable(GL_DEPTH_TEST);
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);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// load and create a texture
// -------------------------
// texture 1
// ----------
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
shader.use(); // don't forget to activate/use the shader before setting uniforms!
// either set it manually like so:
glUniform1i(glGetUniformLocation(shader.ID, "texture"), 0);
return 0;
}
void Texture::render(int w, int h, uint8_t *buffer)
{
// If having trouble doing multiple textures, add "+ index to Active Texture."
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glm::mat4 transform = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
transform = glm::translate(transform, glm::vec3(0.0f, 0.0f, 0.0f));
transform = glm::rotate(transform, glm::radians(this->angle), glm::vec3(0.0f, 0.0f, 1.0f));
// get matrix's uniform location and set matrix
shader.use();
unsigned int transformLoc = glGetUniformLocation(shader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
Texture::~Texture()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
void Texture::framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
(_VERTICIZE just calculates points)
I'm using ubuntu, GLAD, GLFW.
This appears to be a classic example of Aliasing. We can fix this by enabling MSAA.
GLFW has an inbuilt way of doing that. Put this before you create the window:
glfwWindowHint(GLFW_SAMPLES, 4); /* if effect is not strong enough, change to 8 */
Edit -
You have to call glfwWindowHint(GLFW_SAMPLES, 4) in between glfwInit and glfwCreateWindow.
Also, in case OpenGL doesn't enable multisampling by default, do
glEnable(GL_MULTISAMPLE);

How to draw multiple objects in OpenGL using multiple VAO and VBO?

I'm trying to render multiple objects in OpenGL using multiple VAO's and VBO's. To render multiple objects using the same vertices I've done it, but what I want to do is to use different vertices for each object, for example to draw a square and a circle. For a square I only need 6 vertices but for circle I need 360.
I have error with reading or creating the shaders.
Here is the Vertex Shader:
#version 330 core
layout (location = 0) in vec4 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * position;
}
Fragment Shader:
#version 330 core
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main()
{
color = u_Color;
}
The VAO and VBO generating and binding
// Circle
std::vector<VertexFormat> vertices;
for (int i = 0; i < 360; i++)
{
GLfloat angle = i * ((2.0f * 3.14159f) / 360);
vertices.push_back(VertexFormat(glm::vec3(cos(angle) * 100.0f, sin(angle) * 100.0f, 0.0f)));
}
// Pipette object
std::vector<VertexFormat> pipetteVertices;
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 500.0f, 0.0f))); // 0
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 500.0f, 0.0f))); // 1
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 700.0f, 0.0f))); // 2
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 700.0f, 0.0f))); // 3
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 500.0f, 0.0f)));
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 700.0f, 0.0f)));
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 6, &pipetteVertices[0], GL_STATIC_DRAW);
//Position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (GLvoid *)0);
GLuint vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
GLuint vbo2;
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 360, &vertices[0], GL_STATIC_DRAW);
//Position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (GLvoid *) 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And the draw call in the rendering loop:
//Get the uniform locations of model, view and projection matrices
modelID = glGetUniformLocation(program, "model");
viewID = glGetUniformLocation(program, "view");
projectionID = glGetUniformLocation(program, "projection");
//View transform
glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 2), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
//Projection transform
//glm::mat4 projection = glm::perspective(45.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 1000.0f);
glm::mat4 projection = glm::ortho(0.0f, (GLfloat)screenWidth, 0.0f, (GLfloat)screenHeight, 0.1f, 10.0f);
{
glUniformMatrix4fv(viewID, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionID, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 translate = glm::translate(glm::mat4(1.0), glm::vec3(100.0f + move_x, 100.0f + move_y, 0.0f));
glm::mat4 rotate = glm::rotate(glm::mat4(1.0), 0.0f, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, 2.0f));
glm::mat4 model = translate * rotate * scale;
glUniformMatrix4fv(modelID, 1, GL_FALSE, glm::value_ptr(model));
glUniform4f(color, 0.0f, 0.0f, 1.0f, 1.0f);
//Render
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
}
{
glUniformMatrix4fv(viewID, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionID, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 translate = glm::translate(glm::mat4(1.0), glm::vec3(300.0f + injPipette.x, 300.0f + injPipette.y, 0.0f));
glm::mat4 rotate = glm::rotate(glm::mat4(1.0), 0.0f, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, 2.0f));
glm::mat4 model = translate * rotate * scale;
glUniformMatrix4fv(modelID, 1, GL_FALSE, glm::value_ptr(model));
glUniform4f(color, 1.0f, 0.0f, 0.0f, 0.5f);
//Render
glDrawArrays(GL_TRIANGLES, 0, 6);
}
I repeat, to draw multiple objects using the same vertices I've done it. I need to know how to draw multiple objects using the same vertex and fragment shader but different number of vertices. The project is small, just rendering maximum 10 objects in 2D.
Drawing commands such as glDrawArrays process and draw the arrays of generic vertex attribute data specified in the currently bound Vertex Array Object.
This means that you need to bind the correct vertex array object before executing the Draw call:
// [...]
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
// [...]
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
I found a project with the code:
#pragma once
#include "glm\glm.hpp"
struct VertexFormat
{
glm::vec3 position;
VertexFormat(const glm::vec3 &iPos)
{
position = iPos;
}
VertexFormat()
{
}
};

Model, view and projection matrix do not want to work well for opengl glsl

I am trying to make my first cube using open gl. Unfortunately I stucked in easy rotation. This is how it should look:
Instead I am getting those weird, do not even know how to called it : https://youtu.be/0A5Hi-8bygE
Vertex shader
#version 330 core
layout (location = 0) in vec2 a_position;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec4 a_color;
out vec2 v_fragmentPosition;
out vec2 v_fragmentUV;
out vec4 v_fragmentColor;
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
void main()
{
gl_Position = u_projection * u_view * u_model * vec4(a_position, 0.0, 1.0);
v_fragmentPosition = a_position;
v_fragmentUV = vec2(a_uv.x, 1 - a_uv.y);
v_fragmentColor = a_color;
}
Fragment
#version 330 core
out vec4 outColor;
in vec2 v_fragmentPosition;
in vec2 v_fragmentUV;
in vec4 v_fragmentColor;
void main()
{
outColor = v_fragmentColor;
}
Main
#include <glad.h>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
#include <iostream>
#include "Mesh.h"
#include "Shader.h"
int main(int argc,char*args[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_Window* window = SDL_CreateWindow("fdas", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL);
SDL_GLContext context = SDL_GL_CreateContext(window);
gladLoadGLLoader(SDL_GL_GetProcAddress);
glEnable(GL_DEPTH_TEST);
Shader shader;
std::string vertex = shader.LoadFromFile("vertex.shader");
std::string fragment = shader.LoadFromFile("fragment.shader");
shader.CreateShaderProgram(vertex.c_str(), fragment.c_str());
shader.useProgram();
Mesh mesh;
mesh.CreateVertexArray();
bool quit = false;
SDL_Event event;
while (!quit)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
exit(0);
}
}
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 view;
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
glm::mat4 projection;
projection = glm::perspective(glm::radians(45.0f), 1280 / 720.0f, 0.1f, 100.0f);
GLint u_model = shader.GetUniformLocation("u_model");
GLint u_view = shader.GetUniformLocation("u_view");
GLint u_projection = shader.GetUniformLocation("u_projection");
glUniformMatrix4fv(u_model, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(u_view, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(u_projection, 1, GL_FALSE, glm::value_ptr(projection));
Rect destRect = { -0.5f, -0.5f, 1.0f, 1.0f };
Rect uvRect = { 0.0f, 0.0f, 1.0f, 1.0f };
ColorRGBA color = { 255, 255, 128, 255 };
mesh.CreateQuad(destRect, uvRect, color);
mesh.Draw(0);
SDL_GL_SwapWindow(window);
}
return 0;
}
Mesh
void Mesh::CreateVertexArray()
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glBindVertexArray(0);
}
void Mesh::CreateQuad(Rect destRect, Rect uvRect, ColorRGBA color)
{
vertex[0].color = color; // topleft
vertex[0].setPosition(destRect.x, destRect.y + destRect.h);
vertex[0].setUV(uvRect.x, uvRect.y + uvRect.h);
vertex[1].color = color;
vertex[1].setPosition(destRect.x, destRect.y); // bottom left
vertex[1].setUV(uvRect.x, uvRect.y);
vertex[2].color = color;
vertex[2].setPosition(destRect.x + destRect.w, destRect.y); // bottom right
vertex[2].setUV(uvRect.x + uvRect.w, uvRect.y);
vertex[3].color = color;
vertex[3].setPosition(destRect.x + destRect.w, destRect.y + destRect.h); // top right
vertex[3].setUV(uvRect.x + uvRect.w, uvRect.y + uvRect.h);
GLuint indices[6] = {
0, 1, 2,
2, 3, 0
};
glBindVertexArray(vao);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(vertex), NULL, GL_STATIC_DRAW); // orphan the buffer
glBufferSubData(GL_ARRAY_BUFFER, 0, 6 * sizeof(vertex), vertex);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), NULL, GL_STATIC_DRAW); // orphan the buffer
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 6 * sizeof(GLuint), indices);
glBindVertexArray(0);
}
void Mesh::Draw(GLuint texture)
{
glBindVertexArray(vao);
// glEnable(GL_CULL_FACE);
// glCullFace(GL_FRONT);
//glFrontFace(GL_CW);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
glBindVertexArray(0);
}
Vertex
struct Rect {
float x, y;
float w, h;
};
struct Position {
float x, y;
};
struct UV {
float u, v;
};
struct ColorRGBA {
GLubyte r, g, b, a;
};
class Vertex
{
public:
Vertex();
~Vertex();
void setPosition(float x, float y);
void setcolor(ColorRGBA color);
void setUV(float u, float v);
UV uv;
ColorRGBA color;
Position position;
};
I will not show shader class, because there is all good with it.
I know it, because I did an experiment.
I created a new uniform in fragment class called u_expColor and set outColor = u_expColor and a quad's color changed.
Also I created uniform vec4 u_expPos in vertex shader and said gl_Position = e_expPos and it created quad with no problems.
Only if I want to create/multiply position by mvp in vertex shader there is a problem like on the you tube video.
How to fix it?
I have fixed it thanks http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/#putting-it-all-together. I saw he had
glm::mat4 model = glm::mat4(1.0f)
and it was all I had to do.

Modern OpenGL issue texturing plane

I have been having difficulty texturing a plane I made. The first quad on the plane is textured properly, but the rest of the plane then only seems to use the first pixel of the texture so it all ends up as a solid color. It seems to work properly if I make one giant plane and just texture that, but when I try to break up the plane into sections I keep getting this issue. I’m assuming I am missing something as far as the coordinates go, but from my understanding I thought they were always supposed to be between 0 and 1? Any help is appreciated.
[![enter image description here][1]][1]
Texture coordinates
GLfloat grassTexCoords[]
{
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
};
Setting up VAO
GLuint makePlane()
{
float size = 5;
for (int i = -5; i < 5; ++i)
{
for (int j = -5; j < 5; ++j)
{
verts.push_back({ glm::vec3((i * size), -11.f, (j * size)) });
verts.push_back({ glm::vec3((i * size), -11.f, (j * size) + size) });
verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size)) });
verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size)) });
verts.push_back({ glm::vec3((i * size), -11.f, (j * size) + size) });
verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size) + size) });
}
}
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(VertexPos), verts.data(), GL_STATIC_DRAW);
GLuint vboTex;
glGenBuffers(1, &vboTex);
glBindBuffer(GL_ARRAY_BUFFER, vboTex);
glBufferData(GL_ARRAY_BUFFER, 2 * 6 * sizeof(GLfloat), &grassTexCoords, GL_STATIC_DRAW);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vboTex);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
return vao;
}
Rendering
void render()
{
glViewport(0, 0, window.getSize().x, window.getSize().y);
glClearColor(.4f, .4f, .4f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//1st program
glUseProgram(sphereProgram);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, objPointCount);
//2nd program
glFrontFace(GL_CCW);
glDepthMask(GL_FALSE);
glUseProgram(cubeProgram);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
glBindVertexArray(cubeVao);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDepthMask(GL_TRUE);
//3rd program
glFrontFace(GL_CCW);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
sf::Texture::bind(&grassTex);
glUseProgram(planeProgram);
glBindVertexArray(planeVao);
glDrawArrays(GL_TRIANGLES, 0, verts.size());
//-----------------------
window.display();
//window.setFramerateLimit(FPS);
window.setVerticalSyncEnabled(true);
}
Vertex shader
#version 410
layout (location = 0) in vec3 vertexPos;
layout (location = 1) in vec2 texCoords;
uniform mat4 view, proj;
out vec3 posEye;
out vec2 coords;
void main()
{
coords = texCoords; //repeat texture over plane
gl_Position = proj * view * vec4(vertexPos, 1.0);
posEye = (view * vec4(vertexPos, 1.0)).xyz;
}
Fragment shader
#version 410
in vec3 posEye;
in vec2 coords;
out vec4 fragColor;
uniform sampler2D tex;
//fog
const vec3 fogColor = vec3(0.2, 0.2, 0.2);
const float minFogRad = 300;
const float maxFogRad = 900;
void main()
{
vec4 texture = texture2D(tex, coords);
fragColor = texture;
float distance = length(-posEye);
float fogFactor = (distance - minFogRad) / (maxFogRad - minFogRad);
fogFactor = clamp(fogFactor, 0.0, 1.0);
fragColor.rgb = mix(fragColor.rgb, fogColor, fogFactor);
}
The problem here is, that texture coordinates are just supplied for the first quad (for the first 6 vertices). All other vertices seem to get [0,0], which causes them to only read the top-left texel. The solution here is to provide enough texture coordinates for all of the vertices.
Texture coordinates in general are not necessarily between 0 and 1. One can specify how values outside of [0,1] should be treated by setting GL_TEXTURE_WRAP_[RST].
Note, that not supplying enough data in a VBO can lead to crashes (depends on the driver) when OpenGL tries to read outside the buffer.
You are using a GL_ARRAY_BUFFER which stores per vertex data.
The 2 and GL_FLOAT arguments in glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL); are declaring that you have 2 floats in vboTex per vertex but you haven't done this, you have 2 floats for each vertex in the first quad only.
In the same way, the 3 and GL_FLOAT arguments in glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); are declaring that you have 3 floats in vbo per vertex which you have done.
The easiest fix for this is to create a bigger GL_ARRAY_BUFFER which repeats the same texture coordinates for every quad.

Cube is not rendering in OpenGL

I'm trying to write a basic OpenGL 3.3 program with shaders, buffers, etc. drawing a cube. The problem is that the cube is not drawn. Sorry for such an amout of code, but i feel like the error might be anywhere, because to me it all seems right: display function is looping, shaders are compiled, matrices are passed to shaders. I suspecting that something might be wrong with culling. Please take a look. Here is the code (I'm using freeglut, first init() is called, then display runs in a loop):
initialization code:
struct ProgramData
{
GLuint theProgram;
GLuint iModel;
GLuint iView;
GLuint iProjection;
};
ProgramData shaderProgram;
ProgramData LoadProgram(const std::string &strVertexShader,
const std::string &strFragmentShader)
{
std::vector<GLuint> shaderList;
shaderList.push_back(LoadShader(GL_VERTEX_SHADER, strVertexShader));
shaderList.push_back(LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
ProgramData data;
data.theProgram = CreateProgram(shaderList);
data.iModel = glGetUniformLocation(data.theProgram, "mModel");
data.iView = glGetUniformLocation(data.theProgram, "mView");
data.iProjection = glGetUniformLocation(data.theProgram, "mProjection");
return data;
}
float cube_vertices[] = {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
GREEN_COLOR,
BLUE_COLOR,
RED_COLOR,
BROWN_COLOR,
GREEN_COLOR,
BLUE_COLOR,
RED_COLOR,
BROWN_COLOR,
};
GLubyte cube_elements[] = {
0,1,2, 2,3,0,
0,3,4, 4,5,0,
0,5,6, 6,1,0,
1,6,7, 7,2,1,
7,4,3, 3,2,7,
4,7,6, 6,5,4
};
void InitializeProgram()
{
//initialize vertex buffer
glGenBuffers(1, &vertex_buffer_obj);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices),
cube_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//initialize index buffer
glGenBuffers(1, &index_buffer_obj);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_elements),
cube_elements, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
shaderProgram = LoadProgram("shader.vert", "shader.frag");
}
void init()
{
InitializeProgram();
int numberOfVertices = 8;
size_t color_data_offset = sizeof(float) * 3 * numberOfVertices;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0,
(void*)color_data_offset);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj);
glBindVertexArray(0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.0f, 1.0f);
}
vertex shader:
#version 330
layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 color;
uniform mat4 mProjection;
uniform mat4 mView;
uniform mat4 mModel;
smooth out vec3 theColor;
void main()
{
gl_Position = mProjection * mView * mModel * vec4(inPosition, 1);
theColor = color;
}
fragment shader:
#version 330
smooth in vec3 theColor;
out vec4 outputColor;
void main()
{
outputColor = vec4(theColor, 1);
}
draw code:
glm::vec3 cam_pos(3, 2, 3);
void display()
{
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram.theProgram);
glm::mat4 model_matrix = glm::translate(glm::vec3(0, 0, 0));
glm::mat4 view_matrix = glm::lookAt(cam_pos,
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1));
glm::mat4 proj_matrix = glm::perspective(45.0f, 1.0f, 1.0f, 100.0f);
glUniformMatrix4fv(shaderProgram.iProjection, 1,
GL_FALSE, glm::value_ptr(proj_matrix));
glUniformMatrix4fv(shaderProgram.iView, 1,
GL_FALSE, glm::value_ptr(view_matrix));
glUniformMatrix4fv(shaderProgram.iModel, 1,
GL_FALSE, glm::value_ptr(model_matrix));
glBindVertexArray(vao);
int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER,
GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size / sizeof(GLubyte), GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glUseProgram(0);
glutSwapBuffers();
glutPostRedisplay();
}
UPD: in init method when an offset for colors is calculated should be
sizeof(float) * 3 * numberOfVertices instead of
sizeof(GLubyte) * 3 * numberOfVertices, colors are stored as floats. Rendering problem not solved.
SOLVED: thank you for help. See my answer below.
On thing I did spot when glancing over your code is the following line from your vertex shader:
gl_Position = mProjection * mView * mModel * vec4(inPosition, 0);
That 0 should really be a 1.0.
In display() function
glDrawElements(GL_TRIANGLES, size / sizeof(GLubyte), GL_UNSIGNED_SHORT, 0);
should be changed to
glDrawElements(GL_TRIANGLES, size / sizeof(GLubyte), GL_UNSIGNED_BYTE, 0);
and in init()
glFrontFace(GL_CW);
to
glFrontFace(GL_CCW);
So the problem was that I passed to OpenGL incorrect data. Index array is of GLUbyte (1byte size each array element) but I for some reason decided it was GLushort (2bytes).
edit: doesn't matter a lot, but up vector (when generating camera matrix) should be not glm::vec3(0, 0, 1) but glm::vec3(0, 1, 0)