Good afternoon,
I have been working with OpenGL ES version 3.2 and OpenGL EGL to try and render some simple geometries and have been successful. Now I am trying to move to some more advance feature(s), the use of shaders to render a 2D texture.
However, I have only been able to get an image file that is black (my clear color value) when I try and use a texture that I am attaching to the framebuffer. There is a lot of code so I am posting what I hope are the critical points where it may be failing.
I have no idea what is going on with this and any help/hints would be greatly appreciated.
The fragment shader follows:
#version 320 es
precision mediump float;
precision highp int;
layout(binding = 0) uniform highp sampler2D uTexture;
layout(location = 0) out highp vec4 color;
layout(location = 0) in highp vec2 vTexcoord;
void main()
{
color = texture(uTexture, vTexcoord);
}
The vertex shader follows:
#version 320 es
layout(location = 0) in vec3 position;
layout(location = 0) out vec2 vTexcoord;
layout(location = 1) in vec2 texcoord;
void main()
{
gl_Position = vec4(position, 1.0);
vTexcoord = texcoord;
}
The relevant portion of the C++ code that is called after the successful setting of EGL and GLES preliminaries such as setting context, etc., follows:
// Where shader program has already been successfully compiled
// and program defines the uint32_t identifier of this
constexpr int32_t WIDTH = 480;
constexpr int32_t HEIGHT = 620;
GLfloat textureData[4 * WIDTH * HEIGHT];
for (int32_t y = 0; y < HEIGHT; y++) {
for (int32_t x = 0; x < WIDTH; x++) {
int32_t index = 4 * (y * WIDTH + x);
float value = static_cast<float>(x) / WIDTH;
textureData[index] = value; // red component
textureData[index + 1] = value; // green component
textureData[index + 2] = value; // blue component
textureData[index + 3] = 1.0f; // alpha component
}
}
GLfloat vertices[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
};
GLushort indices[] = {
0, 1, 2, 2, 3, 0
};
...
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, textureData);
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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Set uniform for texture
GLint textureLocation = glGetUniformLocation(program, "uTexture");
glUniform1i(textureLocation, 0);
// Create and bind vertex buffer
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Create and bind index buffer
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Set up vertex attribute pointers
GLint positionLocation = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
GLint texcoordLocation = glGetAttribLocation(program, "texcoord");
glEnableVertexAttribArray(texcoordLocation);
glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
// Clear the screen
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Use the shader program
glUseProgram(program);
// Bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// Draw the quad
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
// Read from framebuffer as floating point values
std::vector<float> framebufferData(WIDTH * HEIGHT * 4);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_FLOAT, framebufferData.data());
// Write the framebuffer to a ppm file
std::ofstream ppmFile(out_file.c_str(), std::ios::out | std::ios::binary);
ppmFile << "P6\n" << WIDTH << " " << HEIGHT << "\n255\n";
for (size_t i = 0; i < WIDTH * HEIGHT * 4; i += 4) {
unsigned char r = static_cast<unsigned char>(std::min(framebufferData[i] * 255.0f, 255.0f));
unsigned char g = static_cast<unsigned char>(std::min(framebufferData[i + 1] * 255.0f, 255.0f));
unsigned char b = static_cast<unsigned char>(std::min(framebufferData[i + 2] * 255.0f, 255.0f));
ppmFile << r << g << b;
}
// Clean up
glDeleteTextures(1, &texture);
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);
glDeleteProgram(program);
The textureData array should define a gradient from black to white, however the output ppm file is a solid black rectangle.
Apologies for the long message and if I am unclear in my question, but this has got me stumped and I am hoping one of you GLES experts will know where I am messing up.
Thanks in advance for any help.