c# - Opengl - "fullscreen"纹理渲染性能问题

标签 c# opengl opentk

我正在用 openGL 编写一个 2D 游戏,在渲染覆盖整个窗口的几个纹理时遇到了一些性能问题。

我所做的实际上是创建一个具有屏幕大小的纹理,使用 FBO 将我的场景渲染到该纹理上,然后使用不同的偏移量渲染纹理几次以获得一种“阴影”效果。但是当我这样做时,我在使用我的集成显卡时性能会大幅下降。

所以总而言之,我在整个屏幕上渲染了 7 个四边形(背景图像,5 个带有黑色“色调”的“阴影图像”和具有真实颜色的相同纹理)。我正在使用大小为 1024x1024 的 RGBA 纹理并将它们放入 900x700 的窗口中。当我不渲染纹理时,我得到 200 FPS,而当我这样做时,我得到 34 FPS(在这两种情况下,我实际上创建了纹理并将场景渲染到它上面)。我觉得这很奇怪,因为我基本上只渲染了 7 个四边形。一个奇怪的事情是,当我运行 CPU 分析器时,它并不表明这是瓶颈(我知道 opengl 使用管道架构,这件事可能会发生,但大多数时候不会)。

当我使用外置显卡进行上述测试时,我获得了一致的 200 FPS。但是当我禁用场景渲染到纹理并禁用纹理渲染到屏幕上时,我得到了 ~1000 FPS。这仅发生在我的外部视频卡上 - 当我使用集成显卡禁用 FBO 时,我得到相同的 200 FPS。这真的让我很困惑。

谁能解释一下发生了什么,以及上面的数字是否正确?

集成显卡 - Intel HD Graphics 4000

外置显卡 - NVIDIA GeForce GTX 660M

附言我正在用 C# 编写我的游戏 - 所以如果有任何帮助,我会使用 OpenTK。

编辑:

首先感谢所有的回复——他们在某种程度上都非常有帮助,但不幸的是,我认为它不仅仅是“简化/优化你的代码”。让我分享一些我的渲染代码:

//fields defined when the program is initialized

Rectangle viewport;
//Texture with the size of the viewport
Texture fboTexture;
FBO fbo;

//called every frame
public void Render()
{
    //bind the texture to the fbo
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo.handle);
    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, fboTexture,
       TextureTarget.Texture2D, texture.TextureID, level: 0);

    //Begin rendering in Ortho 2D space
    GL.MatrixMode(MatrixMode.Projection);
    GL.PushMatrix();
    GL.LoadIdentity();
    GL.Ortho(viewport.Left, viewport.Right, viewport.Top, viewport.Bottom, -1.0, 1.0);
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PushMatrix();
    GL.LoadIdentity();

    GL.PushAttrib(AttribMask.ViewportBit);
    GL.Viewport(viewport);

    //Render the scene - this is really simple I render some quads using shaders
    RenderScene();

    //Back to Perspective
    GL.PopAttrib(); // pop viewport
    GL.MatrixMode(MatrixMode.Projection);
    GL.PopMatrix();
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PopMatrix();

    //Detach the texture
    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, fboTexture, 0,
                    0, level: 0);
    //Unbind the fbo
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);

    GL.PushMatrix();
    GL.Color4(Color.Black.WithAlpha(128)); //Sets the color to (0,0,0,128) in a RGBA format

    for (int i = 0; i < 5; i++)
    {
        GL.Translate(-1, -1, 0);
        //Simple Draw method which binds the texture and draws a quad at (0;0) with
        //its size
        fboTexture.Draw();
    }
    GL.PopMatrix();
    GL.Color4(Color.White);
    fboTexture.Draw();
}

所以我认为 fbo 和渲染到纹理上实际上没有任何问题,因为这不会导致程序在我的两张卡上都变慢。以前我每帧都初始化 fbo,这可能是我的 Nvidia 卡变慢的原因,但是现在当我预初始化所有内容时,无论有没有 fbo,我都获得相同的 FPS。

我认为问题不在于一般的纹理,因为如果我禁用纹理并只渲染无纹理的四边形,我会得到相同的结果。而且我仍然认为我的集成卡在屏幕上只渲染 7 个四边形时应该运行速度超过 40 FPS,即使它们覆盖了整个屏幕。

你能给我一些关于如何实际分析并发回结果的提示吗?那真的很有用。

编辑 2:

好的,我尝试了一些并设法获得了更好的性能。首先,我尝试使用着色器渲染最终的四边形 - 这对性能没有我预期的任何影响。

然后我尝试运行分析器。但据我所知,SlimTune 只是一个 CPU 分析器,它没有给我想要的结果。然后我尝试了 gDEBugger。它与 Visual Studio 集成,后来我发现它不支持 .NET 项目。我尝试运行外部版本,但它似乎不起作用(但也许我只是玩得不够)。

真正做到这一点的事情是,我不是直接将 7 个四边形渲染到屏幕上,而是首先将它们渲染在纹理上,再次使用 fbo,然后将最终纹理渲染到屏幕上。这使我的 fps 从 40 提高到 120。这至少可以说是一种古玩。为什么渲染到纹理比直接渲染到屏幕更快?不过感谢大家的帮助 - 看来我已经解决了我的问题。如果有人对这种情况提出合理的解释,我将不胜感激。

最佳答案

显然这是一个猜测,因为我还没有看到或分析过您的代码,但我猜想集成卡只是在为您的后期处理而苦苦挣扎(多次绘制纹理以实现您的“阴影”效果)。
我不知道您对这些概念的熟悉程度,如果我在这里有点冗长,请见谅。
关于后处理
后处理是将完成的场景渲染为纹理,然后在将图像显示在屏幕上之前对图像应用效果的过程。后处理的典型用途包括:

  • Bloom - 通过将明亮的像素“渗入”相邻的较暗像素来更自然地模拟亮度。
  • 高动态范围渲染 - Bloom 的老大哥。场景被渲染为浮点纹理,允许更大的颜色范围(与通常的 0 表示黑色和 1 表示全亮度相反)。屏幕上显示的最终颜色是使用屏幕上所有像素的平均亮度计算出来的。所有这一切的结果是,相机的行为有点像人眼——在黑暗的房间里,明亮的光线(比如,透过 window )看起来非常明亮,但是一旦你走到外面,相机就会调整,光线只会看起来像如果你直视太阳,就会很亮。
  • Cel-shading - 修改颜色以提供卡通般的外观。
  • 运动模糊
  • 景深 - 游戏中的相机近似于真实的(或您的眼睛),其中只有一定距离处的物体处于对焦状态,其余物体模糊。
  • 延迟着色 - 一种相当高级的后处理应用程序,其中在渲染场景后计算照明。这会消耗大量的视频 RAM(它通常使用多个全屏纹理),但允许将大量灯光快速添加到场景中。

  • 简而言之,您可以使用后期处理来获得许多巧妙的技巧。很遗憾...
    后期处理有成本
    后处理的一个很酷的地方是它的成本与场景的几何复杂性无关——无论你画一百万个三角形还是你画十几个三角形,它所花费的时间都是一样的。然而,这也是它的缺点。即使您只是一遍又一遍地渲染四边形以进行后期处理,渲染每个像素也是有成本的。如果要使用更大的纹理,成本会更大。
    专用显卡显然有更多的计算资源来应用后处理,而集成显卡通常可以应用的资源要少得多。正是由于这个原因,视频游戏的“低”图形设置通常会禁用许多后处理效果。这不会在 CPU 分析器上显示为瓶颈,因为延迟发生在显卡上。 CPU 在继续您的程序之前正在等待显卡完成(或者,更准确地说,CPU 在等待显卡完成时正在运行另一个程序)。
    如何加快速度?
  • 使用更少的通行证。如果将传递次数减半,则进行后处理所需的时间也会减半。为此,
  • 使用着色器。由于我没有看到您在任何地方提及它们,我不确定您是否正在使用着色器进行后期处理。着色器本质上允许您使用类 C 语言编写函数(因为您使用的是 OpenGL,您可以使用 GLSL 或 Cg),该函数在对象的每个渲染像素上运行。它们可以采用您喜欢的任何参数,并且对于后期处理非常有用。您可以使用着色器设置要绘制的四边形,然后您可以插入您希望在场景的每个像素上运行的任何算法。
  • 关于c# - Opengl - "fullscreen"纹理渲染性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13131483/

    相关文章:

    c++ - 设计着色器类

    c# - Carbon ReceiveNextEvent 和辅助线程

    c# - 在 Azure ASP.NET 网站中选择地理坐标时出错

    Haskell 中的 OpenGL VBO

    cocoa 和OpenGL : fastest way to draw array of rectangles

    C# OpenTK - 纹理四边形

    c# - Visual C# 中哪个库用于图形编程,Tao 还是 OpenTK?

    javascript - C# 相当于 Python 属性定制/Javascript 对象字面量

    c# - 当查询不为空时,自动映射器投影返回空列表

    c# - ds.Tables[0].Select() 代表什么