如何在QQuickFramebufferObject中呈现文本?

时间:2017-05-30 19:50:52

标签: qt opengl text qml qtquick2

动机:我目前在QML场景中有1000个简单项目,其中一个以60fps动画,所以整个场景以60fps重新绘制。在我的电脑上,我的每个虚拟内核的CPU使用率平均为15%。在目标硬件上情况更糟 - 在4个物理核心中的每一个上都有60%,导致过热,导致冻结。请注意,我已经实现了优化:通过Loader s,卸载(滚动)视口之外的所有项目(因此,在任何给定时间只加载~18个项目)。我报告的性能统计数据 此优化 - 没有它更糟糕。

我的解决方案是开始在一个QQuickFramebufferObject中绘制所有1000个项目,并停止将它们作为实际的QML项目。这样我就可以避免Qt因为只有1000件(卸载!)物品而惩罚我。

虽然我陷入困境:如何在OpenGL中绘制项目的文本部分?

方法1:我知道QPainter可以用来直接将文本渲染到QOpenGLWidget中,但QQFBO中似乎没有这个选项。

方法2:在QML中使用Text设置一个无父layer.enabled: true项,设置其text属性,等待1帧(用于渲染)然后获取纹理。有点丑陋和迂回;也可能是慢慢的。

方法3:查看QQuickText的来源,了解它的作用并复制它。可能很难,我必须遵守许可限制。

方法4:使用QPainter将软件渲染到QImage,然后将该图像上传到纹理。优雅,但可能太慢。

关于这样做的方法的任何建议都没有这些方法中的问题?

1 个答案:

答案 0 :(得分:0)

目前尚不清楚为什么渲染一项会使整个场景重新绘制。但是,如果只有一项正在制作动画,则可能需要拆分场景。那些不动的人应该放在父项中,而一个人可以在外面。

有一种相当简单的方法可以将子树渲染为FBO,只需将子树渲染为ShaderItem即可。

此示例使用灰度着色器(borrowed from the example at Qt docs)渲染图像:

import QtQuick 2.0

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            vertexShader: "
                uniform highp mat4 qt_Matrix;
                attribute highp vec4 qt_Vertex;
                attribute highp vec2 qt_MultiTexCoord0;
                varying highp vec2 coord;
                void main() {
                    coord = qt_MultiTexCoord0;
                    gl_Position = qt_Matrix * qt_Vertex;
                }"
            fragmentShader: "
                varying highp vec2 coord;
                uniform sampler2D src;
                uniform lowp float qt_Opacity;
                void main() {
                    lowp vec4 tex = texture2D(src, coord);
                    gl_FragColor = vec4(vec3(dot(tex.rgb,
                                        vec3(0.344, 0.5, 0.156))),
                                             tex.a) * qt_Opacity;
                }"
        }
    }
}

ShaderEffect只是纹理的渲染,您看到的是一个填充有对象图片的矩形。在这种情况下,幻觉仍然存在,但是您的动画对象仅处理单个纹理矩形。

我不知道这是否是解决方案,因为问题似乎出在其他地方。请详细说明您的问题,我可能会根据需要更新答案。

我知道这似乎是您的第二种方法,但是在这种情况下,您将对整个未更改的子树进行纹理化。如果我可能因为某种滚动动画而似乎一次又一次将批处理文本滚动到GPU,则如果您使用ShaderEffect和长条项目,则可以仅对滚动窗口进行动画处理,并始终将文本保持静态,从而避免批处理。