Я создаю приложение OpenGL для выбора цвета для изображений с ImGUI. Мне удалось загрузить изображение, загрузив изображение в 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, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, 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, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, image_texture, 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, 1, GL_RGBA, GL_UNSIGNED_BYTE, 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;
}
Любая помощь приветствуется!
см. OpenGL 3D-raypicking с высокополигональными сетками есть пример glReadPixel
прямого фреймбуфера (без вложений PBO/FBO) для выбора текстуры напрямую, которую вы можете использовать glGetTexImage
В вашем коде действительно чего-то не хватает:
Вы устанавливаете новый буфер кадра, который содержит только один буфер текстуры. Это нормально, поэтому glCheckFramebufferStatus равен GL_FRAMEBUFFER_COMPLETE. Но к вашему фреймбуферу не подключен буфер рендеринга. Если вы хотите, чтобы ваше изображение отображалось на экране, вы должны использовать фреймбуфер по умолчанию. Этот фреймбуфер создается из вашего контекста GL. Однако в документации говорится: буферы кадров по умолчанию не могут изменять свои вложения буфера, [...] https://www.khronos.org/opengl/wiki/Framebuffer . Таким образом, присоединение текстуры или буфера рендеринга к FB по умолчанию, безусловно, невозможно. Однако вы могли бы сгенерировать новый FB, как вы это сделали, отрендерить его и, наконец, отрендерить результат (или преобразовать буферы) в ваш FB по умолчанию. Возможно, хорошей отправной точкой для этой техники является https://learnopengl.com/Advanced-Lighting/Deferred-Shading
Более того, если вы собираетесь просто считывать отрендеренные значения с вашего графического процессора, более эффективно использовать буфер рендеринга вместо текстуры. Вы даже можете иметь несколько буферов рендеринга, прикрепленных к вашему фреймбуферу (как в случае отложенного затенения). Пример: вы можете использовать второй буфер рендеринга для рендеринга идентификатора объекта/экземпляра (таким образом, буфер рендеринга будет одноканальным целым числом), а ваш первый буфер рендеринга будет использоваться для обычного рисования. Читая второй буфер рендеринга с помощью glReadPixels, вы можете напрямую прочитать, какой экземпляр был нарисован, например. положение мыши. Таким образом, вы можете очень эффективно включить выбор мышью.
остерегайтесь, что координаты мыши относятся к координатам окна, которые отличаются от координат OpenGL ... вам, скорее всего, следует инвертировать позицию
y
, еслиys
- этоy
размер вашего представления, затем используйтеys-mousePosition.y
... Если у вас есть панели и прочее в окне, которое вам нужно чтобы учесть это тоже... Вы также можете использовать выбор текста непосредственно из текстуры... Также важно выбрать glReadPixels во время рендеринга изображения и из того же потока,... поскольку вы, скорее всего, выбираете в каком-то событии возможно, ваше изображение пусто в то время.