3d遮挡剔除

时间:2011-02-14 18:08:26

标签: opengl 3d culling occlusion

我正在用C ++ / openGL编写类似静态3d块世界的Minecraft。我正在努力提高帧率,到目前为止,我已经使用八叉树实现了截锥体剔除。这有帮助,但我仍然看到中等到坏的帧速率。下一步是通过更近的立方体来剔除从视点隐藏的立方体。但是,我无法找到很多关于如何实现这一目标的资源。

5 个答案:

答案 0 :(得分:8)

创建启用了Z缓冲区(或“深度缓冲区”)的渲染目标。然后确保对所有不透明物体进行排序,使它们从前到后渲染,即最先靠近摄像机的物体。在渲染所有不透明物体之后,任何使用alpha混合的东西仍然需要渲染回来。

另一种技术是遮挡剔除:您可以便宜地“干式渲染”几何体,然后找出深度测试中有多少像素失败。在DirectX和OpenGL中有遮挡查询支持,但不是每个GPU都能做到这一点。

缺点是在渲染和获取结果之间需要延迟 - 取决于设置(如使用预测平铺时),它可能是一个完整的帧。这意味着你需要在那里发挥创造力,比如渲染一个比对象本身更大的边界框,并在相机切割后忽略结果。

还有一件事:更传统的解决方案(您可以同时使用遮挡剔除)是一个房间/门户系统,您可以将区域定义为“房间”,通过“门户”连接。如果您当前的房间看不到门户网站,则无法看到与其连接的房间。即便如此,您也可以单击视口到门户网站可见的内容。

答案 1 :(得分:5)

我在this minecraft level renderer中采用的方法基本上是截头限制的洪水填充。 16x16x128块分为16x16x16个块,每个块都带有一个具有相关几何形状的VBO。我在玩家所在位置的chunklet网格中开始填充,以找到要渲染的存储块。填充受限于:

  1. 查看视锥体
  2. 固体存储块 - 如果存储块的整个边是不透明块,则填充不会以该方向进入存储块
  3. 方向 - 洪水不会反转方向,例如:如果当前的存储块位于起始存储块的北部,则不会涌入南面的存储块
  4. 似乎工作正常。我是在android上,所以虽然更复杂的分析(Mike Daniels所指出的反向移植)会剔除更多的几何体,但我已经限制了CPU,所以没有多大意义。

    我刚刚看到你对Alan的回答:剔除不是你的问题 - 这就是你向OpenGL发送的速度和速度。

    绘制内容:不为每个块渲染立方体,渲染与不透明块相邻的透明块的面。考虑一块3x3x3的立方体,比方说,石块:没有点绘制中心区块,因为玩家无法看到它。同样,玩家永远不会看到两个相邻石块之间的面孔,所以不要画它们。

    如何绘制:如Alan所述,使用VBO批处理几何体。你不会相信他们做得多快多快。

    对现有代码进行最少的更改,更简单的方法是使用display lists。这就是我的世界所用的。

答案 2 :(得分:4)

您渲染了多少块以及在哪些硬件上?现代硬件非常快,很难用几何体来压倒(除非我们谈论的是手持平台)。在任何适度的桌面硬件上,你应该能够以每秒60帧的速度每帧渲染数十万个立方体,而不需要任何花哨的剔除技巧。

如果您使用单独的绘制调用绘制每个块(glDrawElements / Arrays,glBegin / glEnd等)(奖励积分:不使用glBegin / glEnd)那么这将是您的瓶颈。这对初学者来说是一个常见的陷阱。如果您正在执行此操作,则需要将共享纹理和着色参数的所有三角形一起批处理为每个设置的单个调用。如果几何图形是静态的并且不会逐帧更改,则您希望为每批三角形使用一个Vertex Buffer Object

如果您通常在视锥体中一次只占整个游戏世界的一小部分,那么这仍然可以与八叉树剔除相结合。顶点缓冲区仍然静态加载而不会更改。 Frustum剔除八叉树只生成平截头体中三角形的索引缓冲区,并在每帧中动态上传它们。

答案 3 :(得分:3)

如果表面靠近相机,则可以创建一个表示不可见区域的平截头体,并剔除完全包含在该平截头体中的对象。在下图中,C是相机,|是相机附近的平面,由.组成的平截头体形区域代表遮挡区域。表面称为antiportal

        .
       ..
      ...
     ....
    |....
    |....
    |....
    |....
C   |....
    |....
    |....
    |....
     ....
      ...
       ..
        .

(你当然也应该开启其他答案和评论中提到的深度测试和深度编写 - 在OpenGL中这很简单。)

答案 4 :(得分:-2)

使用Z-Buffer可确保多边形正确重叠。

启用深度测试会使每个绘图操作在将像素放到屏幕上之前检查Z缓冲区。

如果你有凸对象,你必须(为了表现)启用背面剔除!

示例代码:

glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE);

你可以改变传递GL_FRONT或GL_BACK的glCullFace()的行为......

glCullFace(...);

//画“游戏世界”......