Отсечение окклюзии C/C++ OpenGL

Я пробую сырой OpenGL, поэтому я решил написать очень, очень простую игру, основанную на 3D-блоках, что-то вроде отсталой игры Minecraft, просто чтобы улучшить свои навыки.

Последними проблемами, с которыми я столкнулся, были выбраковки. Я, наконец, понял, как сделать Frustum Culling и Backface Culling, и они оба работают хорошо, но, к сожалению, я понятия не имею, как закодировать Occlusion Culling, чтобы не отображать блоки, закрытые другими блоками, расположенными ближе к игроку.

Просто для теста в основном цикле отрисовки я перебираю все поля, позже я изменю его на более эффективный способ, теперь вот как выглядит код:

for( std::map< std::string, Cube* >::iterator it = Cube::cubesMap.begin( ); it !=  Cube::cubesMap.end( ); it++ )
{
    cube = ( *it ).second;

    if( !cube )
        continue;

    (...)

    if( Camera::cubeInFrustum( cube->position.x, cube->position.y, cube->position.z, 0.5f ) && cube->isInRoundDistance( 80 ) )
        cube->draw( );
}

И Cube::Draw:

void Cube::draw( )
{
    glPushMatrix( );
    glTranslatef( position.x, position.y, position.z );

    if( showSide1 == false && showSide2 == false && showSide3 == false && showSide4 == false && showSide5 == false && showSide6 == false )
    {
        glPopMatrix( );
        return;
    }

    GLfloat cube[] = 
    {
        -0.5f, -0.5f,  0.5f,// Front face
         0.5f, -0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f, -0.5f, -0.5f,// Back face
        -0.5f,  0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f,  0.5f,// Left face
        -0.5f,  0.5f,  0.5f,
        -0.5f, -0.5f, -0.5f,
        -0.5f,  0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,// Right face
         0.5f,  0.5f, -0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,// Top face
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f,  0.5f,// Bottom face
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f, -0.5f, -0.5f 
    };

    float textures[] =
    {
        1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 

        0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 

        0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 

        0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 

        0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 

        0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f
    };

    //ss << position.x + 2 << ", " << position.y << ", " << position.z << std::endl;

    glVertexPointer(3, GL_FLOAT, 0, cube);
    glTexCoordPointer(2, GL_FLOAT, 0, textures);

    if( showSide1 || showSide2 || showSide3 || showSide4 )
        glBindTexture(GL_TEXTURE_2D, imageSides->texture);

    if( showSide1 )
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    if( showSide2 )
        glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);

    if( showSide3 )
        glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);

    if( showSide4 )
        glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);

    if( showSide5 )
    {
        glBindTexture(GL_TEXTURE_2D, imageUp->texture);
        glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
    }

    if( showSide6 )
    {
        glBindTexture(GL_TEXTURE_2D, imageDown->texture);
        glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
    }

    glPopMatrix( );
}

Я почти уверен, что это неэффективно, как я уже говорил ранее, этот код скоро будет оптимизирован. Теперь я пытаюсь заставить его работать. Логические переменные showSide сделаны для обнаружения, если рядом есть поле с другим полем, стороны между ними не будут нарисованы.

Я искал и гуглил, как сделать окклюзионный куллинг, но так и не смог, есть только лаконичные сведения или теория.

Мой вопрос: может ли кто-нибудь помочь мне, как не рисовать закрытые блоки? Я слышал, что есть GLEW, который я скомпилировал и внедрил, он состоит из двух следующих строк: glBeginQuery(GL_SAMPLES_PASSED_ARB, query); glEndQuery (GL_SAMPLES_PASSED);

Судя по всему Query помог решить мою проблему, но я безуспешно пытался использовать его с гуглом разными способами, во-первых кубики не рисовались, во-вторых игра рисовалась как раньше, закрытые кубики тоже.


person Radosław Wójciak    schedule 10.07.2013    source источник


Ответы (1)


Как правило, вы не должны ожидать, что графический API сделает всю работу за вас — его работа заключается в рендеринге, а ваша задача — убедиться, что он должен рендерить как можно меньше.

Я рекомендую прочитать этот блог: http://www.sea-of-memes.com/summary/blog_parts.html

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

person riv    schedule 10.07.2013
comment
Хотя я согласен, это не означает, что вы не должны использовать информацию, такую ​​​​как то, что доставляется запросом окклюзии, для увеличения подготовки сцены во время рендеринга. Выполнение быстрого теста запроса окклюзии с использованием ограничивающих прямоугольников в пикселях отрендеренной сцены может эффективно отказаться от рендеринга больших объемов геометрии, которые было бы очень сложно протестировать на графе сцены на ЦП; подумайте о вещах, отрендеренных с помощью альфа-тестирования (листья на дереве, трава), которые могут привести к полному перекрытию вещей позади; трудно протестировать на графе сцены, легко выполнить запрос окклюзии. - person datenwolf; 10.07.2013
comment
Конечно, окклюзионные запросы — это то, что нужно иметь в виду для более сложных сценариев, но я сомневаюсь, что это окажется полезным при рендеринге мира, состоящего из кубов: вы будете (почти) рендерить куб, чтобы узнать, следует ли вам это делать. визуализировать... куб. - person riv; 10.07.2013