【问题标题】:How to stop rendering invisible faces如何停止渲染不可见的面孔
【发布时间】:2012-04-06 15:16:23
【问题描述】:

我正在制作一个基于体素的游戏,为了它的需要,我正在创建一个块渲染引擎。

重点是,我需要生成很多立方体。每次我渲染超过 16x16x16 块的这些块时,我的 FPS 几乎不会下降,因为它渲染了所有这些立方体的所有 6 个面。那是 24 576 个四边形,我不想要那个。

所以,我的问题是,如何停止渲染不可见的顶点(或四边形),从而提高我的游戏性能?

这是渲染块的类:

public void renderBlock(int posx, int posy, int posz) {
  try{
    //t.bind();
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);// or even GL_FRONT_AND_BACK */);

    glPushMatrix();

    GL11.glTranslatef((2*posx+0.5f),(2*posy+0.5f),(2*posz+0.5f));             // Move Right 1.5 Units And Into The Screen 6.0
    GL11.glRotatef(rquad,1.0f,1.0f,1.0f);

    glBegin(GL_QUADS);               // Draw A Quad

    GL11.glColor3f(0.5f, 0.4f, 0.4f);             // Set The Color To Green
    GL11.glTexCoord2f(0,0);
    GL11.glVertex3f( 1f, 1f,-1f);         // Top Right Of The Quad (Top)
    GL11.glTexCoord2f(1,0);
    GL11.glVertex3f(-1f, 1f,-1f);         // Top Left Of The Quad (Top)
    GL11.glTexCoord2f(1,1);
    GL11.glVertex3f(-1f, 1f, 1f);         // Bottom Left Of The Quad (Top)
    GL11.glTexCoord2f(0,1);
    GL11.glVertex3f( 1f, 1f, 1f);         // Bottom Right Of The Quad (Top)

    //GL11.glColor3f(1.2f,0.5f,0.9f);             // Set The Color To Orange
    GL11.glTexCoord2f(0,0);
    GL11.glVertex3f( 1f,-1f, 1f);         // Top Right Of The Quad (Bottom)
    GL11.glTexCoord2f(0,1);
    GL11.glVertex3f(-1f,-1f, 1f);         // Top Left Of The Quad (Bottom)
    GL11.glTexCoord2f(1,1);
    GL11.glVertex3f(-1f,-1f,-1f);         // Bottom Left Of The Quad (Bottom)
    GL11.glTexCoord2f(1,0);
    GL11.glVertex3f( 1f,-1f,-1f);         // Bottom Right Of The Quad (Bottom)

    //GL11.glColor3f(1.0f,0.0f,0.0f);             // Set The Color To Red
    GL11.glTexCoord2f(0,0);
    GL11.glVertex3f( 1f, 1f, 1f);         // Top Right Of The Quad (Front)
    GL11.glTexCoord2f(1,0);
    GL11.glVertex3f(-1f, 1f, 1f);         // Top Left Of The Quad (Front)
    GL11.glTexCoord2f(1,1);
    GL11.glVertex3f(-1f,-1f, 1f);         // Bottom Left Of The Quad (Front)
    GL11.glTexCoord2f(0,1);
    GL11.glVertex3f( 1f,-1f, 1f);         // Bottom Right Of The Quad (Front)

    //GL11.glColor3f(1f,0.5f,0.0f);             // Set The Color To Yellow
    GL11.glTexCoord2f(0,0);
    GL11.glVertex3f( 1f,-1f,-1f);         // Bottom Left Of The Quad (Back)
    GL11.glTexCoord2f(1,0);
    GL11.glVertex3f(-1f,-1f,-1f);         // Bottom Right Of The Quad (Back)
    GL11.glTexCoord2f(1,1);
    GL11.glVertex3f(-1f, 1f,-1f);         // Top Right Of The Quad (Back)
    GL11.glTexCoord2f(0,1);
    GL11.glVertex3f( 1f, 1f,-1f);         // Top Left Of The Quad (Back)

    //GL11.glColor3f(0.0f,0.0f,0.3f);             // Set The Color To Blue
    GL11.glTexCoord2f(0,1);
    GL11.glVertex3f(-1f, 1f, 1f);         // Top Right Of The Quad (Left)
    GL11.glTexCoord2f(1,1);
    GL11.glVertex3f(-1f, 1f,-1f);         // Top Left Of The Quad (Left)
    GL11.glTexCoord2f(1,0);
    GL11.glVertex3f(-1f,-1f,-1f);         // Bottom Left Of The Quad (Left)
    GL11.glTexCoord2f(0,0);
    GL11.glVertex3f(-1f,-1f, 1f);         // Bottom Right Of The Quad (Left)

    //GL11.glColor3f(0.5f,0.0f,0.5f);             // Set The Color To Violet
    GL11.glTexCoord2f(0,0);
    GL11.glVertex3f( 1f, 1f,-1f);         // Top Right Of The Quad (Right)
    GL11.glTexCoord2f(1,0);
    GL11.glVertex3f( 1f, 1f, 1f);         // Top Left Of The Quad (Right)
    GL11.glTexCoord2f(1,1);
    GL11.glVertex3f( 1f,-1f, 1f);         // Bottom Left Of The Quad (Right)
    GL11.glTexCoord2f(0,1);
    GL11.glVertex3f( 1f,-1f,-1f);         // Bottom Right Of The Quad (Right)

    //rquad+=0.0001f;
    glEnd();
    glPopMatrix();
  }catch(NullPointerException t){t.printStackTrace(); System.out.println("rendering block failed");}
}

这是呈现它们的代码:

private void render() {
  GL11.glClear(GL11.GL_COLOR_BUFFER_BIT|GL11.GL_DEPTH_BUFFER_BIT);
  for(int y=0; y<32; y++){
    for(int x=0; x<16; x++){
      for(int z=0; z<16; z++) {
        b.renderBlock(x, y, z);

      }
    }
  }
}

【问题讨论】:

标签: java opengl lwjgl voxel


【解决方案1】:

您的代码存在较大的性能问题。您不应该使用即时模式 OpenGL 渲染 (glVertexXXX() calls) 来绘制如此大量的顶点。

当您以这种方式执行渲染时,您的代码必须为每个顶点调用图形驱动程序,这很慢。

相反,您应该使用Vertex Buffer Objects。这将允许您将所有几何图形直接上传到显卡上,然后在一个 Java 方法调用中绘制所有立方体(可能是 glDrawArrays)。

【讨论】:

  • 这只是解决较小的问题。这里的问题是他试图以蛮力的方式进行体素渲染,这没有真正的工作机会。至少对于任何重要的输入大小都没有。
【解决方案2】:

我建议,就像 ulmangt 说的,你使用 VBO,但在此之前,你只需要计算可见的面孔。

这可以通过(仅在开始时)检查一张脸是否与空体素(“空气”)相邻来轻松完成。如果是,则将该四边形(面)添加到渲染中。

之后,您只需对已更改体素的邻居进行此检查。示例:当用户移除一个立方体时,检查该体素的 6 个邻居并将这些四边形添加到渲染中。添加体素时执行相反的操作,删除相邻的四边形。

因此,使用由体素组成的 5x5x5 立方体,而不是 750 个四边形,最终得到 150 个。

只需在视图中渲染块(一组体素)(忽略播放器后面的块)并使用距离限制,就可以获得其他收益。

使用八叉树只渲染你知道可能可见的块,你可以更加疯狂。

【讨论】:

  • 谢谢 :) 现在,您知道如何确定体素是否接触体素吗?
  • 好吧,块体素将只是一个填充体素类型的 3d 数组(我认为我的世界在 indev 版本中使用一个字节来表示体素类型,现在不知道。)。想到的最简单的方法是遍历整个数组并检查每个体素的邻居并将可见四边形添加到列表中。 (TL;DR:遍历 3d 体素数组,忽略“空气”类型体素,检查邻居的空气体素,添加可见四边形。)
【解决方案3】:

一个好主意是不要使用立即模式来呈现你的块,我使用显示列表,因为它们最容易设置并且非常快。其次,即使您仍然只使用即时模式,然后在绘图时只使用一个 glBegin/glEnd 调用,在未来使用纹理图集来处理纹理以及您的主要问题是如何停止渲染不可见的面孔,它很简单,我这样做的方式基本上是为每个返回布尔值的面创建六个方法。如果该面方向的块类型是空气块,您将简单地返回,如果是。那么这意味着它将返回true,因此渲染它。在你的draw方法中添加参数“boolean backface, boolean topface...等”和一个if语句来检查绘制哪一面。

希望我能帮上忙,祝你好运!

【讨论】:

  • 这个问题已经超过 2 年了,我已经使用显示列表解决了这个问题。尽管如此,我已经完全离开了这个项目。
  • 我没有看日期,不过对于寻找答案的人来说仍然会有所帮助。
猜你喜欢
  • 2013-08-06
  • 1970-01-01
  • 2016-12-26
  • 2020-11-27
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 2021-06-22
相关资源
最近更新 更多