Qt Quick Scene Graph 小入门

544 阅读4分钟

场景图是基于矢量的图形编辑应用程序和现代计算机游戏常用的通用数据结构,它安排图形场景的逻辑和空间表示。它是图形或树结构中节点的集合。一个树节点可能有很多子节点,但只有一个父节点,父节点的效果应用于它的所有子节点,对组执行的操作会自动将其效果传播到其所有成员。 在许多程序中,关联几何变换矩阵(另请参见变换和矩阵) 在每个组级别并将这些矩阵连接在一起是处理此类操作的有效且自然的方式。例如,一个共同的特征是能够将相关的形状和对象组合成一个复合对象,然后可以像单个对象一样轻松地对其进行操作。

首先引用wiki对Scene Graph的解释,总结来说Scene Graph是一种树形结构,描述图形与图形之间的关系,改变某一个父节点,就能改变其所有的子节点。

image.png

举例鼠标点击拖动功能,所有子图属于一个用于变换的父节点,就能实现全局位置的变化。 [关于实现拖动的代码](http://t.csdn.cn/zUfXK)

sn1.gif 相较于QPainter这种传统CPU绘制方式,QSG渲染的场景可以在帧之间保留,而且其底层使用的是GPU的API比如opengl,性能会更强。关于帧之间的保存与性能提升我深有体会,因为我的工作中需要绘制用于SLAM的地图,如果我想绘制所有的点,使用QPainter是非常卡的。

节点 Node

上文提到,你的图形由节点树组成,下面是QT给出的几个预定节点。

QSGClipNode实现场景图中的裁剪功能
QSGGeometryNode用于场景图中的所有渲染内容
QSGNode场景图中所有节点的基类
QSGOpacityNode用于改变节点的不透明度
QSGTransformNode在场景图中实现转换

其中最重要的是QSGGeometryNode,通过它实现了所有需要被渲染的图形,它可以是一条线、一个矩形、一个多边形、许多不连续的矩形或复杂的 3D 图形。这里就要提到一些关于opengl的概念。

下面引用有关openGL的文章 QSG与其非常相似,基础的概念是相通的,具体请查看引用的文章,不多赘述。

图形的实现需要一个个小程序把数据变成显示到屏幕上的像素,小程序叫做着色器(Shader)。按照下图的流程,一个图形的实现就需要:

  • 顶点数据(Vertex Data) 定义顶点位置,比如三角形就需要三个点
  • 顶点着色器(Vertex Shader) 它把一个单独的顶点作为输入,顶点着色器主要的目的是把3D坐标转为另一种3D坐标
  • 图元装配(Primitive Assembly) 将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状;本节例子中是一个三角形。
  • 几何着色器(Geometry Shader) 通过预定义的顶点,实现一个完整形状的图形
  • 光栅化阶段(Rasterization Stage)
  • 片段着色器 实现高级功能,实现光照、阴影、光的颜色

image.png

那么QSG是如何实现一个图像的呢?

举例QT例程 贝塞尔曲线 首先看看在updatePaintNode函数中做了什么

入参QSGNode *oldNode再用 node = static_cast<QSGGeometryNode *>(oldNode);转换,这里对应了QSG保留了上一帧,在上一帧上进行操作的特性。

整幅图只有一个图形,就是一条线,所以只有一个节点QSGGeometryNodeQSGGeometryNodeQSGGeometryQSGFlatColorMaterial组成, QSGGeometry就像是opengl中的几何着色器,需要定义顶点和图元

//分配顶点空间
 geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), m_segmentCount);
 //设置图元
 geometry->setLineWidth(2);
 geometry->setDrawingMode(QSGGeometry::DrawLineStrip);

QSGFlatColorMaterial就像是opengl中的片段着色器,在QSG中一般被称作材质(Material)

在知道顶点和材质后,我们还要指定图元(Primitive)

geometry->setDrawingMode(QSGGeometry::DrawTriangles);

在OpenGL中,我们是希望把这些数据渲染成一系列的点?一系列的三角形?还是仅仅是一个长长的线?做出的这些提示叫做图元(Primitive),任何一个绘制指令的调用都将把图元传递给OpenGL。这是其中的几个:GL_POINTSGL_TRIANGLESGL_LINE_STRIP

对应的QT DrawingMode

QSGGeometry::DrawPoints
QSGGeometry::DrawLines
QSGGeometry::DrawLineLoop
QSGGeometry::DrawLineStrip
QSGGeometry::DrawTriangles
QSGGeometry::DrawTriangleStrip
QSGGeometry::DrawTriangleFan

使用QSG绘制三角形

image.png 在原有的Beziercurve例程中做改动,关键部分

//改变绘图方式,绘制三角形
geometry->setDrawingMode(QSGGeometry::DrawTriangles);
//三个顶点
geometry->allocate(3);
//设置顶点位置
vertices[0].set(0.5*itemSize.width(), 0.5*itemSize.height());
vertices[1].set(0* itemSize.width(), 0*itemSize.height());
vertices[2].set(0* itemSize.width(), 0.5*itemSize.height());