Why does using a program cause my shape to disappear? - c++

The following code draws a white square to the screen. If I uncomment the line that uses the program, the square disappears.
When I debug the program with GLIntercept, the texture appears in a folder called Images, and the log says that the shaders compiled. However, it also says that the program links, but doesn't validate.
I've been poring over this for hours and I have no idea where to go from here.
// Vertex.vert
#version 150 core
in vec3 in_position;
in vec2 in_texture;
out vec2 Texture;
uniform mat4 in_model;
uniform mat4 in_view;
uniform mat4 in_projection;
void main()
{
gl_Position = in_projection * in_view * in_model * vec4(in_position, 1.0);
Texture = in_texture;
}
// Fragment.frag
#version 150 core
in vec2 Texture;
out vec4 Colour;
uniform sampler2D Sampler2D;
void main()
{
Colour = texture(Sampler2D, Texture);
}
// Source.cpp
#include <cfloat>
#include <iostream>
#include <string>
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include "Archive.h"
using namespace glm;
using namespace sf;
using namespace std;
struct Camera
{
vec3 Position = { 0.0f, 0.0f, 1.0f };
vec3 Target = { 0.0f, 0.0f, 0.0f };
vec3 Up = { 0.0f, 1.0f, 0.0f };
float Fovy = 74.0f;
float Aspect = 16.0f / 9.0f;
float ZNear = FLT_MIN;
float ZFar = FLT_MAX;
mat4 View;
mat4 Projection;
};
struct Actor
{
vec3 Scale = { 1.0f, 1.0f, 1.0f };
vec3 Rotation = { 0.0f, 0.0f, 0.0f };
vec3 Position = { 0.0f, 0.0f, 0.0f };
vector<GLfloat> Vertices;
vector<GLuint> Elements;
GLuint Texture;
Actor(string fileName)
{
Image image;
if (!image.loadFromFile(fileName + ".png"))
{
cerr << "ERROR: Unable to load texture" << endl;
}
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
// Draw a square instead of the actual model
Vertices.push_back(-1.0f); Vertices.push_back(-1.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f);
Vertices.push_back(1.0f); Vertices.push_back(-1.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f);
Vertices.push_back(1.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f); Vertices.push_back(1.0f);
Vertices.push_back(-1.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f);
Elements.push_back(0); Elements.push_back(1); Elements.push_back(2);
Elements.push_back(2); Elements.push_back(3); Elements.push_back(0);
}
};
GLuint CreateShader(GLenum shaderType, string fileName, Archive& archive)
{
string source;
archive.open(fileName);
source.resize(archive.getSize());
archive.read(&source[0], archive.getSize());
GLuint shader = glCreateShader(shaderType);
const char* pointer = source.c_str();
glShaderSource(shader, 1, &pointer, nullptr);
glCompileShader(shader);
GLsizei length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
GLchar* infoLog = new GLchar[length];
glGetShaderInfoLog(shader, length, &length, infoLog);
cerr << infoLog << endl;
delete[] infoLog;
}
return shader;
}
GLuint CreateProgram(GLuint vertex, GLuint fragment)
{
GLuint program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
GLsizei length;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
GLchar* infoLog = new GLchar[length];
glGetProgramInfoLog(program, length, &length, infoLog);
cerr << infoLog << endl;
delete[] infoLog;
}
return program;
}
int main(int argc, char* argv[])
{
Window window(VideoMode(1920, 1080), "");
window.setVerticalSyncEnabled(true);
if (!window.setActive(true))
{
cerr << "ERROR: Unable to set the window as the current target for OpenGL rendering" << endl;
return 1;
}
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
cerr << "ERROR: Unable to initialise GLEW" << endl;
return 1;
}
Archive shaders("Shaders.lea");
Archive models("Models.lea");
Actor actor("tree01");
GLuint vertex = CreateShader(GL_VERTEX_SHADER, "Vertex.vert", shaders);
GLuint fragment = CreateShader(GL_FRAGMENT_SHADER, "Fragment.frag", shaders);
GLuint program = CreateProgram(vertex, fragment);
GLuint vertexArray;
GLuint vertexBuffer;
GLuint elementBuffer;
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
// glUseProgram(program);
GLint position = glGetAttribLocation(program, "in_position");
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
glEnableVertexAttribArray(position);
GLint texture = glGetAttribLocation(program, "in_texture");
glVertexAttribPointer(texture, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 3));
glEnableVertexAttribArray(texture);
GLint projection = glGetUniformLocation(program, "in_projection");
GLint view = glGetUniformLocation(program, "in_view");
GLint model = glGetUniformLocation(program, "in_model");
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Camera camera;
while (window.isOpen())
{
// Input handling code omitted
camera.View = lookAt(camera.Position, camera.Target, camera.Up);
camera.Projection = perspective(radians(camera.Fovy), camera.Aspect, camera.ZNear, camera.ZFar);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniformMatrix4fv(projection, 1, GL_FALSE, value_ptr(camera.Projection));
glUniformMatrix4fv(view, 1, GL_FALSE, value_ptr(camera.View));
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * actor.Vertices.size(), &actor.Vertices[0], GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * actor.Elements.size(), &actor.Elements[0], GL_STATIC_DRAW);
mat4 transform = translate(mat4(), actor.Position);
transform *= rotate(transform, actor.Rotation.z, vec3(0.0f, 0.0f, 1.0f));
transform *= rotate(transform, actor.Rotation.y, vec3(0.0f, 1.0f, 0.0f));
transform *= rotate(transform, actor.Rotation.x, vec3(1.0f, 0.0f, 0.0f));
transform *= scale(transform, actor.Scale);
glUniformMatrix4fv(model, 1, GL_FALSE, value_ptr(transform));
glBindTexture(GL_TEXTURE_2D, actor.Texture);
glDrawElements(GL_TRIANGLES, actor.Elements.size(), GL_UNSIGNED_INT, 0);
window.display();
}
glUseProgram(0);
glDisableVertexAttribArray(texture);
glDisableVertexAttribArray(position);
glDeleteBuffers(1, &elementBuffer);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(1, &vertexArray);
glDetachShader(program, fragment);
glDetachShader(program, vertex);
glDeleteShader(fragment);
glDeleteShader(vertex);
glDeleteProgram(program);
return 0;
}

It was a combination of two things.
When I last used this code, it was with GLM 0.9.7.6, and mat4() generated an identity matrix. However, at some point between that version of GLM and the one I'm currently using (0.9.9.5), mat4() started generating an empty matrix. Instead, you need mat4(1.0f).
Also, I used bad values for the near and far planes. I did think that the values I had would work, but clearly I don't quite understand what's going on behind the scenes.

Related

White screen when loading JPG in OpenGL

I'm trying to render JPG image using "stb_image.h" library. Im using GLEW and GLFW, here is the code:
#include "glew.h"
#include "glfw3.h"
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define WIDTH 800
#define HEIGHT 600
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main(){
GLFWwindow *window;
if (!glfwInit())
{
std::cout << "Failed to Init GLFW" << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL CPP", NULL, NULL);
if (!window)
{
std::cout << "Failed to create GLFW Window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
GLenum err = glewInit();
if (GLEW_OK != err)
{
std::cout << "Failed to Init GLEW" << std::endl;
glfwTerminate();
return -1;
}
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
float indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout (location = 2) in vec2 aTexCoord;\n"
"out vec3 ourColor;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
" ourColor = aColor;\n"
" TexCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
" FragColor = texture(ourTexture, TexCoord);\n"
"}\n\0";
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR COMPILING VERTEX SHADER" << infoLog << std::endl;
}
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR COMPILING FRAGMENT SHADER" << infoLog << std::endl;
}
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
unsigned int VBO, VAO, EBO;
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);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height, nrChannels;
unsigned char *data = stbi_load("C:/Users/user3/Documents/cppopengl/res/container.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
std::cout << "data loaded successfully"<< std::endl;
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
glUseProgram(shaderProgram);
//std::cout << glGetUniformLocation(shaderProgram, "ourTexture") << std::endl;
glUniform1i(glGetUniformLocation(shaderProgram, "ourTexture"), 0);
while (!glfwWindowShouldClose(window))
{
err = glGetError();
glClearColor(0.5, 0.5, 0.5, 1);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
if (((err = glGetError()) != GL_NO_ERROR))
{
std::cout << err << std::endl;
}
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteProgram(shaderProgram);
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
Code compiles just fine, without errors and warnings. When I start the executable it shows white screen. Both vertex shader and fragment shader compile and link without errors. stbi_load() does not return error and glGetError() does not return error, glGetUniformLocation() returns uniform location just fine. Can you please help me out? Thanks in advance.
EDIT:
indices must be unsigned int instead of float, thanks #Rabbid76
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};

glClearColor and blending

I'm using GLFW, OpenGL 4.6 with VSCode, and MinGW64 g++. I'm trying to render a transparent texture using glEnable(GL_BLEND); and glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_ALPHA);. Whilst the texture does render on my window, it seems like the glClearColor() affects the blend significantly. I'm still very new to graphics, so I'm not sure how I can render the texture properly regardless of what the clear color is set to. Also, do I need to enable Depth for 2D games? (shader.cpp and texture.cpp is taken from The Cherno's OpenGL tutorial series)
Without blend
With blend
With blend and black clear color (Desired blend)
main.cpp:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "GeometryUtil.h"
#include "Shader.h"
#include "Texture.h"
#include "Object.h"
#include <iostream>
#include <vector>
using namespace std;
int main() {
if (!glfwInit()) { // Initialise GLFW
cerr << "Failed to initialize GLFW" << endl;
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window {glfwCreateWindow(1280, 720, "2D GAME", NULL, NULL)};
if (window == NULL) {
cerr << "Failed to open GLFW window." << endl;
glfwTerminate();
return -1;
}
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
cerr << "Failed to initialize GLEW" << endl;
glfwTerminate();
return -1;
}
cout << "OpenGL Version: " << glGetString(GL_VERSION) << endl;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_ALPHA);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
Object object {608, 392};
vector<float> vectorData;
createQuad(object.getX(), object.getY(), vectorData);
static const GLfloat texCoords[8] {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
GLuint VBOs[2];
glGenBuffers(2, VBOs);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, vectorData.size() * sizeof(vectorData), &vectorData.front(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void *) 0);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
static const GLuint texIndex[6] {
0, 1, 2,
1, 2, 3
};
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(texIndex), texIndex, GL_STATIC_DRAW);
glm::mat4 Projection {glm::ortho(0.0f, 1280.0f, 0.0f, 720.0f, 0.0f, 1.0f)};
glm::mat4 View {glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0))};
glm::vec3 translationA {glm::vec3(0, 0, 0)};
glm::mat4 Model = glm::translate(glm::mat4(1.0f), translationA); // Model Matrix (Using Identity Matrix - Origin)
glm::mat4 mvp = Projection * View * Model;
Shader shader {"shader/vertexShader.vert", "shader/fragmentShader.frag"};
shader.bind();
shader.setUniformMat4f("MVP", mvp);
int sampler[] {0, 1};
shader.setUniform1iv("v_Textures", sampler, 2);
Texture texture {"resources/sprites/test.png"};
texture.bind();
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
texture.cpp:
#define STB_IMAGE_IMPLEMENTATION
#include <GL/glew.h>
#include "Texture.h"
#include "stb_image.h"
#include <iostream>
Texture::Texture(const std::string &path)
: rendererID{0}, filePath{path}, localBuffer{nullptr}, width{0}, height{0}, bPP{0} {
// stbi_set_flip_vertically_on_load(1);
localBuffer = stbi_load(path.c_str(), &width, &height, &bPP, 4);
if (localBuffer == nullptr)
std::cout << "Unable to load texture file: " << path << std::endl;
glGenTextures(1, &rendererID);
glBindTexture(GL_TEXTURE_2D, rendererID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, localBuffer);
unbind();
if (localBuffer)
stbi_image_free(localBuffer);
}
Texture::~Texture() {
glDeleteTextures(1, &rendererID);
}
void Texture::bind(GLuint slot) const {;
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, rendererID);
}
void Texture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}
vertex shader:
#version 460 core
layout(location = 0) in vec3 vertexCoords;
layout(location = 1) in vec2 textureCoords;
layout(location = 2) in float textureIndex;
out vec2 v_TexCoords;
out float v_TexIndex;
uniform mat4 MVP;
void main() {
gl_Position = MVP * vec4(vertexCoords, 1.0);
v_TexCoords = textureCoords;
v_TexIndex = textureIndex;
}
fragment shader:
#version 460 core
in vec2 v_TexCoords;
in float v_TexIndex;
uniform sampler2D v_Textures[2];
void main() {
gl_FragColor = texture2D(v_Textures[int(v_TexIndex)], v_TexCoords);
}
Everthing is correct codewise on the first look, and yes, the Background will affect the Blending in the case of GL_SRC_ALPHA as first pararmeter.
The issue is the second parameter which should be GL_ONE_MINUS_SRC_ALPHA instead of GL_ONE_MINUS_SRC1_ALPHA. In your case the blend is not normalized and so the values of too much green and a full red add up to that yellowish.
source: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendFuncSeparate.xhtml

Having issues rendering a 2D rectangle on a 3D plane in OpenGL

I'm having issues rendering a 2D object in the 3D space in OpenGL. Whenever I compile my code I get a purple background, which is what I set it to. However, I do not see the object that I should be able to see. I think it's something wrong with the vertex shader, however, I am not completely sure.
Here is my code:
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#ifndef STBI_INCLUDE_STB_IMAGE_H
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#endif
#include "Shader.h"
class Render3D {
private:
GLFWwindow* window;
const int windowWidth = 1920;
const int windowHeigth = 1080;
Render3D(Render3D& render){}
Render3D operator=(Render3D& render) {}
void processInput(GLFWwindow* window) {
}
void privateInit() {
if (!glfwInit()) {
throw(-1);
std::cout << "Error: GLFW Init Failed" << std::endl;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(windowWidth, windowHeigth, "HAHAH BRRR", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW Window \n";
glfwTerminate();
throw (-1);
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cout << "GLEW INIT FAILED\n";
exit(1);
}
//The first two parameters set the position of the lower left corner
glViewport(0, 0, windowWidth, windowHeigth);
}
void render() {
float positions[] = {
// positions // colors // texture
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3
};
const char* vertexShader =
"#version 330 core\n"
"\n"
"layout (location = 0) vec3 aPos;\n"
"layout (location = 1) vec3 aColors;\n"
"layout (location = 2) vec2 aTex;\n"
"\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"\n"
"out vec3 Colors;\n"
"out vec2 TextureCoords;\n"
"\n"
"void main(){\n"
"\n"
"gl_Position = projection * view * model * vec4(aPos, 1.0f);\n"
"Colors = aColors;\n"
"TextureCoords = aTex;\n"
"\n"
"}\0";
const char* fragmentShader =
"#version 330 core\n"
"\n"
"out vec4 ourFrag;\n"
"\n"
"in vec3 Colors;\n"
"in vec2 TextureCoords;\n"
"\n"
"uniform sampler2D texture1;\n"
"uniform sampler2D texture2;\n"
"\n"
"void main(){\n"
"\n"
"ourFrag = mix(texture(texture1, TextureCoords), texture(texture2, TextureCoords), 0.2) * vec4(Colors, 1.0f);;\n"
"\n"
"\n"
"}\0";
unsigned int VAO, VBO, EBO;
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, 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, 8 * sizeof(float), (void*)(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
unsigned int Texture1, Texture2;
glGenTextures(1, &Texture1);
glGenTextures(1, &Texture2);
glBindTexture(GL_TEXTURE_2D, Texture1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
int width, height, nrChannels;
unsigned char* data = stbi_load("src/Images/woodblock.jpg", &width, &height, &nrChannels, 4);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "TEXTURE FAILED:";
std::cout << stbi_failure_reason() << std::endl;
}
glBindTexture(GL_TEXTURE_2D, Texture2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_set_flip_vertically_on_load(1);
data = stbi_load("src/Images/awesomeface.png", &width, &height, &nrChannels, 4);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "TEXTURE FAILED:";
std::cout << stbi_failure_reason() << std::endl;
}
Shader render3D_Program(vertexShader, fragmentShader, 1);
render3D_Program.use();
glUniform1i(glGetUniformLocation(render3D_Program.ID, "texture1"), 0);
glUniform1i(glGetUniformLocation(render3D_Program.ID, "texture2"), 1);
while (!glfwWindowShouldClose(window)) {
processInput(window);
glClearColor(0.5f, 0.2f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Texture2);
render3D_Program.use();
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view1 = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
view1 = glm::translate(view1, glm::vec3(0.0f, 0.0f, -3.0f));
projection = glm::perspective(glm::radians(45.0f), (float)windowWidth / (float)windowHeigth, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(render3D_Program.ID, "model"), 1, GL_FALSE, value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(render3D_Program.ID, "view"), 1, GL_FALSE, value_ptr(view1));
glUniformMatrix4fv(glGetUniformLocation(render3D_Program.ID, "projection"), 1, GL_FALSE, value_ptr(projection));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &VBO);
glfwTerminate();
}
public:
Render3D(){}
void Init() {
privateInit();
}
void Run() {
render();
}
};
Additionally, here is the Shader class:
#ifndef SHADER_H
#define SHADER_H
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
Shader(const char* VertexShader, const char* FragmentShader, bool Specifier) {
unsigned int vertex = glCreateShader(GL_VERTEX_SHADER);
unsigned int fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex, 1, &VertexShader, NULL);
glShaderSource(fragment, 1, &FragmentShader, NULL);
glCompileShader(vertex);
int successVertex;
char infoLogVertex[512];
glGetShaderiv(vertex, GL_COMPILE_STATUS, &successVertex);
if (!successVertex) {
glGetShaderInfoLog(vertex, 512, NULL, infoLogVertex);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLogVertex << std::endl;
}
glCompileShader(fragment);
int successFragment;
glGetShaderiv(fragment, GL_COMPILE_STATUS, &successFragment);
if (!successFragment){
glGetShaderInfoLog(fragment, 512, NULL, infoLogVertex);
std::cout << "ERROR::SHADER:FRAGMENT::COMPILATION_FAILED\n" << infoLogVertex << std::endl;
}
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string& name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string& name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string& name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif
Your vertex shader fails to compiled because you missed the in type qualifier for the vertex shader inputs (attributes):
layout (location = 0) vec3 aPos;
layout (location = 1) vec3 aColors;
layout (location = 2) vec2 aTex;
It has to be:
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColors;
layout (location = 2) in vec2 aTex;

OpenGL binding multiple textures not working

Bear in mind that I have openGL 3 and glsl version 1.30, therefore, I don't have dynamic indexing nor glBindTextureUnit().
I have seen people batch render multiple textures in one draw call by simply activating the texture slot, binding the texture then setting the uniform, like so:
glUniform1i(glGetUniformLocation(program, "u_texture0"), 0);
glUniform1i(glGetUniformLocation(program, "u_texture1"), 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture1);
However, when I do this:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* readFile(const char filePath[])
{
FILE* file;
file = fopen(filePath, "r");
if(file == NULL)
{
perror("unable to load file");
exit(1);
}
fseek(file, 0l, SEEK_END);
char* buffer = (char*)malloc(ftell(file));
rewind(file);
char c;
unsigned int i = 0;
while((c = fgetc(file)) != EOF)
buffer[i++] = c;
fclose(file);
return buffer;
}
GLuint loadShader(const char* src, GLenum type)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
// shader error handling
int result;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if(result == GL_FALSE)
{
int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(shader, length, &length, message);
puts(message);
}
return shader;
}
GLuint loadTexture(const char* filePath)
{
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
unsigned char* buffer;
int width, height;
stbi_set_flip_vertically_on_load(1);
buffer = stbi_load(filePath, &width, &height, NULL, STBI_rgb_alpha);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
if(buffer)
stbi_image_free(buffer);
return texture;
}
void resetViewport(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); }
int main()
{
// initialising GLFW
if(!glfwInit())
{
perror("error with glfw!");
exit(1);
}
// window creation
GLFWwindow* window;
window = glfwCreateWindow(800, 500, "window", NULL, NULL);
glfwSetWindowSizeCallback(window, resetViewport);
// binding renderring context
glfwMakeContextCurrent(window);
// initialising glew
if(glewInit() != GLEW_OK)
perror("error with glee!");
// enabling blend
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// creating program and shaders
GLuint program = glCreateProgram();
char* vertexShaderSource = readFile("vertex.glsl");
char* fragmentShaderSource = readFile("fragment.glsl");
GLuint vertexShader = loadShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fragmentShader = loadShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
// deleting shaders
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
free(vertexShaderSource);
free(fragmentShaderSource);
// compiling and binding program
glLinkProgram(program);
glUseProgram(program);
// creating vertex array
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// creating vertex buffer
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// vertex buffer layout
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), NULL);
glBindAttribLocation(program, 0, "a_position");
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void*)(2 * sizeof(float)));
glBindAttribLocation(program, 1, "a_textureCoordinate");
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void*)(4 * sizeof(float)));
glBindAttribLocation(program, 2, "a_index");
// creating texture
GLuint texture0 = loadTexture("image0.jpeg");
GLuint texture1 = loadTexture("image1.jpeg");
// vertex data
float vertexes[] =
{
// x y u v i (index)
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.0f, -1.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, +1.0f, 0.0f, 1.0f, 1.0f,
+1.0f, +1.0f, 1.0f, 1.0f, 1.0f,
+1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
};
// unbinding just incase
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// rebinding
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// binding texture to texture slot
glUniform1i(glGetUniformLocation(program, "u_texture0"), 0);
glUniform1i(glGetUniformLocation(program, "u_texture1"), 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture1);
// sending data
glBufferData(GL_ARRAY_BUFFER, 8 * 5 * sizeof(float), vertexes, GL_STATIC_DRAW);
glLinkProgram(program);
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
// clear screen
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw call
glDrawArrays(GL_QUADS, 0, 8);
// updating window's buffer
glfwSwapBuffers(window);
}
// error logging
GLenum error = glGetError();
if(error != GL_NO_ERROR)
printf("error: %u\n", error);
// termination
glDeleteTextures(1, &texture0);
glDeleteTextures(1, &texture1);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
glfwTerminate();
}
With the fragment shader code being:
#version 130
in vec2 v_textureCoordinate;
flat in uint v_index;
uniform sampler2D u_texture0;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
uniform sampler2D u_texture3;
uniform sampler2D u_texture4;
uniform sampler2D u_texture5;
uniform sampler2D u_texture6;
uniform sampler2D u_texture7;
out vec4 o_color;
void main()
{
// dynamic indexing is not suppourted in GLSL version 1.30 therefore the most suitable solution is to switch case between them
switch(v_index)
{
case 0u:
o_color = texture2D(u_texture0, v_textureCoordinate);
return;
case 1u:
o_color = texture2D(u_texture1, v_textureCoordinate);
return;
case 2u:
o_color = texture2D(u_texture2, v_textureCoordinate);
return;
case 3u:
o_color = texture2D(u_texture3, v_textureCoordinate);
return;
case 4u:
o_color = texture2D(u_texture4, v_textureCoordinate);
return;
case 5u:
o_color = texture2D(u_texture5, v_textureCoordinate);
return;
case 6u:
o_color = texture2D(u_texture6, v_textureCoordinate);
return;
case 7u:
o_color = texture2D(u_texture7, v_textureCoordinate);
return;
default:
return;
}
}
and the vertex shader code being:
#version 130
attribute vec4 a_position;
attribute vec2 a_textureCoordinate;
attribute float a_index;
out vec2 v_textureCoordinate;
flat out uint v_index;
void main()
{
gl_Position = a_position;
v_textureCoordinate = a_textureCoordinate;
v_index = uint(a_index);
}
It renders both quads with the texture texture0, Am I doing something wrong? I am getting the impression that binding the second texture is unbinding the first texture. What am I missing?
glBindAttribLocation() has to be called before shader program linking to have any effect:
GLuint prog = glCreateProgram();
AttachShader( prog, GL_VERTEX_SHADER, vert );
AttachShader( prog, GL_FRAGMENT_SHADER, frag );
glBindAttribLocation(prog, 0, "a_position");
glBindAttribLocation(prog, 1, "a_textureCoordinate");
glBindAttribLocation(prog, 2, "a_index");
glLinkProgram( prog );
CheckStatus( prog, false );
glUseProgram( prog );
All together:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
void CheckStatus( GLuint obj, bool isShader )
{
GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
std::cerr << (GLchar*)log << "\n";
std::exit( EXIT_FAILURE );
}
void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader, true );
glAttachShader( program, shader );
glDeleteShader( shader );
}
const char* const vert = R"GLSL(
#version 130
attribute vec4 a_position;
attribute vec2 a_textureCoordinate;
attribute float a_index;
out vec2 v_textureCoordinate;
flat out uint v_index;
void main()
{
gl_Position = a_position;
v_textureCoordinate = a_textureCoordinate;
v_index = uint(a_index);
}
)GLSL";
const char* const frag = R"GLSL(
#version 130
in vec2 v_textureCoordinate;
flat in uint v_index;
uniform sampler2D u_texture0;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
uniform sampler2D u_texture3;
uniform sampler2D u_texture4;
uniform sampler2D u_texture5;
uniform sampler2D u_texture6;
uniform sampler2D u_texture7;
out vec4 o_color;
void main()
{
// dynamic indexing is not suppourted in GLSL version 1.30 therefore the most suitable solution is to switch case between them
switch(v_index)
{
case 0u:
o_color = texture2D(u_texture0, v_textureCoordinate);
return;
case 1u:
o_color = texture2D(u_texture1, v_textureCoordinate);
return;
case 2u:
o_color = texture2D(u_texture2, v_textureCoordinate);
return;
case 3u:
o_color = texture2D(u_texture3, v_textureCoordinate);
return;
case 4u:
o_color = texture2D(u_texture4, v_textureCoordinate);
return;
case 5u:
o_color = texture2D(u_texture5, v_textureCoordinate);
return;
case 6u:
o_color = texture2D(u_texture6, v_textureCoordinate);
return;
case 7u:
o_color = texture2D(u_texture7, v_textureCoordinate);
return;
default:
return;
}
}
)GLSL";
GLuint loadTexture(const unsigned char* image, int w, int h)
{
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
return texture;
}
void resetViewport(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
int main()
{
// initialising GLFW
if(!glfwInit())
{
perror("error with glfw!");
exit(1);
}
// window creation
GLFWwindow* window;
window = glfwCreateWindow(800, 500, "window", NULL, NULL);
glfwSetWindowSizeCallback(window, resetViewport);
// binding renderring context
glfwMakeContextCurrent(window);
// initialising glew
if(glewInit() != GLEW_OK)
perror("error with glee!");
// enabling blend
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// creating program and shaders
GLuint prog = glCreateProgram();
AttachShader( prog, GL_VERTEX_SHADER, vert );
AttachShader( prog, GL_FRAGMENT_SHADER, frag );
glBindAttribLocation(prog, 0, "a_position");
glBindAttribLocation(prog, 1, "a_textureCoordinate");
glBindAttribLocation(prog, 2, "a_index");
glLinkProgram( prog );
CheckStatus( prog, false );
glUseProgram( prog );
// creating vertex array
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// creating vertex buffer
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// vertex buffer layout
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), NULL);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void*)(2 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void*)(4 * sizeof(float)));
// creating texture
const unsigned char image1[] = { 255, 0, 0, 255 };
GLuint texture0 = loadTexture( image1, 1, 1 );
const unsigned char image2[] = { 0, 255, 0, 255 };
GLuint texture1 = loadTexture( image2, 1, 1 );
// vertex data
float vertexes[] =
{
// x y u v i (index)
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.0f, -1.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, +1.0f, 0.0f, 1.0f, 1.0f,
+1.0f, +1.0f, 1.0f, 1.0f, 1.0f,
+1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
};
// unbinding just incase
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// rebinding
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// binding texture to texture slot
glUniform1i(glGetUniformLocation(prog, "u_texture0"), 0);
glUniform1i(glGetUniformLocation(prog, "u_texture1"), 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture1);
// sending data
glBufferData(GL_ARRAY_BUFFER, 8 * 5 * sizeof(float), vertexes, GL_STATIC_DRAW);
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
// clear screen
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw call
glDrawArrays(GL_QUADS, 0, 8);
// updating window's buffer
glfwSwapBuffers(window);
}
// error logging
GLenum error = glGetError();
if(error != GL_NO_ERROR)
printf("error: %u\n", error);
// termination
glDeleteTextures(1, &texture0);
glDeleteTextures(1, &texture1);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(prog);
glfwTerminate();
}

OpenGL fragment shader for GL_LINES only renders lines when shader compilation fails

I've looked for an answer to my problem for two days. Maybe I'm just terrible at searching but there doesn't seem to be an answer already out there.
I am trying to draw lines on the screen using OpenGL's glDrawArrays(GL_LINES, ..., ...). This is the current code for my fragment shader:
#version 330 core
in vec4 vertexColor;
out vec4 color;
void main( )
{
//color = vec3(0.5f, 1.0f, 1.0f);
color = vec4(0.5f, 1.0f, 1.0f, 0.5f);
//color = vertexColor;
}
Originally the color=vertexColor line was supposed to work, but nothing appeared on the screen. I thought maybe something was wrong with the data being sent from the vertex shader so I tried setting the output manually in the fragment shader. I accidentally made it a vec3 instead of a vec4 and I got an error in my console window telling me compilation of the shader had failed. But the lines appeared! They showed up in the right spot as white/gray lines of static. When I corrected the mistake and set the output to a vec4, like shown, the lines were invisible again and I had no compilation error.
What am I doing wrong that makes my lines invisible?
Edit:
Here is my first go at a "minimal, complete, and verifiable example". If you link a project with these files to GLEW, GLFW and GLM, this should run on your system. If I'm not supposed to upload a whole program, I apologize. This seems a bit big, but I don't know how else it could be "complete".
Instead of making two white static lines, this one is making only one solid black line when the fragment shader fails to compile. It still renders nothing when compilation is successful.
Main.cpp
#define GLEW_STATIC
#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 "ShaderMaker.h"
#include "TargetBox.h"
const GLint WIDTH = 800, HEIGHT = 600;
//Camera
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
GLfloat yaw = -90.0f;
GLfloat pitch = 0.0f;
// Delta time
GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;
int main() {
cameraFront.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront.y = sin(glm::radians(pitch));
cameraFront.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront = glm::normalize(cameraFront);
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, "Debugger", nullptr, nullptr);
int screenWidth, screenHeight;
glfwGetFramebufferSize(window, &screenWidth, &screenHeight);
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (GLEW_OK != glewInit()) {
std::cout << "Failed to initialize GLEW" << std::endl;
return EXIT_FAILURE;
}
glViewport(0, 0, screenWidth, screenHeight);
glEnable(GL_DEPTH_TEST);
TargetBox tb;
GLuint modelLoc = tb.getUniform("model");
GLuint viewLoc = tb.getUniform("view");
GLuint projectionLoc = tb.getUniform("projection");
glm::mat4 projection;
projection = glm::perspective(glm::radians(45.0f), (float)screenWidth / screenHeight, 0.1f, 100.0f);
while (!glfwWindowShouldClose(window)) {
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glfwPollEvents();
glClearColor(0.5f, 0.7f, 0.9f, 1.0f); // Unnecessary, but adds some color to an otherwise blank window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 view;
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
tb.useShader();
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(tb.getVAO());
glm::vec3 posMod = tb.getPos();
glm::mat4 model;
model = glm::translate(model, glm::vec3(posMod.x, posMod.y, posMod.z));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_LINES, 0, 4);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
glfwTerminate();
return EXIT_SUCCESS;
}
ShaderMaker.h
#pragma once
#ifndef SHADERMAKER_H
#define SHADERMAKER_H
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<GL/glew.h>
class ShaderMaker {
public:
// The program ID
GLuint Program;
// Constructor reads and builds the shader
ShaderMaker(const GLchar* vertexPath, const GLchar* fragmentPath) {
// 1. Retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensures ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::badbit);
try {
// Open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// Convert stream into GLchar array
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
}
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar* fShaderCode = fragmentCode.c_str();
// 2. Compile shaders
GLuint fragment;
GLint success;
GLchar infoLog[512];
// Vertex shader
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Similar for fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Shader program
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
// Print linking errors if any
glGetShaderiv(this->Program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// Delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// Use the program
void Use() { glUseProgram(this->Program); }
// Get a uniform
GLint getUniform(const GLchar * name) {
return glGetUniformLocation(this->Program, name);
}
};
#endif
TargetBox.h
#pragma once
#ifndef TARGETBOX_H
#define TARGETBOX_H
#define GLEW_STATIC
#include <GL/glew.h>
#include<glm/glm.hpp>
#include <GLFW/glfw3.h>
#include "ShaderMaker.h"
class TargetBox
{
public:
TargetBox();
~TargetBox();
void useShader();
GLuint getVAO();
glm::vec3 getPos();
void setPos(glm::vec3 p);
GLuint getUniform(GLchar * u);
private:
glm::vec3 pos;
GLuint VAO, VBO;
const GLchar *vertexShaderPath = ".\\VShaderLine.txt";
const GLchar *fragmentShaderPath = ".\\FShaderLine.txt";
ShaderMaker shader = ShaderMaker(vertexShaderPath, fragmentShaderPath);
};
#endif
TargetBox.cpp
#include "TargetBox.h"
TargetBox::TargetBox()
{
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
GLfloat vertices[] = {
-2, 0, -5, 1.0f, 1.0f, 1.0f,
2, 0, 5, 1.0f, 1.0f, 1.0f,
2, 0, 5, 1.0f, 0.0f, 0.0f,
2, 10, 5, 0.0f, 1.0f, 0.0f
};
size_t data_len = sizeof(vertices);
glBufferData(GL_ARRAY_BUFFER, data_len, vertices, GL_STATIC_DRAW);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid *)0);
glEnableVertexAttribArray(0);
//Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
TargetBox::~TargetBox()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
}
void TargetBox::useShader() { shader.Use(); }
GLuint TargetBox::getVAO() { return VAO; }
glm::vec3 TargetBox::getPos() { return pos; }
void TargetBox::setPos(glm::vec3 p) { pos = p; }
GLuint TargetBox::getUniform(GLchar * u) { return shader.getUniform(u); }
VShaderLine.txt
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
out vec4 vertexColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main( )
{
// The order of multiplication is important?
gl_Position = projection * view * model * vec4( position, 1.0 );
vertexColor = vec4(color.xyz, 1.0f);
}
FShaderLine.txt
#version 330 core
in vec4 vertexColor;
out vec4 color;
void main( )
{
color = vec3(0.5f, 1.0f, 1.0f);
//color = vec4(0.5f, 1.0f, 1.0f, 0.5f);
//color = vertexColor;
}