如何将 2D 纹理生成到 1D 缓冲区并将其加载到 OpenGL 中?
How to generate a 2D texture into a 1D buffer and load it in OpenGL?
在某些情况下,我以一维二进制数据和指定格式的形式从相机获取实时图像数据。我想将这种格式转换为 RGBA 或 BGRA,并用它来纹理屏幕对齐的四边形。但是,我似乎误解了一些关于如何在 OpenGL 中生成和加载纹理的核心概念,因为我无法使以下示例正常工作:
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));
}
我想在这里实现的是纹理到整个屏幕红色。相反,我得到这个:
纹理坐标似乎没问题(我之前能够正确地对加载的图像进行纹理处理):
为了获得更多调试信息,我添加了更多颜色:
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;
}
输出如下所示:
所以看起来纹理在两个方向上都渲染得太小了。纹理上的包裹设置设置为夹紧,因此它不应重复。我在这里做错了什么?
编辑:请忽略任何明显的低效或难看的代码结构,只要它不影响程序的正确性即可。我现在正在尝试让最简单的版本工作。
您的 2d 到 1d 索引计算刚刚失败:
int32_t ind = y * BUFF_WIDTH + x * 4;
应该是
int32_t ind = (y * BUFF_WIDTH + x) * 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;
x
现在是 x * 4
之前的样子(但是您的循环应该转到 x <= 4*BUFF_WIDTH
),ind = y * 4 * BUFF_WIDTH + x
是正确的。
在某些情况下,我以一维二进制数据和指定格式的形式从相机获取实时图像数据。我想将这种格式转换为 RGBA 或 BGRA,并用它来纹理屏幕对齐的四边形。但是,我似乎误解了一些关于如何在 OpenGL 中生成和加载纹理的核心概念,因为我无法使以下示例正常工作:
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));
}
我想在这里实现的是纹理到整个屏幕红色。相反,我得到这个:
纹理坐标似乎没问题(我之前能够正确地对加载的图像进行纹理处理):
为了获得更多调试信息,我添加了更多颜色:
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;
}
输出如下所示:
所以看起来纹理在两个方向上都渲染得太小了。纹理上的包裹设置设置为夹紧,因此它不应重复。我在这里做错了什么?
编辑:请忽略任何明显的低效或难看的代码结构,只要它不影响程序的正确性即可。我现在正在尝试让最简单的版本工作。
您的 2d 到 1d 索引计算刚刚失败:
int32_t ind = y * BUFF_WIDTH + x * 4;
应该是
int32_t ind = (y * BUFF_WIDTH + x) * 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;
x
现在是 x * 4
之前的样子(但是您的循环应该转到 x <= 4*BUFF_WIDTH
),ind = y * 4 * BUFF_WIDTH + x
是正确的。