I want to put the Color Attachment of my custom framebuffer into a compute shader for simple image processing, but I am getting a black screen only.
Here is my example code
Creating color attachment
glGenFramebuffers(1, &this->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
glGenTextures(1, &this->textureColorBuffer);
glBindTexture(GL_TEXTURE_2D, this->textureColorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this->width(), this->height(), 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,
this->textureColorBuffer, 0);
Compiling and linking shader
cshader = glCreateShader(GL_COMPUTE_SHADER);
const char *csSrc[] = {
"#version 440\n",
"layout (binding = 0, rgba32f) uniform image2D destTex;\
layout (binding = 1, rgba32f) uniform image2D sourceTex;\
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\
void main() {\
vec4 texel;\
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\
texel = imageLoad(sourceTex, storePos);\
texel = vec4(1.0) - texel;\
imageStore(destTex, storePos, texel);\
}"
};
glShaderSource(cshader, 2, csSrc, NULL);
glCompileShader(cshader);
cshaderprogram = glCreateProgram();
glAttachShader(cshaderprogram, cshader);
glLinkProgram(cshaderprogram);
Invoke Shader and drawing texture to quad. The shader is a simple color switching shader, for testing purposes.
glUseProgram(cshaderprogram);
glUniform1i(0, 0);
glActiveTexture(GL_TEXTURE0);
glBindImageTexture(0, outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY,
GL_RGBA32F);
glActiveTexture(GL_TEXTURE1);
glBindImageTexture(0, textureColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY,
GL_RGBA32F);
glUniform1i(1, 1);
glDispatchCompute(width() / 16, height() / 16, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
screenProgram.bind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(screenVao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
I am able to render the textureColorBuffer to the quad correctly and i can write to a texture. I think the problem that i do not know how to read from the framebuffer.
I hope you can help me. If there are still some questions just ask.
The binding point of sourceTex is 1 and not 0:
layout (binding = 1, rgba32f) uniform image2D sourceTex;
So you have to bind the texture to the image unit 1
glBindImageTexture( 1, // <------- 1 instead of 0
textureColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
Note, Images units and Texture units are different things.
Of course you can use a texture sampler uniform in the coumpute shader too. If destTex and sourceTex have the same size, you can use texelFetch with gl_GlobalInvocationID, to look up sourceTex:
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout (binding = 0, rgba32f) uniform image2D destTex;
layout (binding = 0) uniform sampler2D sourceTex;
void main()
{
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
vec4 texel = texelFetch(sourceTex, pos, 0);
texel = vec4(1.0) - texel;
imageStore(destTex, pos, texel);
}
In the above snippet is used the image unit 0 for destTex and the texture unit 0 for sourceTex.
By the way, are you sure that you want to do
texel = vec4(1.0) - texel;
Note, if the alpha channel of texel is 1.0, it will become completely transparent.
Related
Now I have a noise texture generated by this website: https://aeroson.github.io/rgba-noise-image-generator/. I want to use 4 uniform samplers in my computing shader to get 4 random rgba values from a single noise texture. My computing shader source codes look like:
#version 430 core
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
uniform sampler2D noise_r0;
uniform sampler2D noise_i0;
uniform sampler2D noise_r1;
uniform sampler2D noise_i1;
layout (binding = 0, rgba32f) writeonly uniform image2D tilde_h0k;
layout (binding = 1, rgba32f) writeonly uniform image2D tilde_h0minusk;
uniform int N = 256;
....
// Box-Muller algorithm
vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / float(N); // Here every invocation refers to a pixel of output image
float noise00 = clamp(texture(noise_r0, texCoord).r, 0.001, 1.0);
float noise01 = clamp(texture(noise_i0, texCoord).r, 0.001, 1.0);
float noise02 = clamp(texture(noise_r1, texCoord).r, 0.001, 1.0);
float noise03 = clamp(texture(noise_i1, texCoord).r, 0.001, 1.0);
....
and in the main program, I use this code to upload my downloaded noise texture to the computing shader:
unsigned int tex_noise;
glGenTextures(1, &tex_noise);
glBindTexture(GL_TEXTURE_2D, tex_noise);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
int w_noise, h_noise, nrChannels;
unsigned char* data = stbi_load("noise.png", &w_noise, &h_noise, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_noise, h_noise, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else std::cout << "Failed to load noise texture." << std::endl;
stbi_image_free(data);
....
....
My question is: Can I set up those sampler2D's in computing shader using this code?
glUseProgram(computeProgram);
glActiveTexture(GL_TEXTURE1);
glUniform1i(glGetUniformLocation(computeProgram, "noise_r0"), 1);
glActiveTexture(GL_TEXTURE2);
glUniform1i(glGetUniformLocation(computeProgram, "noise_i0"), 2);
glActiveTexture(GL_TEXTURE3);
glUniform1i(glGetUniformLocation(computeProgram, "noise_r1"), 3);
glActiveTexture(GL_TEXTURE4);
glUniform1i(glGetUniformLocation(computeProgram, "noise_i1"), 4);
If it is wrong, what should I do to set up those sampler2D's, and make sure that the random rgba values I get from those sampler2D's are not the same? (cause if they are the same, the Box-Muller algorithm won't work).
Thanks so much for your help!
The type of the uniform is ìmage2D, not sampler2D. To load and store an image, you must bind the texture to an image unit using glBindImageTexture. See Image Load Store. e.g.:
glBindImageTexture(1, tex_noise, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
If you want to bind a texture to a texture unit you need to select active texture unit with glActiveTexture and then bind the texture with glBindTexture:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_object);
You can access this texture in the shader with a uniform of type sampler2D and the texture* functions:
layout(binding = 1) uniform sampler2D myTextue;
If you want to bind a texture to a image unit, you have to use glBindImageTexture:
glBindImageTexture(1, texture_object, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
You can access this texture in the shader with a uniform of type iamge2D and and the image* functions:
layout (binding = 1, rgba32f) writeonly uniform image2D myImage;
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.
I've been trying to render to an FBO and render two FBO's to the screen, but have been unsuccessfull to do a depth test at the merge of the two FBO's. I've tried merging the textures with an compute shader, but I am unable to read the values of the depth textures(all values are value 1, but depth test is working when I render to the FBO). Does anybody knows what I am doing wrong, or knows an other method to merge two FBO's?
This is how I create the FBO:
struct FBO {
uint color;
uint depth;
uint fbo;
};
FBO createFBO(int width, int height) {
FBO fbo;
fbo.color = createFBOTexture(width, height, false);
fbo.depth = createFBOTexture(width, height, true);
fbo.fbo = generateFramebuffer(fbo.color, fbo.depth);
return fbo;
}
uint createFBOTexture(int width, int height, bool isDepthBuffer) {
uint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if (isDepthBuffer)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
int i = glGetError();
if (i)
std::cout << "Error while creating the FBO: " << gluErrorString(i) << '\n';
return texture;
}
uint generateFrameBuffer(uint color, uint depth)
{
int mipmapLevel = 0;
//Generate FBO
uint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//Attatch textures to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, mipmapLevel);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, mipmapLevel);
//Error check
int i = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (i != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR: frambuffer is not ok, status: " << i << '\n';
else {
int i = glGetError();
if (i)
std::cout << "Error while creating the FBO: " << gluErrorString(i) << '\n';
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return fbo;
}
This is how I render to the FBO:
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_pointcloud.fbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawPointCloud(); //Here I draw points with the depreciated fixed pipeline
glFlush();
I have tried to bind the textures with glBindTexture(all values read where 1):
void MergeFrames::merge(TextureLoading::FBO tex0, TextureLoading::FBO tex1, GLuint result, int width, int height)
{
glUseProgram(shader);
//Bind depth textures
glActiveTexture(GL_TEXTURE0+0);
glBindTexture(GL_TEXTURE_2D, tex0.depth);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, tex1.depth);
//Bind color textures
glBindImageTexture(2, tex0.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(3, tex1.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(4, result, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
//Dispatch the shader
glDispatchCompute(ceilf(width / 16.0f), ceilf(height / 16.0f), 1);
}
The compute shader:
#version 430
uniform sampler2D depthTex0;
uniform sampler2D depthTex1;
uniform layout(rgba8) readonly image2D colorTex0;
uniform layout(rgba8) readonly image2D colorTex1;
uniform layout(rgba8) writeonly image2D mergedColor;
layout (local_size_x = 16, local_size_y = 16) in;
void main() {
ivec2 ID = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(colorTex0);
vec2 texCoords = vec2(float(ID.x)/float(size.x),float(ID.y)/float(size.y));
float depths[2];
vec4 colors[2];
depths[0] = texture2D(depthTex0, texCoords).x;
depths[1] = texture2D(depthTex1, texCoords).x;
colors[0] = imageLoad(colorTex0, ID);
colors[1] = imageLoad(colorTex1, ID);
int i = int(depths[1] > depths[0]);
imageStore(mergedColor, ID, colors[i]);
}
I have tried to bind the textures with glBindTexture(all values read where 0):
void MergeFrames::merge(TextureLoading::FBO tex0, TextureLoading::FBO tex1, GLuint result, int width, int height)
{
glUseProgram(shader);
glBindImageTexture(0, tex0.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(1, tex1.color, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glBindImageTexture(2, tex0.depth, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16);
glBindImageTexture(3, tex1.depth, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16);
glBindImageTexture(4, result, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glDispatchCompute(ceilf(width / 16.0f), ceilf(height / 16.0f), 1);
}
The compute shader:
#version 430
uniform layout(rgba8) readonly image2D colorTex0;
uniform layout(rgba8) readonly image2D colorTex1;
uniform layout(r16) readonly image2D depthTex0;
uniform layout(r16) readonly image2D depthTex1;
uniform layout(rgba8) writeonly image2D mergedColor;
layout (local_size_x = 16, local_size_y = 16) in;
void main() {
ivec2 ID = ivec2(gl_GlobalInvocationID.xy);
float depths[2];
vec4 colors[2];
colors[0] = imageLoad(colorTex0, ID);
depths[0] = imageLoad(depthTex0, ID).x;
colors[1] = imageLoad(colorTex1, ID);
depths[1] = imageLoad(depthTex1, ID).x;
int i = int(depths[1] < depths[0]);
imageStore(mergedColor, ID, colors[i]);
}
And this is how I bind the indices (the indices are differt in the version where I use sampler2D instead of image2D):
MergeFrames::MergeFrames()
{
shader = OpenGL::compileComputeShader("MergeFrames.comp");
glUseProgram(shader);
glUniform1i(glGetUniformLocation(shader, "colorTex0"), 0);
glUniform1i(glGetUniformLocation(shader, "colorTex1"), 1);
glUniform1i(glGetUniformLocation(shader, "depthTex0"), 2);
glUniform1i(glGetUniformLocation(shader, "depthTex1"), 3);
glUniform1i(glGetUniformLocation(shader, "mergedColor"), 4);
}
I got the code working, by copying the data from depth texture to a texture with format GL_RED after rendering .
I want to use image2D as 2D storage for vertices which will be modified by compute shader but things doesnt work.
Create textures:
glGenTextures(1, &HeightMap);
glBindTexture(GL_TEXTURE_2D, HeightMap);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, 513, 513, 0,GL_RGBA32F, GL_UNSIGNED_BYTE, 0);
Use and dispatch compute shader:
glUseProgram(ComputeProgram);
glActiveTexture(GL_TEXTURE0);
glBindImageTexture(0, HeightMap, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glDispatchCompute(1, 1, 1 );
glMemoryBarrier( GL_ALL_BARRIER_BITS );
And compute shader:
#version 430 core
layout( std430, binding=1 ) buffer VertBuffer
{
vec4 Positions[ ];
};
layout( local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout (binding=0, rgba32f) uniform image2D HeightMap;
void main (void)
{
imageStore(HeightMap, ivec2(0,0),vec4(0,0,0,1));
Positions[0]=imageLoad(HeightMap, ivec2(0,0)).rgba;
}
Ok i found solution. This is how you use image2D for read and write data with compute shader:
Create texture:
glGenTextures(1, &HeightMap);
glBindTexture(GL_TEXTURE_2D, HeightMap);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, 513, 513, 0,GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
Dispatch compute shader:
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 1, VerticesBuffer );
glBindImageTexture(0, HeightMap, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glUseProgram(ComputeProgram);
glUniform1i(glGetUniformLocation(ComputeProgram, "HeightMap"), 0);
glDispatchCompute(1, 1, 1 );
glMemoryBarrier( GL_ALL_BARRIER_BITS );
Example compute shader:
#version 430 core
layout( std430, binding=1 ) buffer VertBuffer
{
vec4 Positions[ ];
};
layout( local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout (rgba32f) uniform image2D HeightMap;
void main (void)
{
ivec2 pos=ivec2(0,0);
imageStore(HeightMap, pos,vec4(10,0,0,1));
Positions[0].xyzw=imageLoad(HeightMap, pos).rgba;
}
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, 513, 513, 0,GL_RGBA32F, GL_UNSIGNED_BYTE, 0);
Always check your OpenGL errors. This line fails because GL_RGBA32F is not a legal pixel transfer format. The pixel transfer format only specifies the number of components you're using. It should be GL_RGBA. This causes an OpenGL error.
Yes, I know you're not actually transfering pixel data. But OpenGL requires that the pixel transfer parameters be legitimate even if you're not actually doing a pixel transfer.
Also, the type (the next parameter) should be GL_FLOAT, not GL_UNSIGNED_BYTE.
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.