Как мне настроить и использовать постоянный объект кадрового буфера для выбора уникального цвета?
Этот вопрос сильно изменился с тех пор, как его сначала спросили, потому что я не понимал, как мало я знал о том, что спрашиваю. И одна проблема, касающаяся изменения размера, омрачала мою способность понимать более крупную проблему создания и использования кадрового буфера. Если вам нужен фреймбуфер, перейдите к ответу... для истории, я оставил исходный вопрос без изменений.
Вопросновичка. У меня есть проект GL, над которым я работаю, и пытаюсь разработать стратегию выбора, используя уникальные цвета. Большинство дискуссий / руководств вращаются вокруг рисования выбираемых объектов в заднем буфере и вычисления выбора, когда пользователь щелкает где-то. Я хочу, чтобы буфер выделения был постоянным, чтобы я мог быстро рассчитывать попадания при любом движении мыши и не будет перерисовывать буфер выбора, пока не изменится отображение или геометрия объекта.
Казалось бы, лучшим выбором будет выделенный объект фреймбуфера. Вот моя проблема. Помимо того, что я совершенно новичок в объектах кадрового буфера, мне любопытно. Мне лучше удалить и воссоздать объект frambuffer на событиях размера окна или создать его один раз при максимальном разрешении экрана, а затем использовать то, что может быть только небольшой его частью. Мои события работают должным образом, чтобы вызывать подпрограмму framebuffer только один раз для того, что может быть потоком множества событий изменения размера, но я обеспокоен фрагментацией памяти GPU или другими проблемами, воссоздающими буфер, возможно, много раз.
Кроме того, будет ли объект кадрового буфера (текстура и глубина) даже вести себя согласованно при использовании только его части.
Идеи? Я полностью вне базы?
РЕДАКТИРОВАТЬ: у меня есть мой объект framebuffer настройки и теперь работает на размеры окна, и я изменяю его размер с окном. Я думаю, что моя проблема была классической "переосмысление". Хотя, безусловно, верно, что по возможности следует избегать удаления / воссоздания объектов на графическом процессоре. Пока он обрабатывается правильно, размеры относительно невелики.
Что я нашел, так это установить флаг и пометить буфер как грязный при изменении размера окна, а затем дождаться нормального события мыши, прежде чем изменять размер буфера. Обычная мышь вводит или перемещает сигналы, вы перетаскиваете окно до нужного размера и готовы вернуться к работе. Буферы воссозданы один раз. Кроме того, поскольку основной кадровый буфер обычно изменяется для каждого события размера окна в конвейере, вполне понятно, что изменение размера кадрового буфера не приведет к прожиганию дыры в вашем ноутбуке.
Кризис предотвращен, продолжайте!
1 ответ
Я упомянул в вопросе, что я переосмыслил проблему. Основная причина этого в том, что проблема была больше, чем вопрос. Проблема была в том, что я не только не знал, как управлять кадровым буфером, но и не знал, как его создать. Вариантов так много, и ни один из веб-ресурсов, похоже, не посвящен тому, что я пытался сделать, поэтому я боролся с этим. Если вы также боретесь с тем, как перенести процедуру выбора в уникальную цветовую схему с постоянным буфером, или просто полностью потеряны в отношении кадровых буферов и закадрового рендеринга, читайте дальше.
Мой холст OpenGL определен как класс, и мне нужен "объект буфера выбора". Я добавил это к частным членам класса.
unsigned int sbo;
unsigned int sbo_pixels;
unsigned int sbo_depth;
bool sbo_dirty;
void setSelectionBuffer();
И в моем обработчике изменения размера, и в инициализации OpenGL я установил грязный флаг для буфера выбора.
sbo_dirty = true;
В начале моего обработчика мыши я проверяю грязный бит и setSelectionBuffer();
при необходимости.
if(sbo_dirty) setSelectionBuffer();
Это решает мои первоначальные опасения по поводу множественного удаления / воссоздания буфера. Размер буфера не изменяется до тех пор, пока указатель мыши не войдет в клиентскую область после изменения размера окна. Теперь мне просто нужно выяснить буфер...
void BFX_Canvas::setSelectionBuffer()
{
if(sbo != 0) // delete current selection buffer if it exists
{
glDeleteFramebuffersEXT(1, &sbo);
glDeleteRenderbuffersEXT(1, &sbo_depth);
glDeleteRenderbuffersEXT(1, &sbo_pixels);
sbo = 0;
}
// create depth renderbuffer
glGenRenderbuffersEXT(1, &sbo_depth);
// bind to new renderbuffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, sbo_depth);
// Set storage for depth component, with width and height of the canvas
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, canvas_width, canvas_height);
// Set it up for framebuffer attachment
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, sbo_depth);
// rebind to default renderbuffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// create pixel renderbuffer
glGenRenderbuffersEXT(1, &sbo_pixels);
// bind to new renderbuffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, sbo_pixels);
// Create RGB storage space(you might want RGBA), with width and height of the canvas
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, canvas_width, canvas_height);
// Set it up for framebuffer attachment
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, sbo_pixels);
// rebind to default renderbuffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// create framebuffer object
glGenFramebuffersEXT(1, &sbo);
// Bind our new framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sbo);
// Attach our pixel renderbuffer
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, sbo_pixels);
// Attach our depth renderbuffer
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, sbo_depth);
// Check that the wheels haven't come off
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
// something went wrong
// Output an error to the console
cout << "Selection buffer creation failed" << endl;
// restablish a coherent state and return
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
sbo_dirty = false;
sbo = 0;
return;
}
// rebind back to default framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// cleanup and go home
sbo_dirty = false;
Refresh(); // force a screen draw
}
Затем в конце своей функции рендеринга я тестирую sbo и рисую, если он кажется готовым.
if((sbo) && (!sbo_dirty)) // test that sbo exists and is ready
{
// disable anything that's going to affect color such as...
glDisable(GL_LIGHTING);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POINT_SMOOTH);
glDisable(GL_POLYGON_SMOOTH);
// bind to our selection buffer
// it inherits current transforms/rotations
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sbo);
// clear it
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw selectables
// for now i'm just drawing my object
if (object) object->draw();
// reenable that stuff from before
glEnable(GL_POLYGON_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_LIGHTING);
// blit to default framebuffer just to see what's going on
// delete this bit once selection is setup and working properly.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, sbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
glBlitFramebufferEXT(0, 0, canvas_width, canvas_height,
0, 0, canvas_width/3, canvas_height/3,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
// We're done here, bind back to default buffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
Это дает мне это...
На данный момент я считаю, что все готово для рисования выбираемых элементов в буфере, и использую события перемещения мыши для проверки попаданий. И у меня есть миниатюра на экране, чтобы показать, как все взрывается.
Надеюсь, это помогло вам так же, как и неделю назад.:)