本文介绍了使用 QSGImageNode 渲染非平滑 QImage 的一部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试渲染图块集中的单个图块.比如我想在下面的tileset中显示灰色的tile:

I'm trying to render individual tiles from a tileset. For example, I want to display the grey tile in the tileset below:

在实际用例中,这些将是例如游戏中的水、草等瓷砖.渲染这些图块有一些要求:

In the real use case, these would be e.g. water, grass, etc. tiles in a game. There are some requirements for rendering these tiles:

  • 它们是 32x32 像素,将全屏呈现,因此性能很重要.
  • 它们不应平滑缩放时.

据我所知,没有一个内置的 Qt Quick 类型满足这些要求(渲染未平滑的图像部分).我试过 QQuickPaintedItem 和各种 QPainter 渲染提示(比如SmoothPixmapTransform设置为false)没有成功;放大时图像模糊".AnimatedSprite 支持渲染部分一个图像,但没有禁用平滑的 API.

None of the built-in Qt Quick types meet these requirements (rendering a section of an image that's not smoothed), as far as I can tell. I've tried QQuickPaintedItem with various QPainter render hints (such as SmoothPixmapTransform set to false) without success; the image is "blurry" when upscaled. AnimatedSprite supports rendering sections of an image, but has no API to disable smoothing.

我的想法是使用场景图 API 实现自定义 QQuickItem.

My idea was to implement a custom QQuickItem using the scene graph API.

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QQuickWindow>
#include <QSGImageNode>

static QImage image;
static const int tileSize = 32;
static const int tilesetSize = 8;

class Tile : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged)

public:
    Tile() :
        mIndex(-1) {
        setWidth(tileSize);
        setHeight(tileSize);

        setFlag(QQuickItem::ItemHasContents);
    }

    QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
    {
        if (!oldNode) {
            oldNode = window()->createImageNode();
        }

        if (mIndex == -1)
            return oldNode;

        if (image.isNull()) {
            image = QImage("C:/tileset.png");
            if (image.isNull())
                return oldNode;
        }

        QSGTexture *texture = window()->createTextureFromImage(image);
        qDebug() << "textureSize:" << texture->textureSize();
        if (!texture)
            return oldNode;

        QSGImageNode *imageNode = static_cast<QSGImageNode*>(oldNode);
//        imageNode->setOwnsTexture(true);
        imageNode->setTexture(texture);
        qDebug() << "source rect:" << (mIndex % tileSize) * tileSize << (mIndex / tileSize) * tileSize << tileSize << tileSize;
        imageNode->setSourceRect((mIndex % tileSize) * tileSize, (mIndex / tileSize) * tileSize, tileSize, tileSize);

        return oldNode;

    }

    int index() const {
        return mIndex;
    }

    void setIndex(int index) {
        if (index == mIndex)
            return;

        mIndex = index;
        emit indexChanged();
    }

signals:
    void indexChanged();

private:
    int mIndex;
};

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<Tile>("App", 1, 0, "Tile");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

#include "main.moc"

main.qml:

import QtQuick 2.9
import QtQuick.Controls 2.2

import App 1.0

ApplicationWindow {
    id: window
    width: 800
    height: 800
    visible: true

    Slider {
        id: slider
        from: 1
        to: 10
    }

    Tile {
        scale: slider.value
        index: 1
        anchors.centerIn: parent

        Rectangle {
            anchors.fill: parent
            color: "transparent"
            border.color: "darkorange"
        }
    }
}

此应用程序的输出看起来不错,但矩形内没有渲染任何内容:

The output from this application looks fine, but nothing is rendered within the rectangle:

textureSize: QSize(256, 256)
source rect: 32 0 32 32

最小文档来看,我的实现(就我如何创建节点)似乎没问题.我哪里出错了?

Judging from the minimal docs, my implementation (in terms of how I create nodes) seems OK. Where am I going wrong?

推荐答案

聚会晚了一年,但我遇到了和你一样的问题.为了其他任何试图对 QQuickItem 进行子类化并遇到此线程的人,文档中有一个关于 updatePaintNode 的小块:

A year late to the party, but I was running into the same problem as you. For the sake of anyone else who is trying to subclass a QQuickItem and has come across this thread, there's a little nugget that's in the documentation in regards to updatePaintNode:

该函数作为 QQuickItem::update() 的结果被调用,如果用户在项目上设置了 QQuickItem::ItemHasContents 标志.

当我设置那个标志时,一切都呈现了.

When I set that flag, everything rendered.

我认为自己是一个注重细节的人...

And I considered myself a detail-oriented person...

在 OP 指出他们已经设置了 ItemHasContents 标志之后,我再次查看了代码,发现虽然 OP 在节点上设置了 sourceRect,OP 没有设置节点的 rect,这确实是 OP 遇到的问题.

After the OP pointed out they had already set the ItemHasContents flag, I looked at the code again and saw that while the OP had set the sourceRect on the node, the OP hadn't set the rect of the node, and that indeed was the problem the OP was running into.

这篇关于使用 QSGImageNode 渲染非平滑 QImage 的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 02:24