Reputation: 47
For some context, I'm getting real-time image data from a camera in a form of 1D binary data and a specified format. I want to convert this format to RGBA or BGRA and use it to texture a screen-aligned quad. However, I seem to be misunderstanding some core concepts about how generating and loading texture in OpenGL works, since I can't get the following example to work correctly:
void OpenGLRenderer::renderScreenAlignedQuad(const XrCompositionLayerProjectionView& view)
{
CHECK_GL_ERROR(glBindVertexArray(m_screenAlignedQuad.vao));
CHECK_GL_ERROR(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_screenAlignedQuad.indexBuffer));
// Update texture
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glBindTexture(GL_TEXTURE_2D, m_screenAlignedQuad.texture);
#define BUFF_HEIGHT 1152
#define BUFF_WIDTH 1152
unsigned char *buffer = new unsigned char[BUFF_HEIGHT * BUFF_WIDTH * 4];
for (int32_t y = 0; y < BUFF_HEIGHT; y++) {
for (int32_t x = 0; x < BUFF_WIDTH; x++) {
int32_t ind = y * BUFF_WIDTH + x * 4;
buffer[ind] = 255; // R
buffer[ind + 1] = 0; // G
buffer[ind + 2] = 0; // B
buffer[ind + 3] = 255; // A
}
}
{// =! Critical section !=
// The mutex will be unlocked when this object goes out of scope;
// Note that it blocks other threads from writing, but allows reading
std::shared_lock<std::shared_mutex> sl(m_videoStreamContext.g_currentFrameDataMutex);
CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, BUFF_HEIGHT, BUFF_WIDTH, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer));
}// =! Critical section !=
CHECK_GL_ERROR(glDrawElements(GL_TRIANGLES, m_screenAlignedQuad.indexCount, GL_UNSIGNED_SHORT, 0));
}
What I wanted to achieve here is to texture to whole screen red. Instead, I get this:
The texture coordinates seem to be alright (I was able to texture a loaded image correctly before):
For some more debugging information I add some more colors:
void OpenGLRenderer::renderScreenAlignedQuad(const XrCompositionLayerProjectionView& view)
{
CHECK_GL_ERROR(glBindVertexArray(m_screenAlignedQuad.vao));
CHECK_GL_ERROR(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_screenAlignedQuad.indexBuffer));
// Update texture
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glBindTexture(GL_TEXTURE_2D, m_screenAlignedQuad.texture);
unsigned char *buffer = new unsigned char[BUFF_HEIGHT * BUFF_WIDTH * 4];
for (int32_t y = 0; y < BUFF_HEIGHT; y++) {
for (int32_t x = 0; x < BUFF_WIDTH; x=x+4) {
int32_t ind = y * BUFF_WIDTH + x;
if (y < BUFF_HEIGHT / 2) {
buffer[ind] = 255; // R
buffer[ind + 1] = 0; // G
buffer[ind + 2] = 0; // B
buffer[ind + 3] = 255; // A
} else if (x < BUFF_WIDTH / 2) {
buffer[ind] = 0; // R
buffer[ind + 1] = 0; // G
buffer[ind + 2] = 255; // B
buffer[ind + 3] = 255; // A
} else {
buffer[ind] = 0; // R
buffer[ind + 1] = 255; // G
buffer[ind + 2] = 0; // B
buffer[ind + 3] = 255; // A
}
}
}
{// =! Critical section !=
// The mutex will be unlocked when this object goes out of scope;
// Note that it blocks other threads from writing, but allows reading
std::shared_lock<std::shared_mutex> sl(m_videoStreamContext.g_currentFrameDataMutex);
CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, BUFF_HEIGHT, BUFF_WIDTH, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer));
}// =! Critical section !=
CHECK_GL_ERROR(glDrawElements(GL_TRIANGLES, m_screenAlignedQuad.indexCount, GL_UNSIGNED_SHORT, 0));
delete buffer;
}
So it looks like the texture is rendered too small in both directions. The wrap setting on the texture is set to clamp, so it should not repeat as it does. What am I doing wrong here?
Edit: Please, ignore any obvious inefficiencies or ugly code structure as long as it does not affect the correctness of the program. I'm trying to get the simplest possible version working for now.
Upvotes: 1
Views: 452
Reputation: 45352
Your 2d-to-1d index calculation is just broken:
int32_t ind = y * BUFF_WIDTH + x * 4;
That is supposed to be
int32_t ind = (y * BUFF_WIDTH + x) * 4;
You're making the same basic mistake also in your second approach, just obfuscated a bit more:
for (int32_t y = 0; y < BUFF_HEIGHT; y++) { for (int32_t x = 0; x < BUFF_WIDTH; x=x+4) { int32_t ind = y * BUFF_WIDTH + x;
x
here is now what x * 4
was before (but your loop should then go to x <= 4*BUFF_WIDTH
), and ind = y * 4 * BUFF_WIDTH + x
would be correct.
Upvotes: 2