OpenGL:如何在 3d 模式下优化多层相互重叠的 2d 渲染?

Posted

技术标签:

【中文标题】OpenGL:如何在 3d 模式下优化多层相互重叠的 2d 渲染?【英文标题】:OpenGL: How to optimize 2d rendering with multiple layers overlapping each other in 3d mode? 【发布时间】:2011-06-06 12:36:31 【问题描述】:

我知道如何通过简单地首先渲染最近的平面来加速 3d 渲染。

但是我如何在 2d 模式下利用这种方法呢?我不能使用深度测试,因为它们都在同一个 z 级别。

所以我在想当我不需要渲染“下面”图层的不可见部分时是否可以加快速度。这可能吗?

请注意,我在 3d 模式下渲染,可能同时存在 3d 对象和 2d 对象。所以我不能只切换到 2d 渲染,我总是对所有东西使用 3d 坐标。而且我可以随心所欲地旋转相机,因此不能接受特定于相机的技巧。

编辑: 我尝试了 Ville 建议的方法:

(http://img815.imageshack.us/img815/7857/zfighting.png)

但正如你所见,它会导致 z-fighting。

我用来渲染的代码在这里:

glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_POLYGON_OFFSET_FILL);

glColor4f(1,0,0,1);
DrawQuad(0, 0, 10, 10);

glColor4f(0,0,1,1);
DrawQuad(5, 5, 15, 15);

glDepthFunc(GL_LEQUAL);

【问题讨论】:

深度测试(使用默认模式 GL_LESS)即使您的所有 2d 对象都在同一个 z 水平上,仍然可以工作。像素不会更新两次。 @Ville,这会导致 z-fight。查看我发布的图片。 你说得对,我以为你的意思是 2d 对象 HUD 样式,但不明白你也打算围绕 2d 对象旋转相机。为此,我会首先像 derkyjadex 建议的那样以正交模式渲染纹理。 @Ville,渲染到纹理不会是矫枉过正...?我特别想找到比我使用 atm 的方法更快的方法:只是禁用深度测试。但我希望我可以优化一下,因为它确实绘制了一些永远不可见的无用像素...... 【参考方案1】:

听起来您在同一平面上渲染所有“2D”对象。您可以使用正交投影将 2D 部件渲染到屏幕外帧缓冲区中,并按照 datenwolf 的建议为它们提供不同的 Z 值。然后将帧缓冲区纹理渲染到您的主 3D 场景中。

【讨论】:

或者只是清除深度缓冲区并使用 2D 平面过度绘制。 渲染到帧缓冲区比仅仅禁用深度测试更快? 可能没有,datenwolf 或许有更好的建议。但是您并没有禁用深度测试,而是清除了深度缓冲区,以便 OpenGL“忘记”已经渲染的 3D 对象。使用单独的帧缓冲区有效地做同样的事情,但如果某些 3D 对象应该出现在 2D 对象的前面,则您可以保留 3D 深度缓冲区。【参考方案2】:

您对 2D 模式的理解是什么?你是说正交投影吗?然后我有一个好消息:深度测试也可以完美地工作。 gluOrtho2D 与 glOrtho(..., -1, 1); 基本相同。即你有 Z 范围 -1 ... 1 可以花费。

因评论而编辑:

完全可以在一帧中组合渲染多个投影:

void render_perspective_scene(void);

void render_ortho_scene(void);

void render_HUD();

void display()

    float const aspect = (float)win_width/(float)win_height;

    glViewport(0,0,win_width,win_height);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-aspect*near/lens, aspect*near/lens, -near/lens, near/lens, near, far);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    render_perspective_scene();

    // just clear the depth buffer, so that everything that's
    // drawn next will overlay the previously rendered scene.
    glClear(GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-aspect*scale, aspect*scale, -scale, scale, 0, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    render_ortho_scene();

    // Same for the HUD, only that we render
    // that one in pixel coordinates.
    glClear(GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, win_width, 0, win_height, 0, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    render_HUD();

当然,如果您喜欢那些将投影矩阵设置放置在重塑处理程序中的糟糕教程,那么您当然会心烦意乱,无法看到明显的解决方案。

【讨论】:

“请注意,我在 3d 模式下渲染,可能同时存在 3d 对象和 2d 对象。所以我不能切换到仅 2d 渲染”你读了吗? 当然可以切换。你认为游戏 HUD 是如何渲染的? HUD 不是我想要在这里实现的。想象一下,你有一个普通的 3d 世界,然后你以 2d 模式从上往下渲染 3d 世界,然后旋转相机,你看到世界变平了。 好吧,你有一些严重的误解:OpenGL 不是场景图。一旦您将一些几何图形发送到 OpenGL,只需将其栅格化为像素,然后忘记几何图形。所以去正交,渲染一些东西,然后旋转/切换投影不会改变你已经绘制到帧缓冲区的任何东西。因此,您实际上需要做的是渲染纹理,然后绘制这些四边形,或者使用一些着色器魔法将几何平面投影到这些平面上,但仍然传递可用于深度测试的深度值。 我尝试过使用着色器,但它也需要关闭深度测试......我想那时没有解决方案,我也不是真的需要它,但作为一个优化怪胎,我想知道每一个技巧:P

以上是关于OpenGL:如何在 3d 模式下优化多层相互重叠的 2d 渲染?的主要内容,如果未能解决你的问题,请参考以下文章

如何绘制两个相互重叠的图形?

CSOL OpenGL与D3D哪个好?

AutoLayout 的按钮相互重叠

OPENGL和D3D哪个好

dx和 opengl 有啥区别?

与 OpenGL 的重叠线