Как настроить и использовать постоянный объект кадрового буфера для уникального выбора цвета?

Этот вопрос сильно изменился с тех пор, как он был задан впервые, потому что я не понимал, как мало я знал о том, о чем спрашивал. И одна проблема, связанная с изменением размера, затуманивала мою способность понимать большую проблему создания и использования буфера кадра. Если вам просто нужен кадровый буфер, перейдите к ответу ... для истории я оставил исходный вопрос нетронутым.


Вопрос новичка. У меня есть проект GL, над которым я работаю, и я пытаюсь разработать стратегию выбора с использованием уникальных цветов. Большинство обсуждений/учебников вращаются вокруг рисования выбираемых объектов в заднем буфере и вычисления выбора, когда пользователь щелкает где-нибудь. Я хочу, чтобы буфер выбора был постоянным, чтобы я мог быстро вычислять попадания при любом движении мыши и не перерисовывал буфер выбора, пока не изменится отображение или геометрия объекта.

Казалось бы, лучшим выбором будет выделенный объект фреймбуфера. Вот моя проблема. Помимо того, что я совершенно новичок в объектах фреймбуфера, мне любопытно. Мне лучше удалить и воссоздать объект frambuffer для событий размера окна или создать его один раз с максимальным разрешением экрана, а затем использовать то, что может быть лишь небольшой его частью. Мои события работают должным образом, чтобы вызывать процедуру буфера кадра только один раз для того, что может быть потоком многих событий изменения размера, но меня беспокоит фрагментация памяти графического процессора или другие проблемы, воссоздание буфера, возможно, много раз.

Кроме того, будет ли объект фреймбуфера (текстура и глубина) вести себя согласованно при использовании только его части.

Идеи? Я совсем не в себе?

РЕДАКТИРОВАТЬ: у меня есть настройка объекта фреймбуфера и теперь я работаю с размерами окна, и я изменяю его размер вместе с окном. Я думаю, что моя проблема была классическим «переосмыслением». Хотя, безусловно, следует по возможности избегать удаления/восстановления объектов на графическом процессоре. Пока он обрабатывается правильно, изменения размеров относительно невелики.

Что я нашел, так это установить флаг и пометить буфер как грязный при изменении размера окна, а затем дождаться обычного события мыши, прежде чем изменять размер буфера. Обычный ввод или перемещение мыши сигнализирует о том, что вы закончили перетаскивание окна по размеру и готовы вернуться к работе. Буферы воссозданы один раз. Кроме того, поскольку размер основного фреймбуфера обычно изменяется для каждого события размера окна в конвейере, само собой разумеется, что изменение размера фреймбуфера не прожжет дыру в вашем ноутбуке.

Кризис предотвращен, продолжайте!


person BentFX    schedule 12.12.2011    source источник
comment
Для ясности я предлагаю вам переместить этот ответ из вопроса в отдельный ответ и пометить его как принятый. Это может помочь другим с похожими проблемами, которые у вас были.   -  person Kromster    schedule 14.12.2011
comment
Я готов. Вопрос кардинально изменится.   -  person BentFX    schedule 14.12.2011


Ответы (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);
}

Это дает мне это...

скриншот

На данный момент я полагаю, что все готово для фактического рисования выбираемых элементов в буфере и использования событий перемещения мыши для проверки попаданий. И у меня есть миниатюра на экране, чтобы показать, как все плохо.

Надеюсь, это было для вас такой же большой помощью, как и для меня неделю назад. :)

person BentFX    schedule 14.12.2011