Related
main.cpp
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glad/glad.h>
#include <fstream>
#include <iostream>
#include <string>
#include <stdio.h>
#include <SOIL/SOIL.h>
typedef struct vertex{
float x; float y; float z;
float texX; float texY;
float texIndex;
} vertex;
void readTextFile(const char* path, std::string* dst);
int main(){
std::cout << 3 << std::endl;
GLFWwindow* window;
if(!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(640, 480, "Geometry Shader Bathing with Texture Atlas", NULL, NULL);
if(!window){
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
gladLoadGL();
glfwSwapInterval(1);
glFrontFace(GL_CW);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//create and set vertex buffer
vertex vertices[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.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, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
};
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
//create vertex shader
std::string* shaderSource = new std::string();
readTextFile("shader/vertexShader.glsl", shaderSource);
const char* vertexShaderSourcePtr = shaderSource->c_str();
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSourcePtr, NULL);
glCompileShader(vertexShader);
GLint status;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE){
char buffer[512];
glGetShaderInfoLog(vertexShader, 512, NULL, buffer);
std::cout << "vertexShader FAIL : " << std::endl <<
shaderSource <<std::endl
<< buffer << std::endl;
}else{
std::cout << "vertexShader compile success!" << std::endl;
}
//create fragment shader
readTextFile("shader/fragmentShader.glsl", shaderSource);
const char* fragmentShaderSourcePtr = shaderSource->c_str();
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSourcePtr, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE){
char buffer[512];
glGetShaderInfoLog(fragmentShader, 512, NULL, buffer);
std::cout << "fragmentShader FAIL : " << std::endl <<
shaderSource <<std::endl
<< buffer << std::endl;
}else{
std::cout << "fragmentShader compile success!" << std::endl;
}
delete shaderSource;
//create and set program
GLint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glBindAttribLocation(program, 0, "inPos");
glBindAttribLocation(program, 1, "inTex");
glBindAttribLocation(program, 2, "inTexIndex");
glLinkProgram(program);
//set frameBuffer(renderTarget) index and fragmentShader output name
glBindFragDataLocation(program, 0, "outColor");
glUseProgram(program);
//create and set texture
int width = 384;
int height = 384;
unsigned char* textureRawData0 = SOIL_load_image("resource/character/test0.png", &width, &height, 0, SOIL_LOAD_RGBA);
unsigned char* textureRawData1 = SOIL_load_image("resource/character/test1.png", &width, &height, 0, SOIL_LOAD_RGBA);
glUniform1i(glGetUniformLocation(program, "texture0"), 0);
glUniform1i(glGetUniformLocation(program, "texture1"), 1);
GLuint texture1;
glGenTextures(1, &texture1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureRawData0);
SOIL_free_image_data(textureRawData0);
std:: cout << "texture0: " << glGetUniformLocation(program, "texture0") << std::endl;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLuint texture2;
glGenTextures(1, &texture2);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureRawData1);
SOIL_free_image_data(textureRawData1);
std:: cout << "texture1: " << glGetUniformLocation(program, "texture1") << std::endl;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//input layout : vertex Attribute
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glLinkProgram(program);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)(5 * sizeof(float)));
while(!glfwWindowShouldClose(window)){
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 12);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void readTextFile(const char* path, std::string* dst){
std::ifstream f;
f.open(path);
if(f.is_open()){
std::string buff;
dst->clear();
while(!f.eof()){
std::getline(f, buff);
dst->append(buff);
dst->push_back('\n');
}
dst->push_back('\0');
f.close();
}else{
std::cout << "파일 열기 실패 : " << *dst << std::endl;
}
}
ps
#version 330 core
in vec2 outTex;
in float outTexIndex;
out vec4 outColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
void main(){
if(outTexIndex == 0.0f){
outColor = texture(texture0, outTex);
}
else if(outTexIndex == 1.0f){
outColor = texture(texture1, outTex) + vec4(0.5f, 0.5f, 0.5f, 1.0f);
}
}
The input layout(vertex attribute) works fine.
TexIndex is transferred correctly. 1.0f and 0.0f
But the problem is
//fragment shader
texture(texture0, outTex);
texture(texture1, outTex);
both returns same texture color but it is actually different texture from test1.png and test2.png. what is the problem with my code?
++
I tried below fragment shader following the answer of #Rabbid76
#version 330 core
in vec2 outTex;
in float outTexIndex;
out vec4 outColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
void main()
{
vec4 c1 = texture(texture0, outTex) + vec4(0.5f, 0.0f, 0.0f, 1.0f);
vec4 c2 = texture(texture1, outTex) + vec4(0.0f, 0.5f, 0.0f, 1.0f);
outColor = mix(c1, c2, outTexIndex);
}
Color applied but still sampling from same the texture. looks like somehow glActiveTexture(i); doesn't work.
ps. test1.png and test2.png is completely different picture. above screenshot is test1.png
++ when I changed
glGenTexture(1, &texture0);
glGenTexture(1, &texture1);
to
glGenTexture(0, &texture0);
glGenTexture(0, &texture1);
then sampler2D texture0 and sampler2D texture1 both sample from texture1 test1.png (not form texture0 which is test0.png)
what is happening?
++
vs
#version 330
in vec3 inPos;
in vec2 inTex;
in float inTexIndex;
out vec2 outTex;
out float outTexIndex;
void main(){
outTex = inTex;
gl_position = vec4(inPos, 1.0f);
outTexIndex = inTexIndex;
}
Since the condition if(outTexIndex == 0.0f) depends on a fragment shader input, that may cause undefined behavior.
See (most recent) OpenGL Shading Language 4.60 Specification - 8.9. Texture Functions
[...] Some texture functions (non-“Lod” and non-“Grad” versions) may require implicit derivatives. Implicit derivatives are undefined within non-uniform control flow and for non-fragment shader texture fetches. [...]
respectively Non-uniform flow control.
Lookup both textures and mix the colors to solve the issue:
#version 330 core
in vec2 outTex;
in float outTexIndex;
out vec4 outColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
void main()
{
vec4 c1 = texture(texture0, outTex);
vec4 c2 = texture(texture1, outTex) + vec4(0.5f, 0.5f, 0.5f, 1.0f);
outColor = mix(c1, c2, outTexIndex);
}
I thought if I have a compiled example of multiple textures that working no problem, then I can find the problem of my code changing my code line to line comparing with the example. So I found this one.
tutorial
example code
It was SDL based. So I changed initialization code and loop to glfw. And It worked fine on my environment.
Even after I changed my code's texture loading part completely same with the example, the problem wasn't solved. So it must be other part that makes the problem. Finally, I found this.
//input layout : vertex Attribute
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//*****here!*****
//glLinkProgram(program);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)(5 * sizeof(float)));
After I just add two characters "//", result was shown as I intended.
I'm not sure about the reason that one line of code makes problem.
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();
}
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 using GLFW and GLEW to initialize a window, and SOIL to load image data for a texture. I'm trying (and failing) to load a texture to display on a simple square in the middle of the screen.
Here's the code:
GLuint VAO, VBO, EBO, texture, shaderProgram;
GLFWWindow* window;
const char* vertexShaderSource = //Shown later
const char* fragmentShaderSource = //Shown later
void init()
{
glfwInit();
window = glfwCreateWindow(320, 288, "GameBozo", nullptr, nullptr);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glewInit()
glViewport(0, 0, 320, 288);
GLfloat 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
};
GLuint indices[] = {
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
//Generate vertex arrays and buffers
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);
//Shaders
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// TexCoord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
// Load and create a texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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_NEAREST);
int width, height;
GLubyte* image = SOIL_load_image("path\to\image.jpg", &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
}
And then the main loop:
void main()
{
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
And finally, the vertex shader:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(position, 1.0f);
ourColor = color;
TexCoord = texCoord;
}
And the fragment shader:
#version 330
in vec3 ourColor;
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture;
void main()
{
color = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
}
I don't know what I'm doing wrong... the square will just show up white.
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.