Search code examples
qtqtquick2clipscenegraphqsgclipnode

How to use QSGClipNode with custom geometry?


How to use QSGClipNode with a custom geometry?
This is a sample:

enter image description here


Solution

  • QSGClipNode

    The QSGClipNode uses its geometry to clip rendering of its children nodes.

    So to use it, you first have to create the geometry (set of vertices/triangles) representing your mask, and set it with the setGeometry method. Resources are scarce yes, here is a few examples using QSGGeometry, that you need to draw your "heart" shape:

    Then use the appendChildNode method to add the children that you want to clip in your QSGClipNode. In your case, QSGImageNode is probably the way to go, to show your image clipped.

    Other solution: OpacityMask

    Another solution, available without digging into c++ scene graph classes, is to use an OpacityMask from QtQuick.GraphicalEffect. It also applies to a QtQuickItem you would have created in C++.

    The example in Qt documentation is easy to use, just don't forget to set the visible property of both the Mask and the Source to false, the OpacityMask element itself will display the source cropped/masked.

    Here is a way to clip "children" with it (NB: untested at that time):

    clipperitem.qml

    import QtQuick 2.5
    import QtGraphicalEffects 1.0
    
    Item {
        width: 300
        height: 300
    
        // Item-based children will be mapped to this property
        default property alias clippedContent: clippedItem.children
    
        // Optional mask property to set it from outside
        property alias mask: opacityMask.mask
    
        Item {
            id: clippedItem
            anchors.fill: parent
            visible: false
        }
    
        Item {
            id: defaultMask
            // Your default mask
            visible: false
        }
    
        OpacityMask {
            id: opacityMask
            anchors.fill: clippedItem
            source: clippedItem
            mask: defaultMask
        }
    }
    

    main.qml

    ClipperItem {
        // Content here will be clipped. Non item-based elements will have
        // to be explicitly assigned to `ressources` property (i.e. Timer, etc.)
        Rectangle {
            //...
        }
        Image {
            //...
        }
    }