我想使用Qt场景图绘制网格。我有几天没有研究成功。请帮助我,谢谢!
问题是:
我遵循了代码,发现Qt在renderer->setViewportRect(rect)
中调用了QQuickWindowPrivate::renderSceneGraph()
;
但是场景图使用整个窗口而不是自定义QQuickItem对象作为绘制区域。
我重新计算了着色器矩阵,但是没有用。我觉得这很丑
// grid_item.h
class GridItem : public QQuickItem
{
Q_OBJECT
public:
explicit GridItem(QQuickItem *parent = nullptr);
protected:
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) Q_DECL_OVERRIDE;
};
// grid_item.cpp
GridItem::GridItem(QQuickItem *parent) : QQuickItem (parent)
{
setFlag(ItemHasContents, true);
}
QSGNode *GridItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
QRectF rect = boundingRect();
if (rect.isEmpty()) {
delete oldNode;
return nullptr;
}
QSGGeometryNode *node = nullptr;
QSGGeometry *geometry = nullptr;
GridItemMaterial *material = nullptr;
if(!oldNode)
{
node = new QSGGeometryNode;
node->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial, true);
geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0);
geometry->setDrawingMode(QSGGeometry::DrawLines);
node->setGeometry(geometry);
material = new GridItemMaterial;
material->setFlag(QSGMaterial::RequiresDeterminant, true);
node->setMaterial(material);
}
else
{
node = static_cast<QSGGeometryNode *>(oldNode);
geometry = node->geometry();
material = static_cast<GridItemMaterial *>(node->material());
}
int m_xAxisSegment {10};
int m_yAxisSegment {10};
const int totalVertices = (m_xAxisSegment+1)*2 + (m_yAxisSegment+1)*2;
if(geometry->vertexCount() != totalVertices)
{
geometry->allocate(totalVertices);
QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
for(int x=0; x<=m_xAxisSegment; x++)
{
float xPos = 1.0f*x/m_xAxisSegment;
(*vertices++).set(xPos, 0.0f);
(*vertices++).set(xPos, 1.0f);
}
for(int y=0; y<=m_yAxisSegment; y++)
{
float yPos = 1.0f*y/m_yAxisSegment;
(*vertices++).set(0.0f, yPos);
(*vertices++).set(1.0f, yPos);
}
node->markDirty(QSGNode::DirtyGeometry);
}
// calculate matrix for shader
ConvertParameter param;
param.windowWidth = 640;
param.windowHeight = 480;
param.contentX = 100;
param.contentY = 100;
param.contentWidth = 200;
param.contentHeight = 200;
param.glX = 0;
param.glY = 0;
param.glWidth = 1.0f;
param.glHeight = 1.0f;
material->m_convertParameter = param;
return node;
}
// grid_item_material.h
class GridItemMaterial : public QSGMaterial
{
public:
QSGMaterialType *type() const Q_DECL_OVERRIDE;
QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
ConvertParameter m_convertParameter;
};
// grid_item_material.cpp
QSGMaterialType *GridItemMaterial::type() const
{
static QSGMaterialType type;
return &type;
}
QSGMaterialShader *GridItemMaterial::createShader() const
{
return new GridItemMaterialShader;
}
// grid_item_material_shader.h
class GridItemMaterialShader : public QSGMaterialShader
{
public:
GridItemMaterialShader();
const char *const *attributeNames() const Q_DECL_OVERRIDE;
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) Q_DECL_OVERRIDE;
protected:
void initialize() Q_DECL_OVERRIDE;
QMatrix4x4 getConvertMatrix(const ConvertParameter ¶m);
private:
int m_id_mvpMatrix {-1};
int m_id_gridlineColor {-1};
};
// grid_item_material_shader.cpp
GridItemMaterialShader::GridItemMaterialShader()
{
setShaderSourceFile(QOpenGLShader::Vertex, ":/shaders/gridlines.vert");
setShaderSourceFile(QOpenGLShader::Fragment, ":/shaders/gridlines.frag");
}
const char * const *GridItemMaterialShader::attributeNames() const
{
static char const *const names[] = { "Vertex", 0 };
return names;
}
void GridItemMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *)
{
GridItemMaterial *material = static_cast<GridItemMaterial *>(newMaterial);
QMatrix4x4 matrix = getConvertMatrix(material->m_convertParameter);
program()->setUniformValue(m_id_mvpMatrix, matrix);
program()->setUniformValue(m_id_gridlineColor, QColor::fromRgbF(1, 0, 0, 1));
}
void GridItemMaterialShader::initialize()
{
m_id_mvpMatrix = program()->uniformLocation("mvpMatrix");
m_id_gridlineColor = program()->uniformLocation("gridlineColor");
}
QMatrix4x4 GridItemMaterialShader::getConvertMatrix(const ConvertParameter ¶m)
{
QMatrix4x4 model1;
// convert window to (-1, -1)..(+1, +1)
model1.setToIdentity();
model1.translate(-1, -1, 0);
model1.scale(2.0f/param.windowWidth, 2.0f/param.windowHeight, 1.0f);
// left-bottom
QVector4D v3(param.contentX, param.windowHeight-param.contentY-param.contentHeight, 0, 1);
v3 = model1 * v3;
// right-top
QVector4D v4(param.contentX+param.contentWidth, param.windowHeight-param.contentY, 0, 1);
v4 = model1 * v4;
// content area should in (-1, -1)..(+1, +1)
float width = v4.x() - v3.x();
float height = v4.y() - v3.y();
QMatrix4x4 model2;
model2.setToIdentity();
model2.translate(v3.x(), v3.y(), 0);
model2.scale(width/param.glWidth, height/param.glHeight, 1);
model2.translate(-param.glX, -param.glY, 0);
return model2;
}
// grid_convert_parameter.h
struct ConvertParameter
{
int windowWidth = 640;
int windowHeight = 480;
int contentX = 100;
int contentY = 100;
int contentWidth = 200;
int contentHeight = 200;
float glX = 3;
float glY = 3;
float glWidth = 4.0f;
float glHeight = 4.0f;
};
// main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<GridItem>("io.draw", 1, 0, "GridItem");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickWindow *window = static_cast<QQuickWindow *>(engine.rootObjects().first());
QSurfaceFormat format = window->requestedFormat();
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3);
window->setFormat(format);
window->show();
return app.exec();
}
// main.qml
import QtQuick 2.9
import QtQuick.Controls 2.4
import io.draw 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
GridItem {
x: 100
y: 100
width: 200
height: 200
}
}
// gridlines.vert
#version 330 core
uniform mat4 mvpMatrix;
layout(location = 0) in vec2 Vertex;
void main(void)
{
gl_Position = mvpMatrix * vec4(Vertex, 0.0, 1.0);
}
// gridlines.frag
#version 330 core
uniform vec4 gridlineColor;
layout(location = 0) out vec4 fragColor;
void main(void)
{
fragColor = gridlineColor;
}
我还基于Qt OpenGL演示进行了简单的更改。
class OpenGLWindow : public QWindow, protected QOpenGLFunctions_3_3_Core
除了将结果直接输出到整个窗口外,几乎做同样的事情(但这不是我想要的)
另一个区别是变换矩阵已更改:
QMatrix4x4 model, view, projection;
projection.ortho(0, 1, 0, 1, -10, 10);
m_program->setUniformValue(m_matrixUniform, projection*view*model);
它正常工作...
因为它涉及OpenGL和Qt场景图,所以我不知道出了什么问题。