用于渲染大量立方体的剔除技术

jma*_*erx 21 c c++ algorithm rendering

我正在制作一个个人学习项目来制作一个Minecraft克隆.除了一件事,它的工作非常好.类似于我的世界,我的地形有很多立方体堆叠在Y上,所以你可以挖掘.虽然我做了截头剔除,但这仍然意味着我无用地在我下面画出所有层的立方体.立方体是X,Y和Z有序的(虽然只在1个方向,所以从技术上讲,它不是Z订购到相机).我基本上从玩家的位置只添加指向玩家周围的立方体的指针.然后,我对这些进行了截击.我不做oct树细分.我想只是没有渲染玩家下面的图层,除非玩家向下看到一个洞时这不起作用.鉴于此,我怎么能避免在我下面渲染我看不到的立方体,或者还有其他立方体隐藏的立方体.

谢谢

void CCubeGame::SetPlayerPosition()
{
PlayerPosition.x = Camera.x / 3;
PlayerPosition.y = ((Camera.y - 2.9) / 3) - 1;
PlayerPosition.z = Camera.z / 3;
}

void CCubeGame::SetCollids()
{

SetPlayerPosition();

int xamount = 70;
int zamount = 70;
int yamount = 17;

int xamountd = xamount * 2;
int zamountd = zamount * 2;
int yamountd = yamount * 2;
PlayerPosition.x -= xamount;

PlayerPosition.y -= yamount;

PlayerPosition.z -= zamount;


collids.clear();
CBox* tmp;

    for(int i = 0; i < xamountd; ++i)
    {
        for(int j = yamountd; j > 0; --j)
        {
            for(int k = zamountd; k > 0; --k)
            {

                tmp = GetCube(PlayerPosition.x + i, PlayerPosition.y + j, PlayerPosition.z + k);



                if(tmp != 0)
                {
                    if(frustum.sphereInFrustum(tmp->center,25) != NULL)
                    {
                        collids.push_back(tmp);
                    }
                }

            }
        }

}
Run Code Online (Sandbox Code Playgroud)

Ben*_*son 16

这是我在编写自己的克隆时学到的:

  1. 不要只是将每个多维数据集转储到OpenGL中,也不要担心自己完成所有可见性修剪.如另一个答案所述,检查所有6个面以查看它们是否被相邻块完全遮挡.仅渲染可见的面.这大致减少了从立方项(立方体体积n*n*n)到平方项(表面仅约n*n)的面数.
  2. OpenGL可以比你更快地查看截头剔除.将所有曲面面渲染到显示列表或VBO后,只需将整个blob发送到OpenGL即可.如果你将几何体分成切片(或Minecraft称之为块),你可能会避免绘制你可以很容易地确定在相机背后的块.
  3. 将整个几何体渲染到显示列表(或列表)中,并每次重绘.如果您使用立即模式,这是一个简单的步骤,因为您只需将现有代码包装在glNewList/glEndList中并使用glCallList重绘.减少OpenGL调用计数(每帧)将比减少要渲染的多边形总量产生更大的影响.
  4. 一旦你看到生成显示列表需要多长时间而不是绘制它们,你将开始考虑如何将更新放入一个线程.这是转换为VBO的结果:线程呈现为普通的旧数组(例如,向数组添加3个浮点数而不是调用glVertex3f)然后GL线程只需要使用glBufferSubData将它们加载到卡中.你赢了两次:代码可以在一个线程中运行,并且可以用3个数组写入而不是3个函数调用"绘制"一个点.

我注意到的其他事情:

VBO和显示列表具有非常相似的性能.给定的OpenGL实现很可能在内部使用VBO来存储显示列表.我跳过了顶点数组(一种客户端VBO)所以我不确定那些.使用ARO扩展版本的VBO而不是GL 1.5标准,因为英特尔驱动程序仅实现扩展(尽管声称支持1.5)并且nvidia和ATI驱动程序不关心.

纹理地图集规则.如果您在每张脸上使用一个纹理,请查看地图集的工作原理.

如果你想看我的代码,请在github上找到我.


ybu*_*ill 13

从前到后渲染.为此,您不需要排序,使用八叉树.叶子不是单独的立方体,而是更大的群体.

每个这样的叶子的网格应该缓存在显示列表中(如Bobmitch建议的那样),或者在顶点缓冲区中更好(更新更便宜).生成此网格时,不要以强力方式生成所有立方体.相反,对于每个立方体面,检查它是否在同一个叶子中有一个不透明的邻居,如果是这样,你根本不需要生成这个面.您还可以将具有相同材质的相邻面统一到一个长矩形中.您还可以将网格分成六组,每个主方向一组:+/- XYZ面.仅绘制可能面向相机的那些面部组.

从前到后渲染本身并没有帮助.但是,您可以使用现代硬件提供的遮挡剔除来受益于此排序.在渲染八叉树叶之前,检查其bbox是否通过了遮挡查询.如果它没有通过你根本不需要绘制它.

遮挡查询的替代方法可以是光线跟踪.光线跟踪有利于渲染这样的环境.您可以投射一组稀疏的光线来近似可见的叶子并仅绘制那些叶子.但是,这会低估可见性集.


ues*_*esp 5

像其他人一样,我一直在玩一个使用Ogre的块世界"引擎",并在我去的时候写一些文章(参见Block World Articles).我一直在采取的基本方法是:

  • 仅创建块的可见面(不是块之间的面).
  • 将世界分成更小的块(仅用于更快地更新单个块).
  • 将块纹理组合到一个纹理文件(纹理图集)中.

只需使用这些就可以在大型简单块世界中获得非常好的性能(例如,在合适的硬件上使用1024x1024x1024).