opengl3 20k sprites 帧速率慢?

Posted

技术标签:

【中文标题】opengl3 20k sprites 帧速率慢?【英文标题】:opengl3 20k sprites slow framerate? 【发布时间】:2015-08-07 10:44:08 【问题描述】:

我已经成功用golang制作了一个opengl 3.x动画。然而;仅在渲染 20k 纹理后,逐帧更新才明显变慢。所有精灵所做的只是简单地从屏幕左侧移动到右侧。请记住,它们都在彼此之上,因为我懒得随机定位。

我有一台更新的 PC,可以在高设置下运行 GTA5,但无法在 opengl3 环境中显示 20k 精灵(带纹理的四边形)??

我一定是在这里做错了什么。也许我需要将所有顶点打包在一个 VBO 中,而不是为每个对象打包一个新的 vbo?我也绑定了每个对象。我不确定是什么导致了这个瓶颈。有人可以帮忙吗,因为我不知道从这里去哪里?

我附上了我的代码作为参考,任何人都可以提供一些关于在 opengl3 中加速渲染 20k 精灵的提示: http://pastebin.com/SHQtRPn7

【问题讨论】:

【参考方案1】:

在不查看源代码的情况下,您应该使用一个 VBO 并为所有共享纹理的精灵组合几何图形,并使用一次绘制调用来绘制它们。

【讨论】:

如果一切都在一个 vbo 中,我如何对每个对象应用转换?我是否将制服传递给包含矩阵的顶点着色器?或者我是否使用客户端更新每个顶点,以便着色器获取已经转换的顶点? 我还觉得将较大的 VBO 传输到着色器所需的时间会抵消较小的着色器传输,从而抵消任何性能优势? 如果您小心操作,数据传输会在后台发生,而您的程序已经在执行其他操作。【参考方案2】:

OpenGL 调用很昂贵。你在每一帧中都做了很多一万次。相反,如果可能的话,你想做一个大的draw call。如果没有,每个纹理 + 程序组合一个绘制调用。

您可以为您绘制的每个对象传递一个矩阵,而不是将矩阵作为统一传递。

这段代码不如它应该的那么好,但它的性能比你的要好几个数量级。

func (drawer *SpriteDrawer) Draw(sprites []Sprite) 
    if len(sprites) == 0 
        return
    

    drawer.Use()
    drawer.Texture.Bind(gl.TEXTURE_2D_ARRAY)

    tmp := drawer.GetTransform().To32()
    drawer.camera_uniform.UniformMatrix2x3f(false, &tmp)

    vertexbuffer := gl.GenBuffer()
    defer vertexbuffer.Delete()
    vertexbuffer.Bind(gl.ARRAY_BUFFER)

    stride := int(unsafe.Sizeof(sprites[0]))

    gl.BufferData(gl.ARRAY_BUFFER, stride*len(sprites), sprites, gl.STREAM_DRAW)

    var transform1, transform2, texcoords, texlevel gl.AttribLocation
    transform1 = 0
    transform2 = 1
    texcoords = 2
    texlevel = 3

    transform1.AttribPointer(3, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].Transform))
    transform2.AttribPointer(3, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].Transform)+unsafe.Sizeof(sprites[0].Transform[0])*3)
    texcoords.AttribPointer(4, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].TextureLeft))
    texlevel.AttribPointer(1, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].Layer))

    transform1.EnableArray()
    transform2.EnableArray()
    texcoords.EnableArray()
    texlevel.EnableArray()

    gl.DrawArrays(gl.POINTS, 0, len(sprites))

    transform1.DisableArray()
    transform2.DisableArray()
    texcoords.DisableArray()
    texlevel.DisableArray()

library this is from

【讨论】:

【参考方案3】:

我看到的一个问题是您每帧都创建一个 vbo。我不确定您要做什么。如果您尝试更新您的 vbo,请改用 glBufferSubData()。 glBufferData() 每次调用它时都会创建一个新缓冲区,因此它肯定会比 glBufferSubData() 更昂贵。 glBufferSubData() 只是修改/更新你的 vbo。这应该可以提高您的 fps。

【讨论】:

所以对于我的每个 vbo(uv、颜色、顶点)我应该调用 glbuffersubdata 并且只在循环开始前调用 glbuffer 一次?我说的对吗? 是的 :)。您使用 glBufferData() 分配内存,然后如果需要修改它,只需使用 glBufferSubData() 谢谢。这真的会给我带来那么大的 fps 提升吗...我的意思是它仅落后于 20k 四边形(4 个顶点)。使用我的显卡/cpu 应该每帧处理数十万个顶点? 不能肯定地说。这只是增加开销的一件事。 如果您修改 vbo 只是为了应用转换(平移、旋转或缩放),那么您应该只将矩阵传递给着色器。我认为这将比 glBufferSubData() 提高 fps。

以上是关于opengl3 20k sprites 帧速率慢?的主要内容,如果未能解决你的问题,请参考以下文章

限制 Sprite 套件帧率

从 onCameraFrame、OpenCV、Android/Java 调用 HoughCircles() 方法时改变慢帧速率

使用libav编码时根据经过时间计算帧PTS

OpenGL帧率:与窗口大小的关系

Sprite 帧动画 Cocos2d 3.0

Python人脸识别慢