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();
}
Related
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
};
I'm trying to display an image on the whole window.
For that, I only draw a rectangle which take the whole window and apply it a texture.
The problem is that the image does not fill the whole screen at all:
Output image
The image isn't too small since it is 5600 x 3000. Also, I don't want the image to be repeat. I don't what i've missed, why it does't fill the screen and why it's only on the top left corner. I already try this solution and it didn't work: Texture does not fit in the square - OpenGL
Here's how I create and bind my shaders:
Shader::Shader(const char* vertSrcFile, const char* fragSrcFile, const char* texSrcFile) {
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
GLint vlen;
GLint flen;
char* source = loadFile(vertSrcFile, vlen);
char* fragment = loadFile(fragSrcFile, flen);
glShaderSource(vertShader, 1, &source, &vlen);
glShaderSource(fragShader, 1, &fragment, &flen);
GLint compiled = 0;
glCompileShader(vertShader);
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint maxLength = 0;
glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(vertShader, maxLength, &maxLength, &infoLog[0]);
// We don't need the shader anymore.
glDeleteShader(vertShader);
Logger::GetSystemLogger()->error("Vertex shader compilation error");
Logger::GetSystemLogger()->error("{}", infoLog.data());
return;
}
glCompileShader(fragShader);
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint maxLength = 0;
glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(fragShader, maxLength, &maxLength, &infoLog[0]);
// We don't need the shader anymore.
glDeleteShader(fragShader);
Logger::GetSystemLogger()->error("Fragment shader compilation error");
Logger::GetSystemLogger()->error("{}", infoLog.data());
return;
}
prog = glCreateProgram();
glAttachShader(prog, vertShader);
glAttachShader(prog, fragShader);
glLinkProgram(prog);
GLint isLinked = 0;
glGetProgramiv(prog, GL_LINK_STATUS, (int*)&isLinked);
if (isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(prog, maxLength, &maxLength, &infoLog[0]);
// We don't need the program anymore.
glDeleteProgram(prog);
// Don't leak shaders either.
glDeleteShader(vertShader);
glDeleteShader(fragShader);
Logger::GetSystemLogger()->error("Program link error");
Logger::GetSystemLogger()->error("{}", infoLog.data());
return;
}
glDetachShader(prog, vertShader);
glDetachShader(prog, fragShader);
glGenTextures(1, &texID); // generate texture ID
glBindTexture(GL_TEXTURE_2D, texID);
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_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
LoadTexture(texSrcFile);
}
Here's how I load my image as a texture:
void Shader::LoadTexture(const char* texSrcFile) const {
int width, height, nrChannels;
unsigned char* data = stbi_load(texSrcFile, &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);
}
else
{
Logger::GetSystemLogger()->error("Failed to load textures");
}
stbi_image_free(data);
}
Here's my Shaders:
Fragment:
#version 330
precision highp float; // needed only for version 1.30
layout(location = 0) out vec4 out_Color;
in vec2 ex_Tex;
uniform sampler2D textureUnit0;
void main(void){
out_Color = texture(textureUnit0, ex_Tex);
}
vertex:
#version 330
layout (location = 0) in vec3 in_Position;
layout (location = 1) in vec2 in_Tex;
out vec2 ex_Tex;
void main(void){
gl_Position = vec4(in_Position, 1.0);
ex_Tex = in_Tex;
}
Here's the main code:
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
glGenBuffers(1, &m_VBO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
GLfloat vertices[4 * 5]{
// Positions // Textures
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
// Texture coord
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
glGenBuffers(1, &m_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
unsigned int indices[6] = { 0, 1, 2, 0, 1, 3 };
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
m_Shader = std::make_shared<Engine::Shader>("src/Shaders/Background.vert", "src/Shaders/Background.frag", "res/background.jpg");
And here's the main loop
while (m_Running) {
// clear the screen and set the background color to grey
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
m_Shader->Bind();
glBindTexture(GL_TEXTURE_2D, m_Shader->GetTexID());
glBindVertexArray(m_VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
m_Window->OnUpdate();
}
Though the viewport coordinates go from negative one to one [-1, 1), texture coordinates go from zero to one [0,1). Therefore three quarters of your viewport are filled with black according to the GL_CLAMP_TO_BORDER policy.
You need to fix your VAO coordinates as follows:
GLfloat vertices[4 * 5]{
// Positions // Textures
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f
};
EDIT: Also your texture coordinates offset is incorrect. It should be:
// Texture coord
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float)));
Without the proper offset it is using the X and Y of the position for the texture coordinates.
I'm trying to render a simple blue box to a texture, so that I can pass the texture to ImGui to render it as an image. For some reason though, I only ever get a simply white texture, and I can't figure out why. I've stripped my class down to as simple a case that I can, but I still only ever get a solid white texture, instead of a blue box that takes up most of the screen.
main.cpp
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
GLFWwindow * window;
GLuint solid_texture;
GLuint loadShaders(const char * vertex_file_source, const char * fragment_file_source)
{
// Create the shaders
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
GLuint framgent_shader_id = glCreateShader(GL_FRAGMENT_SHADER);
GLint Result = GL_FALSE;
int InfoLogLength;
glShaderSource(vertex_shader_id, 1, &vertex_file_source, NULL);
glCompileShader(vertex_shader_id);
// Check Vertex Shader
glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &Result);
glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(vertex_shader_id, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
std::cerr << VertexShaderErrorMessage[0] << std::endl;
}
glShaderSource(framgent_shader_id, 1, &fragment_file_source, NULL);
glCompileShader(framgent_shader_id);
// Check Fragment Shader
glGetShaderiv(framgent_shader_id, GL_COMPILE_STATUS, &Result);
glGetShaderiv(framgent_shader_id, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(framgent_shader_id, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
std::cerr << FragmentShaderErrorMessage[0] << std::endl;
}
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, vertex_shader_id);
glAttachShader(ProgramID, framgent_shader_id);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
std::cerr << ProgramErrorMessage[0] << std::endl;
}
glDetachShader(ProgramID, vertex_shader_id);
glDetachShader(ProgramID, framgent_shader_id);
glDeleteShader(vertex_shader_id);
glDeleteShader(framgent_shader_id);
return ProgramID;
}
void generate_solid_texture()
{
glGenTextures(1, &solid_texture);
// Solid texture
unsigned char solidTexturePixels[4];
solidTexturePixels[0] = ~0;
solidTexturePixels[1] = ~0;
solidTexturePixels[2] = ~0;
solidTexturePixels[3] = ~0;
glBindTexture(GL_TEXTURE_2D, solid_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, solidTexturePixels);
glBindTexture(GL_TEXTURE_2D, 0);
}
int main(void)
{
// Initialise GLFW
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
window = glfwCreateWindow(1024, 768, "Tutorial 14 - Render To Texture", NULL, NULL);
if (window == NULL) {
fprintf(stderr,
"Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 "
"version of the tutorials.\n");
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// We would expect width and height to be 1024 and 768
int windowWidth = 1024;
int windowHeight = 768;
// But on MacOS X with a retina screen it'll be 1024*2 and 768*2, so we get the actual framebuffer size:
glfwGetFramebufferSize(window, &windowWidth, &windowHeight);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
glfwPollEvents();
glfwSetCursorPos(window, 1024 / 2, 768 / 2);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Setup OpenGL shaders
std::string vertex_shader_source =
R""(
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 uv;
layout (location = 2) in vec3 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
out vec2 frag_uv;
out vec4 frag_color;
void main()
{
frag_uv = uv;
frag_color = vec4(color, 1.0f);
gl_Position = proj_matrix * mv_matrix * vec4(position.xyz, 1);
}
)"";
std::string fragment_shader_source =
R""(
#version 330 core
uniform sampler2D Texture;
in vec2 frag_uv;
in vec4 frag_color;
layout (location = 0) out vec4 color;
void main()
{
// color = frag_color * texture(Texture, frag_uv.st);
// color = vec4((frag_color * texture(Texture, frag_uv)).xyz, 1);
color = frag_color * texture(Texture, frag_uv.st);
}
)"";
GLuint program_id = loadShaders(vertex_shader_source.c_str(), fragment_shader_source.c_str());
generate_solid_texture();
// Heatmap objects
GLuint m_vao, m_vbo, m_uvbo, m_cbo;
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glGenBuffers(1, &m_vbo);
glGenBuffers(1, &m_uvbo);
glGenBuffers(1, &m_cbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, m_uvbo);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, m_cbo);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
// Create the FBO for later
GLuint fbo, map_texture;
glGenFramebuffers(1, &fbo);
glGenTextures(1, &map_texture);
glBindVertexArray(0);
GLsizei heat_map_width = 600;
GLsizei heat_map_height = 600;
std::vector<float> map_vertices, map_vertex_uvs, map_vertex_colors;
std::vector<float> solid_uv = {0.0f, 0.0f};
std::vector<float> bl = {0, 0}, br = {1.0f, 0}, tl = {0, 1.0f}, tr = {1.0f, 1.0f};
map_vertices = {bl[0], bl[1], 1.0f, tr[0], tr[1], 1.0f, tl[0], tl[1], 1.0f,
bl[0], bl[1], 1.0f, br[0], br[1], 1.0f, tr[0], tr[1], 1.0f};
map_vertex_uvs = {solid_uv[0], solid_uv[1], solid_uv[0], solid_uv[1], solid_uv[0], solid_uv[1],
solid_uv[0], solid_uv[1], solid_uv[0], solid_uv[1], solid_uv[0], solid_uv[1]};
map_vertex_colors = {0.0f, 0.0f, 1.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, 0.0f, 0.0f, 1.0f};
glUseProgram(program_id);
glBindTexture(GL_TEXTURE_2D, map_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, heat_map_width, heat_map_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, map_texture, 0);
// glViewport(0, 0, heat_map_width, heat_map_height);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
glClearColor(0.0f, 0.0f, 0.0f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(m_vao);
// Vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, map_vertices.size() * sizeof(map_vertices[0]), map_vertices.data(), GL_STATIC_DRAW);
// UV buffer
glBindBuffer(GL_ARRAY_BUFFER, m_uvbo);
glBufferData(GL_ARRAY_BUFFER, map_vertex_uvs.size() * sizeof(map_vertex_uvs[0]), map_vertex_uvs.data(),
GL_STATIC_DRAW);
// Color buffer
glBindBuffer(GL_ARRAY_BUFFER, m_cbo);
glBufferData(GL_ARRAY_BUFFER, map_vertex_colors.size() * sizeof(map_vertex_colors[0]), map_vertex_colors.data(),
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
static const GLfloat identity_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
GLuint move_matrix_location = glGetUniformLocation(program_id, "mv_matrix");
GLuint projection_matrix_location = glGetUniformLocation(program_id, "proj_matrix");
GLuint texture_location = glGetUniformLocation(program_id, "Texture");
glUniformMatrix4fv(move_matrix_location, 1, GL_FALSE, identity_matrix);
glUniformMatrix4fv(projection_matrix_location, 1, GL_FALSE, identity_matrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, solid_texture);
glUniform1i(texture_location, 0);
glDrawArrays(GL_TRIANGLES, 0, map_vertices.size() / 3);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
// Framebuffer to texture
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Always check that our framebuffer is ok
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
// The fullscreen quad's FBO
static const GLfloat g_quad_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
};
static const GLfloat g_quad_vertex_uv_data[] = {
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
};
static const GLfloat g_quad_vertex_color_data[] = {
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,
};
GLuint quad_vao;
glGenVertexArrays(1, &quad_vao);
glBindVertexArray(quad_vao);
GLuint quad_vertexbuffer;
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
GLuint quad_uvbuffer;
glGenBuffers(1, &quad_uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_uvbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_uv_data), g_quad_vertex_uv_data, GL_STATIC_DRAW);
GLuint quad_colorbuffer;
glGenBuffers(1, &quad_colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_color_data), g_quad_vertex_color_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, quad_uvbuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, quad_colorbuffer);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
glBindVertexArray(0);
do {
// Render to our framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(
0, 0, windowWidth,
windowHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right
// Clear the screen
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(program_id);
// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render on the whole framebuffer, complete from the lower left corner to the upper right
glViewport(0, 0, windowWidth, windowHeight);
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(program_id);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, map_texture);
// Set our "renderedTexture" sampler to use Texture Unit 0
glUniform1i(texture_location, 0);
glBindVertexArray(quad_vao);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glBindVertexArray(0);
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
I am fairly certain the issue is not with the vertex or fragment shaders, because I use them in another renderer class and that one works fine. Please let me know if I can provide anything else that would be of use.
Major Edit: I've created a minimal reproducible example of my issue.
Edit2: I believe I have updated it for the better, but now showing a black screen instead of a white one. I ran the generate_solid_texture function, enabled the verex atttrib arrays for the quad_vao, and set the framebuffer to default in the main loop.
I'm writing my program, that draws a quad with a texture. Here's my code:
#include <stdio.h>
#include <stdlib.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL.h>
#include <math.h>
extern const char* VertexShaderCode;
extern const char* FragmentShaderCode;
int main()
{
glfwInit();
glewInit();
//initialize glew
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
int width = 1920, height = 1080;
glViewport(0, 0, width, height);
GLFWwindow* window = glfwCreateWindow(width, height, "Opengl program", NULL, NULL);
glfwGetFramebufferSize(window, &width, &height);
if (!window)
{
printf("Someting is wrong with window");
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
printf("Something is wrong with glew");
}
/*GLfloat vertecies[] = {
0.75f, 0.75f, 0.0f, //0
0.75f, -0.75f, 0.0f, //1
-0.75f, -0.75f, 0.0f, //2
-0.75f, 0.75f, 0.0f, //3
0.5f, 0.5f, 0.0f, //0
0.5f, -0.5f, 0.0f, //1
-0.5f, -0.5f, 0.0f, //2
-0.5f, 0.5f, 0.0f, //3
};
GLuint index[] =
{
0,4,1,
4,1,5,
5,1,2,
6,2,5,
2,6,3,
6,7,3,
3,7,4,
3,4,0
};*/
GLfloat vertecies[] = {
//vertices colors
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
};
GLuint index[] =
{
0,1,3,
1,2,3
};
GLfloat texCoords[] = {
0.0f, 0.0f, // Lower-left corner
1.0f, 0.0f, // Lower-right corner
0.5f, 1.0f // Top-center corner
};
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_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int widthText, heightText;
unsigned char* image = SOIL_load_image("container.jpg", &widthText, &heightText, 0, SOIL_LOAD_RGB);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, widthText, heightText, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GLuint EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW);
GLuint VAO;
glGenVertexArrays(1, &VAO);
GLuint VBO;
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertecies), vertecies, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW);
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);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
const char* adapter[1];
GLuint vertexShaderID;
vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
adapter[0] = VertexShaderCode;
glShaderSource(vertexShaderID, 1, adapter, 0);
glCompileShader(vertexShaderID);
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShaderID, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED %s\n", infoLog);
}
//declare fragment shader
GLuint fragmentShaderID;
//create fragment shader
fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
//set fragment shader source
adapter[0] = FragmentShaderCode;
glShaderSource(fragmentShaderID, 1, adapter, 0);
//compile fragment shader
glCompileShader(fragmentShaderID);
//declare a shader program
GLuint shaderProgram;
shaderProgram = glCreateProgram();
//attach haders to the program
glAttachShader(shaderProgram, vertexShaderID);
glAttachShader(shaderProgram, fragmentShaderID);
//link program
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
//rendering
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
//glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glDisableClientState(GL_VERTEX_ARRAY);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glfwTerminate();
return 0;
}
The vertex attrib array is not setting texture vertex input as my third input. Can anyone see, whyt am I doing wrong? Oh and here's my shader code:
const char* VertexShaderCode =
"#version 330 core\r\n"
""
"layout(location=0) in vec3 position;"
"layout(location=1) in vec3 color;"
"layout(location=2) in vec2 textCoord;"
""
"out vec2 TextCoord;"
""
""
"out vec3 theColor;"
""
"void main()"
"{"
" gl_Position = vec4(position, 1.0);"
" theColor = color;"
" TextCoord = textCoord;"
"}";
const char* FragmentShaderCode =
"#version 330 core\r\n"
""
"in vec3 theColor;"
"in vec2 TexCoord;"
""
"uniform sampler2D ourTexture;"
""
""
""
"out vec4 color;"
""
"void main()"
"{"
" color = texture(ourTexture, TexCoord);"
"}";
Help.
The variable is called out vec2 TextCoord in the vertex shader, but in vec2 TexCoord; in the fragment shader (note the additional t in the vertex shader).
You are only checking the compile status of the vertex shader, but not the compile status of the fragment shader or the link status of the program.
This question already has an answer here:
OpenGL texture tilted
(1 answer)
Closed 1 year ago.
I'm trying to upload a texture in OpenGL but the texture is crooked.
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <SOIL/SOIL.h>
#define GLSL(version, shader) "#version " #version "\n" #shader
const char * vertShader = GLSL(430,
in vec2 position;
in vec2 texcoord;
out vec2 coordinates;
void main() {
coordinates = texcoord;
gl_Position = vec4(position, 0.0, 1.0);
}
);
const char * fragShader = GLSL(430,
in vec2 coordinates;
out vec4 color;
uniform sampler2D texture;
void main() {
color = texture(texture, coordinates);
}
);
int main(int argc, char ** argv)
{
if (not glfwInit())
{
std::cerr << "Failed to initialize GLFW" << std::endl;
return -1;
}
GLFWwindow *window;
window = glfwCreateWindow(720, 480, "Textures", 0, 0);
if (not window)
{
std::cerr << "Failed to open GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK)
{
std::cerr << "Failed to initialize GLEW" << std::endl;
return -1;
}
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
-1.0f, +1.0f, 0.0f, 0.0f,
+1.0f, +1.0f, 1.0f, 0.0f,
+1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint ebo;
glGenBuffers(1, &ebo);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertShader, 0);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragShader, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));
glEnableVertexAttribArray(texAttrib);
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
int width, height;
unsigned char * image = SOIL_load_image("happyface.png", &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
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);
do {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
glfwSwapBuffers(window);
} while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS
&& glfwWindowShouldClose(window) == 0);
glDeleteTextures(1, &tex);
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();
return 0;
}
What am I doing wrong? As you can see the texture is crooked and repeating, but the texture is just one smiley face.
That is the result:
And that is the texture:
I'm no OpenGL guru, but some graphics systems require textures that are multiples of 2 or 4 pixels wide.
Your texture is 479 wide - add another column of pixels and I think you'll be fine.