叫场景树更合适,本质不是图。QML场景中的Qt Quick项目将填充QSGNode实例树。
场景图是Qt Quick 2.0引入的,建立在要绘制的内容是已知的基础上。所有QML项目均使用场景图进行渲染,场景图的默认实现是与OpenGL紧密相关的低级高性能渲染堆栈。
qt的场景图和osg的场景图的组织上有些类似,都是不同节点通过一定关系构建的,但是osg的场景节点更多些,并且还关联了渲染状态。在渲染方面,qt是直接对场景图进行渲染,osg是将场景图转换为渲染树再进行渲染(避免渲染状态的频繁切换)。
qt的场景图是根据界面元素的位置、透明等信息构建出来的,而osg的场景图是直接利用节点构建出来的。也就是用户不直接参与qt场景图的构建,但是直接参与osg场景图的构建。
例如,假设用户界面包含十个项目的列表,其中每个项目都有背景色,图标和文本。使用传统的绘图技术,这将导致30次绘图调用和类似数量的状态更改。另一方面,场景图可以重组原始图元以进行渲染,以便在一次调用中绘制所有背景,然后绘制所有图标,然后绘制所有文本,从而将绘制调用的总数减少到仅3个。批处理和状态更改减少这样可以大大提高某些硬件的性能。
场景图由QQuickWindow类管理和呈现,自定义Item类型可以通过调用QQuickItem :: updatePaintNode()将其图形基元添加到场景图中。
场景图是Item场景的图形表示,它是一个独立的结构,其中包含足以渲染所有项目的信息。设置完成后,就可以独立于项目状态对其进行操作和渲染。在许多平台上,场景图形甚至会在GUI线程准备下一帧状态时在专用渲染线程上进行渲染。
场景图的结构
场景图由许多预定义的节点类型组成,每种类型都有专门的用途。尽管我们将其称为场景图,但更精确的定义是节点树。该树是根据QML场景中的QQuickItem类型构建的,然后在内部由渲染该场景的渲染器处理该场景。节点本身不包含任何活动的绘图代码或虚拟paint()函数。
即使节点树主要由现有的Qt Quick QML类型在内部构建,用户也可以添加具有自己内容的完整子树,包括表示3D模型的子树。
节点
对于用户而言,最重要的节点是QSGGeometryNode。它用于通过定义其几何形状和材质来定义自定义图形。使用QSGGeometry定义几何形状,并描述图形图元的形状或网格。它可以是直线,矩形,多边形,许多不连续的矩形或复杂的3D网格。该材质定义如何填充此形状的像素。
一个节点可以有任意数量的子节点,并且将渲染几何节点,以便它们以子顺序出现,并且父级位于其子级之后。
常见的节点有:
在场景图中实现裁剪功能的节点 | |
用于场景图中的所有渲染内容的节点 | |
场景图中所有节点的基类的节点 | |
用于更改节点的不透明度的节点 | |
在场景图中实现变换的节点 |
|
表示一组针对场景所使用的图形API的自定义渲染命令。 |
通过子类QQuickItem :: updatePaintNode()并设置QQuickItem :: ItemHasContents标志,将自定义节点添加到场景图。
至关重要的是,本机图形(OpenGL,Vulkan,Metal等)操作以及与场景图的交互必须专门在渲染线程上进行,主要是在updatePaintNode()调用期间进行。经验法则是仅在QQuickItem :: updatePaintNode()函数内使用带有“ QSG”前缀的类。
处理过程
节点具有虚拟QSGNode :: preprocess()函数,该函数将在呈现场景图之前被调用,主要用于处理节点要渲染的内容。节点子类可以设置标志QSGNode :: UsePreprocess并重写QSGNode :: preprocess()函数以对其节点进行最终准备。例如,将贝塞尔曲线划分为当前比例因子的正确细节级别或更新纹理的一部分。
节点的所有权
节点的所有权由创建者或场景图通过设置标志QSGNode :: OwnedByParent明确完成。通常,将所有权分配给场景图通常是可取的,因为这样可以简化场景图位于GUI线程之外时的清理操作。