Qt5.12 C++ Как динамически загружать QPIxmap в качестве текстуры в QML 3DScene?

Чтобы динамически загрузить QPixmap в качестве текстуры в QML 3DScene в Qt 5.12, вам понадобится создать собственный производный класс от QQuickItem и использовать его в качестве основы для вашей сцены 3D.

Вот шаги, которые помогут вам реализовать эту функциональность:

1. Создайте новый класс, производный от QQuickItem. Давайте назовем его Custom3DItem. В этом классе вы будете определять специфическую логику для работы с QPixmap.

#include <QQuickItem>
#include <QPainter>

class Custom3DItem : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QPixmap texture READ texture WRITE setTexture NOTIFY textureChanged)

public:
    Custom3DItem(QQuickItem *parent = nullptr);

    QPixmap texture() const;
    void setTexture(const QPixmap &texture);

signals:
    void textureChanged();

protected:
    QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override;

private:
    QPixmap m_texture;
};

2. В реализации Custom3DItem определите свойство texture, которое представляет собой QPixmap, и определите getter и setter для него.

Custom3DItem::Custom3DItem(QQuickItem *parent)
    : QQuickItem(parent)
{
    setFlag(ItemHasContents, true);
}

QPixmap Custom3DItem::texture() const
{
    return m_texture;
}

void Custom3DItem::setTexture(const QPixmap &texture)
{
    if (m_texture == texture)
        return;

    m_texture = texture;
    emit textureChanged();
    update();
}

3. Переопределите метод updatePaintNode для создания соответствующего узла рендеринга QSGNode внутри вашего Custom3DItem.

QSGNode *Custom3DItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QSGGeometryNode *node = nullptr;
    QSGTexture *texture = nullptr;

    if (!m_texture.isNull()) {
        if (!oldNode) {
            node = new QSGGeometryNode;
            QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
            geometry->setDrawingMode(QSGGeometry::DrawTriangleStrip);
            node->setGeometry(geometry);

            QSGSimpleMaterial<State> *material = new QSGSimpleMaterial<State>;
            material->setFlag(QSGMaterial::Blending, true);
            material->setShaderProgram(ShaderProgram::instance());
            material->state()->texture = textureProvider()->bindTexture(m_texture);
            node->setMaterial(material);

            QSGOpacityNode *opacityNode = new QSGOpacityNode;
            opacityNode->setOpacity(opacity());
            opacityNode->setChildNode(node);

            node = opacityNode;
        } else {
            node = static_cast<QSGGeometryNode *>(oldNode);
            texture = static_cast<QSGSimpleMaterial<State> *>(node->material())->state()->texture;
            textureProvider()->updateTexture(texture, m_texture);
            node->markDirty(QSGNode::DirtyEverything);
        }
    }

    return node;
}

4. В QML-интерфейсе используйте ваш класс Custom3DItem в качестве основы для QML 3DScene.

import Qt3D.Core 2.0
import Qt3D.Render 2.0
import QtQuick 2.12
import QtQuick.Controls 2.12

Custom3DItem {
    id: customItem
    texture: textureImage.source

    // ... остальные опции и свойства для настройки вашей сцены 3D ...

    Image {
        id: textureImage
        source: "..."
        visible: false
    }
}

5. Теперь из свойства texture в вашем Custom3DItem вы можете привязать QPixmap, чтобы задать текстуру вашей сцене 3D из кода C++.

QQuickView view;
Custom3DItem customItem;

QPixmap texture("path/to/your/image.png");
customItem.setTexture(texture);

// Передайте customItem в QML для отображения

view.setSource(QUrl("main.qml"));
view.show();

Теперь при изменении свойства texture в коде C++, ваша 3D-сцена будет автоматически обновляться и отображать новую текстуру из QPixmap.