I have the following OpenGL/GLSL code. I'm trying to take two textures into a shader and get two different textures out.
At the moment I'm only doing pointless calculations. But for my actually application (HDR imaging) I need to get two+ textures in and out of a single shader.
My issue is in the int main() I don't know how to display one of the output textures on a quad.
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <stdio.h>
const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"in vec3 color;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"out vec3 Color;"
"void main() {"
" Color = color;"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
const GLchar* fragmentSource =
"#version 150 core\n"
"in vec3 Color;"
"in vec2 Texcoord;"
"out vec4 outColor1;"
"out vec4 outColor2;"
"uniform sampler2D texLena;"
"uniform sampler2D texTex7;"
"void main() {"
" vec4 colLena = texture(texLena, Texcoord);"
" vec4 colTex7 = texture(texTex7, Texcoord);"
" outColor1 = mix(colLena, colTex7, 0.75) * vec4(Color, 1.0);"
" outColor2 = mix(colLena, colTex7, 0.25);"
"}";
void printShaderInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
int main()
{
if (glfwInit() != GL_TRUE)
{
fprintf(stderr, "Failed to initialize GLFW\n");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", glfwGetPrimaryMonitor(), NULL);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 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, &vertexSource, NULL);
glCompileShader(vertexShader);
printShaderInfoLog(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
printShaderInfoLog(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor1");
glBindFragDataLocation(shaderProgram, 1, "outColor2");
glLinkProgram(shaderProgram);
printProgramInfoLog(shaderProgram);
glUseProgram(shaderProgram);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE,
7*sizeof(float), (void*)(2*sizeof(float)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
7*sizeof(float), (void*)(5*sizeof(float)));
GLuint textures[2];
glGenTextures(2, textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
cv::Mat image = cv::imread("lena.tiff");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows, 0,
GL_BGR, GL_UNSIGNED_BYTE, image.data);
image.release();
glUniform1i(glGetUniformLocation(shaderProgram, "texLena"), 0);
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);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
image = cv::imread("tex7.jpg");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows, 0,
GL_BGR, GL_UNSIGNED_BYTE, image.data);
glUniform1i(glGetUniformLocation(shaderProgram, "texTex7"), 1);
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 frameBuffer;
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
GLuint texFront;
glGenTextures(1, &texFront);
glBindTexture(GL_TEXTURE_2D, texFront);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows,0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texFront, 0);
GLuint texBack;
glGenTextures(1, &texBack);
glBindTexture(GL_TEXTURE_2D, texBack);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows,0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texBack, 0);
image.release();
GLenum bufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, bufs);
while(!glfwWindowShouldClose(window))
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// What should I be doing here?
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texFront);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteTextures(1, textures);
glDeleteTextures(1, &texFront);
glDeleteTextures(1, &texBack);
glDeleteFramebuffers(1, &frameBuffer);
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();
return 0;
}
How do I select texFront (which is my COLOR_ATTACHMENT0) to be displayed when I glDrawElements?
EDIT

I am getting a weird result where part of COLOR_ATTACHMENT0 appears when I try display COLOR_ATTACHMENT1
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex2);
Then glUniform1i to point the uniform sampler2Ds to the texture bind points (0/1).
Read as normal (i.e. texture()/texelFetch() (texture2D() < GL3).
Attach multiple textures as colour attachments with glFramebufferTexture2D and then set glDrawBuffers.
Bind the framebuffer.
Draw your geometry, writing data from the fragment shader.
With < GL3:
gl_FragData[*]Or >= GL3:
glBindFragDataLocation and out colour1, colour2ARB_image_load_store is an alternative, but not necessary here.
Side note: reading from a texture bound to the current FBO is possible and works if there are no RMW hazards.
Either:
Draw a full screen polygon, and use a fragment shader to draw whatever you want (i.e. a passthrough for the texture you just wrote to using the FBO). This can be done with a single really big triangle clipped using glViewport (it doesn't matter if bits go outside the screen).
Note that to draw anything to the default framebuffer, unbind any currently bound FBO with glBindFramebuffer(GL_FRAMEBUFFER, 0);
Much simpler, blit the contents of your FBO to the default framebuffer.
https://www.opengl.org/sdk/docs/man3/xhtml/glBlitFramebuffer.xml
glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); //destination
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
The colour attachments that are copied can be set with glReadBuffer/glDrawBuffers`. See here. Another here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With