Scene Graph 和 Painter 的区别
Qt Quick 2系列组件使用了 Scene Graph进行组件的绘制和渲染,这与之前使用 Painter系统(QPainter/Canvas) 有所不同。
如果一个Windows中包含30个组件,那么使用Painter系统需要对这30个组件依次进行绘制,这其中可能包括绘制底色,加载icon,加载纹理等等。 每个组件都经历这些步骤的话就会显得很耗费时间。
使用Scene Graph的话,这30个组件的绘制就是按批次进行的,第一批次绘制所有组件的底色,第二批动作加载icon,第三批加载纹理。这里有效地减少了函数调用次数,因为每次绘制动作都是一次性附加到30个组件中,这样显著地提高了渲染效率。
目前只有 Qt Quick 2的组件使用了 Scene Graph策略。
Scene Graph 依赖于 QQuickWindow
Scene Graph 的绘制和渲染是 有 QQuickWindow 管理和执行的,因此在QWidget这样不是继承自QQuickWindow的窗体中无法插入Qt Quick 2 的组件。
所有希望使用Scene Graph的自定义 QQuickItem 都要实现虚数 QQuickItem::updatePaintNode 。
Scene Graph 是独立于 Painter 系统的一套体系,但是需要依托 QQuickWindow ,且自定义的QQuickItem组件寄生的窗口必须是继承自 QQuickWindow 。
Scene Graph 可以看作一个数据结构,其内部包含了当前 QQuickWindow 下所有 QQuickItem的信息,这些信息可以用来渲染出所有 QQuickItem 。当场景图(scene graph)渲染完成以后,我们可以对Scene Graph中的特定结点进行独立渲染。
目前QQuickWindow没有开放任何接口来控制渲染流程。
其他
Qt Quick Scene Graph 渲染的底层支撑除了 OpenGL 外,还可以使用 Direct3D 12 /OpenVG 等,具体参照helper手册 Scene Graph Adaptations 。
从本源上来说 Scene Graph 其实就是一个 节点树,每个节点都是一个 Item 。
所有的 Item(QQuickItem) 本身都没有 paint() 函数 ,因此也不会绘制自己,自己只要把某些信息完善,并等待 QQuickWindow来根据信息绘制自己即可。
这也是有别于 QWidget 体系的一点,在QWidget 体系下,每个 QWidget 都要实现 paint() 来绘制自己,这也是 Scene Graph系统 和 Painter系统的一个差异。
自定义 Scene Graph中的节点
节点类:Secne Graph中的每一个节点都可以用下面五个类中的一个来表示
QSGClipNode Implements the clipping functionality in the scene graph
QSGGeometryNode Used for all rendered content in the scene graph
QSGNode The base class for all nodes in the scene graph(其他类的基类)
QSGOpacityNode Used to change opacity of nodes
QSGTransformNode Implements transformations in the scene graph
QSGSimpleRectNode a QSGGeometryNode subclass which defines a rectangular
geometry with a solid color material.
QSGSimpleTextureNode a QSGGeometryNode subclass which defines a rectangular
geometry with a texture material.
所有节点类都可以实现QSGNode::preprocess() 函数来进行 scene graph渲染前的预处理工作。
换句话说,QQuickWindow进行scene graph渲染之前,会统一调用所有节点的preprocess()方法。
辅助类:用来定义节点渲染信息的类,通常作为节点类的成员变量。
上文中提到QQuickWindow会使用每个节点的信息来进行节点渲染,这些信息来自这些类。QQuickWindow会遍历节点树中的所有节点(节点类),然后再使用节点中的信息(辅助类提供)完成场景渲染和构建。比如 QSGGeometryNode 继承自 QSGBasicGeometryNode ,QSGBasicGeometryNode包含 QSGGeometry 和 QSGMaterial 这两个 辅助类的成员变量。
QSGGeometry
provides low-level storage for graphics primitives
QSGFlatColorMaterial
Convenient way of rendering solid colored geometry in the scene graph
QSGMaterial
Encapsulates rendering state for a shader program
QSGMaterialShader
Represents an OpenGL shader program in the renderer
QSGMaterialType
Used as a unique type token in combination with QSGMaterial
QSGOpaqueTextureMaterial
Convenient way of rendering textured geometry in the scene graph
QSGSimpleMaterial
Template generated class used to store the state used with a QSGSimpleMateralShader
QSGSimpleMaterialShader
Convenient way of building custom OpenGL-based materials for the scene graph
QSGTextureMaterial
Convenient way of rendering textured geometry in the scene graph
QSGVertexColorMaterial
Convenient way of rendering per-vertex colored geometry in the scene graph
所有Material 类内部都有一个OpenGL shader程序。
除了通过使用Material类来加载 shader程序外,还可以通过注册包含shader程序的槽函数给 QQuickWindow::beforeRendering() 和 QQuickWindow::afterRendering() 。从名字可以看出,这两个信号分别在渲染前和渲染后被 QQuickWindow 发出。
在Scene Graph中使用Painter
前面提到了Scene Graph和Painter是两个独立体系,Scene Graph为了考虑某些人的使用习惯,对外开放了 QQuickPaintedItem 类 ,这个类通过在内部继承一个 可以绘制的 Rectangle 来实现对 Painter的兼容。
使用起来很简单,继承QQuickPaintedItem,实现其纯虚函数 paint() ,在paint函数内部可以使用QPainter 类进行绘制。