I am attempting to learn OpenGL, more or less from scratch. I seem to run into an issue when I load two different textures, and use a different one depending on the y-position of the shape. It works, but it appears that computing each frame takes a lot longer than I'd hope for. My computer seems to be completely consumed by that one task, until the window with the OpenGL code closes with the terminal telling me Killed. So I assume I am doing something very wrong and stupid.
Here is my texture shader:
#version 120
uniform sampler2D tex0;
uniform sampler2D tex1;
varying float factor; // y-coordinate passed from the vertex shader
varying vec2 intp_texture;
void main(void) {
vec4 opt0 = texture2D(tex0, intp_texture);
vec4 opt1 = texture2D(tex1, intp_texture);
if (factor < 0) {
gl_FragColor = opt0;
} else if (factor > 0) {
gl_FragColor = opt1;
} else {
gl_FragColor = mix(opt0, opt1, 0.5);
}
}
Here is what I think is the relevant part of my render function:
glEnableVertexAttribArray(texture_loc);
glBindBuffer(GL_ARRAY_BUFFER, tbuffer);
glVertexAttribPointer(texture_loc, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glGenTextures(2, texs);
// images for the texture
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data_0);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glUniform1i(tex0_loc, 0);
glBindTexture(GL_TEXTURE_2D, texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data_1);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glUniform1i(tex1_loc, 1);
I have tried running glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data_?); only at the initialisation. The problem I have then is that then the shader doesn't seem to differentiate between tex0 sampler and tex1 sampler.
All and any input would be much appreciated! The full code is on github, too, if that is helpful.
Related
I am a bloody newbie to OpenGL and it still looks sometimes like black magic to me. I just want to load and display an texture for testing purposes and I do not want to use the tutorial libraries to really understand what happens. But I just get a black screen and I cannot find the reason for it.
My c++ source code
int main(){
new cpp_logger();
GLint program_rgb_;
Mat img = imread("plane.jpg");
std::string file_path = "plane.jpg";
// Set viewport window size and clear color bit.
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
//set viewport
glViewport(0, 0, img.size().width, img.size().height);
// Create a Vertex Buffer Object and copy the vertex data to it
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {-1, 1, -1, -1, 1, 1, 1, -1,
0, 0, 0, 1, 1, 0, 1, 1};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//create program and shader
program_rgb_ = glCreateProgram();
const char* vertexShader = read_shader("vertex.glsl"); //simple method to read the shader files
const char* fragmentShader = read_shader("fragment.glsl");
CreateShader(program_rgb_, GL_VERTEX_SHADER, vertexShader); //simple method to link and compile shader programs
CreateShader(program_rgb_, GL_FRAGMENT_SHADER, fragmentShader);
glLinkProgram(program_rgb_);
glUseProgram(program_rgb_);
//use fast 4-byte alignment (default anyway) if possible because using OpenCV
glPixelStorei(GL_UNPACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
//set length of one complete row in data (doesn't need to equal image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, img.step/img.elemSize());
flip(img, img, 0);
// Load texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
//set parameters
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.cols, img.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data);
glUniform1i(glGetUniformLocation(program_rgb_,"tex"), 0);
uint8_t* result = new uint8_t[img.cols * img.rows * 4];
while(true){
GLint pos_location = glGetAttribLocation(program_rgb_, "a_position");
GLint tc_location = glGetAttribLocation(program_rgb_, "a_texCoord");
// Specify the layout of the vertex data
glEnableVertexAttribArray(pos_location);
glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
//specify color data
glEnableVertexAttribArray(tc_location);
glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, static_cast<float*>(0) + 8);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawArrays(GL_TRIANGLES, 0, 8);
glReadPixels(0, 0, img.rows, img.cols, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void*)result);
auto result_ = cv::Mat(img.rows, img.cols, CV_8UC4, result);
imshow("img", result_);
if(waitKey(1) >= 0) break;
}
destroyAllWindows();
return EXIT_SUCCESS;
}
My fragment shader
#version 150 core
precision mediump float;
in vec2 texCoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
}
my vertex shader
#version 150 core
out vec2 texCoord;
attribute vec2 a_texCoord;
attribute vec4 a_position;
void main()
{
texCoord = a_texCoord;
gl_Position = a_position;
}
Thank you a lot for your help!
EDIT
Sorry for the missunderstanding. I meant: I do not want to use the libraries like SOIL and SFML and I want to go an alternative way to fully understand what actually happens.
It might be stupid and a trivial question but since i'm kinda new with OpenGL ,I don't understand how to send color buffer and depth buffer coming from a single FBO to the fragment shader.
My FBO is generated with 1 texture buffer and 1 depth buffer
glGenTextures(1, &texture_color);
glBindTexture(GL_TEXTURE_2D, texture_color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glGenTextures(1, &texture_depth);
glBindTexture(GL_TEXTURE_2D, texture_depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
and I would like, in my fragment buffer to have
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
to be filled with both color and depth texture...
I can send just one or the other with GlBindtexture (and it works well), but I don't success to send the 2 at the same time. Does somebody knows how to do it?
Thanks!
Ok, I might not be giant since the solution is easy, and I was just doing wrong.
I was trying to use glActiveTexture(GL_DEPTH) followed by a binding to my Texture : (glBindTexture(GL_TEXTURE_2D, visibilityFBO.getDepthTexture());) thinking it was normal to use GL_DEPTH.
But i was wrong,
and it works using :
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, visibilityFBO.getColorTexture());
glUniform1i(glGetUniformLocation(visibilityPassShader.Program, "positionTexture"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, visibilityFBO.getDepthTexture());
glUniform1i(glGetUniformLocation(visibilityPassShader.Program, "depthTexture"), 1);
it's the same as before, but the DEPTH is considerated as a Texture since I used glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); to produce my Depth texture. So I just have to call the next texture and bind it to be able to use it.
In the fragment, it is still :
uniform sampler2D positionTexture;
uniform sampler2D depthTexture;
In the good order.
Using OpenGL >= 4, you can use in the fragment shader
layout (binding = 0) uniform sampler2D positionTexture;
layout (binding = 1) uniform sampler2D depthTexture;
and forgive the part about glUniform1i in the source code.
Hope it can help someone!
There's some Artifacts on my FrameBuffer Depth Texture I can't get rid off:
The Code used to init the FrameBuffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, depth, 0);
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, attachments);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "FBO FEHLER" << std::endl;
}
Code used to draw the FrameBuffer:
shader->bind();
// Bind Textures
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, color);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depth);
glUniform1i(shader->getUniform("tex"), 0);
glUniform1i(shader->getUniform("depth"), 1);
glUniformMatrix4fv(shader->getUniform("matrix"), 1, GL_FALSE, glm::value_ptr(ortho));
// Draw Call
glBindBuffer(GL_ARRAY_BUFFER,fbovbo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, (void*)12);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Unbind
shader->unbind();//*/
FragmentShader of the actual rendering:
#version 330 core
layout(location = 0) out vec4 out_color;
layout(location = 1) out vec4 out_depth;
in float temp;
void main(void){
out_color = vec4(1,0.0,0.0,1.0);
out_depth = vec4(gl_FragCoord.z);
}
FragmentShader of the FrameBuffer rendering:
#version 330 core
in vec2 fuv;
out vec4 color;
uniform sampler2D tex;
uniform sampler2D depth;
void main(){
vec4 d = texture2D(depth, fuv);
gl_FragDepth = d.a;
vec4 c = texture2D(tex,fuv);
if(c.a<0.1){
discard;
}
color = c;
//color = vec4(texture2D(depth, fuv).zzz,1.0);
//color.a = 0.8;
//color = vec4(1,0,0,0.5);
}
The red "Mesh" is behind the brown surface, but its borders still appear. thats the problem
The problem might come from the limited precision of the depth buffer. Basically, the range between near and farplane has to be represented by the depth-buffer. In your case, the depth-buffer has 8 bit, thus there are only 256 different depth values that can be represented. When two objects are closer together than this, they will be mapped to the same value in the depth buffer.
To overcome this, you can try to increase the precision of the depth buffer, for example, by using
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);
Side-note: I'm not sure why the depth texture has four channels. If you don't need them, I would change this to a one channel format.
I'm trying to draw a textured plane following the OpenGL SuperBible 6th ed. but for some reason I fail.
Here's my texture initialization code.
GLuint texture;
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
int w = 256;
int h = 256;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, w, h);
float * data = new float[w * h * 4];
//This just creates some image data
generateTexture(data, w, h);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_FLOAT, data);
delete [] data;
This is the plane object. The object itself is drawn, just untextured.
glGenBuffers(1, &planeBuffer);
glBindBuffer(GL_ARRAY_BUFFER, planeBuffer);
glBufferData(GL_ARRAY_BUFFER,
sizeof(planePositions),
planePositions,
GL_STATIC_DRAW);
These are my vertex and fragment shaders.
#version 430 core
layout (location = 0) in vec3 position;
uniform mat4 proj, view;
void main(void){
gl_Position = proj * view * vec4 (position, 1.0);
}
#version 430 core
uniform sampler2D s;
out vec4 frag_color;
void main () {
frag_color = texelFetch(s, ivec2(gl_FragCoord.xy), 0);
};
I draw like this
glUseProgram(textureProgram);
GLuint projLocation = glGetUniformLocation (textureProgram, "proj");
glUniformMatrix4fv (projLocation, 1, GL_FALSE, projectionSource);
GLuint viewLocation = glGetUniformLocation (textureProgram, "view");
glUniformMatrix4fv (viewLocation, 1, GL_FALSE, viewSource);
glBindBuffer(GL_ARRAY_BUFFER, planeBuffer);
GLuint positionLocation = glGetAttribLocation(textureProgram, "position");
glVertexAttribPointer (positionLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray (positionLocation);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
GLuint ts = glGetUniformLocation (textureProgram, "s");
glUniform1i(ts, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray (positionLocation);
//Afterwards I draw more geometry with other shaders. This shows correctly
glUseProgram(shaderProgram);
//Bind buffers, matrices, drawarrays, etc
But I just get a black untextured plane. If I override the frag_color assignment by adding another line afterwards, like so
frag_color = vec4(1.0);
it works, i.e. I get a white plane, so the shaders seem to be working correctly.
I don't get any errors whatsoever from glGetError().
Compatibility:
OpenGL version supported: 4.2.12337 Compatibility Profile Context 13.101
GLSL version supported: 4.30
The data array does contain values between 0 and 1. I have also tried hard-coding some random coordinates into the texelFetch() function, but I always get a black plane. It looks as though the sampler2D contained nothing but zeroes. I have also tried hard-coding the values contained in data to 1.0, 255.0, but nothing.
Either the book fails to mention something or I am missing something stupid. Why does the texture refuse to show on the plane?
EDIT: I added some code to the drawing part. The rest of the geometry that I draw (with different shaders) shows perfectly. None of it uses textures.
I finally got my way around this, although it is not clear what the problem is exactly.
I got the texture to show using glTexImage2D instead of glTexStorage2D and glTexSubImage2D.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, data);
I also had to set the parameters explicitly, even though I'm using texelFetch().
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);
Binding the uniform explicitly was not necessary.
What is strange is that, according to the docs, glTexStorage2Dis equivalent to this:
for (i = 0; i < levels; i++) {
glTexImage2D(target, i, internalformat, width, height, 0, format, type, NULL);
width = max(1, (width / 2));
height = max(1, (height / 2));
}
However, this combination does not work.
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA, w, h);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_FLOAT, data);
I still have to figure out why is that, but at least I got it to work.
I'm trying to show a greyscale texture on the screen. I create my texture via
glGenTextures(1, &heightMap);
glBindTexture(GL_TEXTURE_2D, heightMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 512, 512, 0, GL_RED, GL_FLOAT, colorData);
colorData is a float[512*512] with values between 0.0 and 1.0.
When rendering, I use:
glBindTexture(GL_TEXTURE_2D, heightMap);
glUniform1i(shader.GetUniformLocation("textureSampler"), 0);
shader.GetUniformLocation is a function of a library we use at university. It is essentially the same as glGetUniformLocation(shader, "textureSampler"), so don't be confused by it.
I render two triangles via triangle strip. My fragment shader is:
#version 330
layout(location = 0) out vec4 frag_color;
in vec2 texCoords;
uniform sampler2D textureSampler;
void main()
{
frag_color = vec4(texture(textureSampler, texCoords).r, 0, 0, 1);
}
I know the triangles are rendered correctly (e.g. if I use vec4(1.0, 0, 0, 1) for frag_color, I get a completely red screen). However with the line above, I only get a completely black screen. Every texture value seems to be 0.0.
Does anyone have an idea, what I have done wrong? Are there mistakes in that few lines of code or are these completely correct and the error is somewhere else?
As one of the comments below says, setting glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); and glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); solves the problem. :)