问题描述
我正在使用 ImGUI 为图像创建颜色选择器 OpenGL 应用程序。我设法通过将图像加载到 glTexImage2D
并使用 ImGUI::Image()
来加载图像。
现在我想实现一个方法,它可以在鼠标左键单击的情况下确定像素的颜色。
这是我加载纹理,然后将其分配给帧缓冲区的方法:
bool LoadTextureFromFile(const char *filename,gluint *out_texture,int *out_width,int *out_height,ImVec2 mousePosition ) {
// Reading the image into a GL_TEXTURE_2D
int image_width = 0;
int image_height = 0;
unsigned char *image_data = stbi_load(filename,&image_width,&image_height,NULL,4);
if (image_data == NULL)
return false;
gluint image_texture;
glGenTextures(1,&image_texture);
glBindTexture(GL_TEXTURE_2D,image_texture);
glTexImage2D(GL_TEXTURE_2D,GL_RGBA,image_width,image_height,GL_UNSIGNED_BYTE,image_data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
stbi_image_free(image_data);
glBindTexture(GL_TEXTURE_2D,0);
*out_texture = image_texture;
*out_width = image_width;
*out_height = image_height;
// Assigning texture to Frame Buffer
unsigned int fbo;
glGenFramebuffers(1,&fbo);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,image_texture,0); glFramebufferTexture2D(GL_FRAMEBUFFER,0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE){
std::cout<< "Frame buffer is done."<< std::endl;
}
return true;
}
不幸的是,上面的代码导致一个完全空白的屏幕。我想,我在设置帧缓冲区时遗漏了一些东西。
这是我想使用鼠标坐标对帧缓冲区纹理进行采样的方法:
void readPixelFromImage(ImVec2 mousePosition) {
unsigned char pixels[4];
glreadBuffer(GL_COLOR_ATTACHMENT0);
glreadPixels(GLint(mousePosition.x),GLint(mousePosition.y),1,pixels);
std::cout << "r: " << static_cast<int>(pixels[0]) << '\n';
std::cout << "g: " << static_cast<int>(pixels[1]) << '\n';
std::cout << "b: " << static_cast<int>(pixels[2]) << '\n';
std::cout << "a: " << static_cast<int>(pixels[3]) << '\n' << std::endl;
}
感谢任何帮助!
解决方法
您的代码中确实缺少一些东西:
您设置了一个仅包含单个纹理缓冲区的新帧缓冲区。这没关系,所以 glCheckFramebufferStatus 等于 GL_FRAMEBUFFER_COMPLETE。但是没有附加到您的帧缓冲区的渲染缓冲区。如果您希望在屏幕上呈现图像,则应使用默认帧缓冲区。该帧缓冲区是从您的 GL 上下文创建的。 但是,文档说:默认帧缓冲区无法更改其缓冲区附件,[...] https://www.khronos.org/opengl/wiki/Framebuffer。因此,将纹理或渲染缓冲区附加到默认 FB 肯定是不可能的。但是,您可以像以前一样生成一个新的 FB,渲染它,最后将结果(或 blit 缓冲区)渲染到您的默认 FB。也许这项技术的一个很好的起点是 https://learnopengl.com/Advanced-Lighting/Deferred-Shading
此外,如果您只想从 GPU 读回渲染值,使用 renderbuffer 而不是 texture 会更高效。您甚至可以将多个渲染缓冲区附加到您的帧缓冲区(如延迟着色)。示例:您可以使用第二个渲染缓冲区来渲染对象/实例 ID(因此,渲染缓冲区将是单通道整数),并且您的第一个渲染缓冲区将用于正常绘制。使用 glReadPixels 读取第二个渲染缓冲区,您可以直接读取绘制的实例,例如鼠标位置。这样,您可以非常有效地启用鼠标拾取。