1

我尝试按照 QT 的在线文档(QtQuick Scenegraph CustomMaterial Example)给出的教程进行操作,但是当我调试我的程序时,该对象没有显示,看起来是透明的。但是,当我尝试用 替换我的自定义着色器类QSGFlatColorMaterial并设置颜色时,该对象确实显示没有任何问题。我使用示例 git repo 中的示例代码仔细检查了本教程的实现。

这是我有问题的代码

/* MapDisplay Class */

MapDisplay::MapDisplay(QQuickItem* parent) : QQuickItem(parent) {
  this->setFlag(ItemHasContents, true);
};

QSGNode* MapDisplay::updatePaintNode(QSGNode* old, UpdatePaintNodeData*) {
  auto* node = static_cast<MapNode*>(old);

  if (!node) {
    node = new MapNode();
  }
  if (this->flag_geo_changed) {
    node->ChangeRectBounds(this->boundingRect());
    this->flag_geo_changed = false;
  }
  const QRectF rect = this->boundingRect();
  auto* vertices = node->geometry()->vertexDataAsPoint2D();
  vertices[0].set(rect.bottomLeft().x(), 1);
  vertices[1].set(200, 0);
  vertices[2].set(0, 200);
  vertices[3].set(200, 200);
  node->markDirty(QSGNode::DirtyGeometry);
  return node;
}

void MapDisplay::geometryChange(const QRectF& new_geo, const QRectF& old_geo) {
  this->flag_geo_changed = false;
  this->update();
  QQuickItem::geometryChange(new_geo, old_geo);
}

/* MapShader Class */

MapShader::MapShader() {
  this->setShaderFileName(VertexStage, ":/geo/shader/map.vert.qsb");
  this->setShaderFileName(FragmentStage, ":/geo/shader/map.frag.qsb");
};

/* MapMaterial Class */

MapMaterial::MapMaterial(){};
MapMaterial::~MapMaterial(){};
QSGMaterialType* MapMaterial::type() const {
  static QSGMaterialType type;
  return &type;
}

int MapMaterial::compare(const QSGMaterial* o) const {
  Q_ASSERT(o && this->type() == o->type());
  const auto* other = static_cast<const MapMaterial*>(o);
  return other == this ? 0 : 1;
}

QSGMaterialShader* MapMaterial::createShader(
    QSGRendererInterface::RenderMode) const {
  return new MapShader();
}

/* MapNode Class */

MapNode::MapNode() {
  // Material
  auto* mat = new MapMaterial();
  this->setMaterial(mat);
  this->setFlag(QSGGeometryNode::OwnsMaterial, true);
  // Geometry
  auto* geo = get_geo_data::GetRectShape();
  this->setGeometry(geo);
  this->setFlag(QSGGeometryNode::OwnsGeometry, true);
}

void MapNode::ChangeRectBounds(const QRectF& bounds) {
  QSGGeometry::updateTexturedRectGeometry(this->geometry(), bounds,
                                          QRectF(0, 0, 0, 0));
  this->markDirty(QSGNode::DirtyGeometry);
}

这是我与customitem.cpp交叉检查的示例代码的链接

这也是我的着色器,

#version 460
// map.vert

layout(location = 0) in vec4 vertex_object;
layout(location = 1) in vec2 atex_coord;
layout(location = 0) out vec2 vtex_coord; 

void main() {
  gl_Position = vertex_object;
  vtex_coord = atex_coord;
}
#version 460

// map.frag
layout(location = 0) out vec4 frag_color;

void main() {
  frag_color = vec4(0.0, 1.0, 0.0, 1.0);
}

这里还有一些截图:

如果我使用QSGFlatColorMaterial

如果我使用我的自定义材质和着色器

4

1 回答 1

0

好的,所以在通过示例 repo 进行刺激之后,我没有将vertex_objectvert shader 中的 与对象的矩阵相乘。

因此,在将文档中的方法和 glsl 代码实现到我的之后,我让着色器正确显示。原来我没有正确设置着色器位置

map.cpp

bool MapShader::updateUniformData(RenderState& state, QSGMaterial* new_material,
                                  QSGMaterial* old_material) {
  bool changed = false;
  QByteArray* buf = state.uniformData();
  Q_ASSERT(buf->size() >= 64);

  if (state.isMatrixDirty()) {
    const QMatrix4x4 m = state.combinedMatrix();
    std::memcpy(buf->data(), m.constData(), 64);
    changed = true;
  }
  auto* cus_masterial = static_cast<MapMaterial*>(new_material);
  if (old_material != new_material || cus_masterial->uniform.dirty) {
    cus_masterial->uniform.dirty = false;
    changed = true;
  }
  return changed;
}

map.vert

#version 460

layout(location = 0) in vec4 vertex_object;
layout(location = 1) in vec2 atex_coord;
layout(location = 0) out vec2 vtex_coord; 

layout(std140, binding=0) uniform buf {
  mat4 qt_matrix; // offset 0
} ubuf;

void main() {
  gl_Position = ubuf.qt_matrix /* Very important */ * vertex_object;
  vtex_coord = atex_coord;
}
于 2021-08-14T21:44:20.273 回答