C/C++ OpenGL 遮挡剔除

Posted

技术标签:

【中文标题】C/C++ OpenGL 遮挡剔除【英文标题】:C/C++ OpenGL Occlusion Culling 【发布时间】:2013-07-10 11:26:44 【问题描述】:

我正在尝试原始 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( );

我很确定它的效率很低,正如我之前所说的,这段代码很快就会被优化。现在我正在努力让它发挥作用。 bool 变量 showSide 是用来检测的,如果有 box 旁边有其他 box,则不会绘制它们之间的边。

我一直在寻找和搜索如何进行遮挡剔除,但失败了,只有简洁的信息或理论。

我的问题是,谁能帮助我如何不绘制覆盖块?我听说有我编译和注入的 GLEW,它有以下两行: glBeginQuery(GL_SAMPLES_PASSED_ARB, 查询); glEndQuery(GL_SAMPLES_PASSED);

显然 Query 有助于解决我的问题,但是我尝试在 Google 上使用它的很多方法都没有成功,首先没有绘制立方体,其次游戏像之前一样绘制,也覆盖了立方体。

【问题讨论】:

【参考方案1】:

通常,您不应期望图形 API 为您完成工作 - 它的工作是渲染,而您的工作是确保它尽可能少地渲染。

我推荐阅读这个博客:http://www.sea-of-memes.com/summary/blog_parts.html

这是关于某人从头开始开发类似于我的世界的引擎,并且涵盖了从遮挡到照明再到透明度的所有内容。事实上,第一部分应该很好地回答了你的问题。

【讨论】:

虽然我同意,但这并不意味着您不应该使用遮挡查询提供的信息来增强渲染时的场景准备。使用边界框对目前渲染的场景像素进行快速遮挡查询测试可以有效地丢弃大量几何图形的渲染,这在 CPU 上的场景图中很难测试;想想使用 alpha 测试渲染的东西(树上的叶子、草),这可能相当于完全遮挡后面的东西;难以在场景图中测试,易于遮挡查询。 当然,对于更复杂的场景,遮挡查询是需要牢记的,但我怀疑这对于渲染一个由立方体组成的世界是否有用:你会(几乎)渲染一个立方体,看看你是否应该渲染......一个立方体。

以上是关于C/C++ OpenGL 遮挡剔除的主要内容,如果未能解决你的问题,请参考以下文章

Unity4.3 遮挡剔除:基本知识

Occlusion(遮挡剔除)

unity 遮挡剔除的实现

unity 遮挡剔除的实现

Unity学习笔记4:遮挡剔除LODProfiler光照声音

Unity学习笔记4:遮挡剔除LODProfiler光照声音