2

It masks the source item with another item, so the source is visible only where the mask is opaque. How to make source visible only where the mask is transparent?

Currently it's done with a shader, but I want to replace that.

Can't invert the mask, because it consists of multiple images: the sum of individually inverted images is not the same as the inversion of the sum.

Velkan
  • 7,067
  • 6
  • 43
  • 87
  • All components in GraphicalEffects are using shaders. For sure there is no component that can do it for you - you need to make one yourself. I do not know what is the problem here. One idea that comes to my mind is manually inverting your mask in C++ and then applying it in QML but is it better than a shader? I do not think so. In the best case the difference would be slight. What is wrong with your shader? – Filip Hazubski May 30 '16 at 21:20
  • 1
    @FilipHazubski, at least it's good to get a confirmation that there is no component for that. During the code review the shader caused a suggestion to investigate further (that's what's wrong with my shader). – Velkan May 30 '16 at 23:04

2 Answers2

2

There is no component made by Qt that can do what you need. OpacityMask is closest to what you need. You can view its code here on the official repository or on your machine in this path: Qt_folder/Qt_version/Qt_kit/qml/QtGraphicalEffects/OpacityMask.qml. This way you can easily browse the source of all QtGraphicalEffects components.

Using ShaderEffect is a good choice for the task.

As GrecKo pointed out there already is an invert property in OpacityMask object. It will be available with Qt 5.7 but the code is already available in the link above. You can either wait for the update or download the component and use it in your project.

Community
  • 1
  • 1
Filip Hazubski
  • 1,668
  • 1
  • 17
  • 33
  • 2
    In the code linked (the Qt 5.7 version of `OpacityMask`) there is an `invert` property. So you could just copy the code or wait for Qt 5.7 to be released and set `invert: true`. – GrecKo May 31 '16 at 07:40
  • 1
    @GrecKo Very good advice! I have added it to my answer (I hope it is okay with you). – Filip Hazubski May 31 '16 at 07:48
1

If you like to use QML Items (Rectangle) you can use following codes:

import QtQuick 2.6

Item {
    anchors.fill: parent
    Image {
        anchors.fill: parent
        source: "http://i.imgur.com/R3yMj0y.jpg"
        fillMode: Image.PreserveAspectCrop
        focus: true
        Keys.onRightPressed: _mask.maskX += 100
        Keys.onLeftPressed: _mask.maskX -= 100
        Keys.onUpPressed: _mask.maskY -= 100
        Keys.onDownPressed: _mask.maskY += 100
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            onPositionChanged: {
                _mask.maskX = mouseX;
                _mask.maskY = mouseY;
            }
        }
    }

    Rectangle {
        id: _bk
        anchors.fill: parent
        color: "#33000000"
        visible: false
        layer.enabled: true
        layer.smooth: true
    }

    Rectangle {
        id: _mask
        anchors.fill: parent
        color: "transparent"
        visible: true
        property int maskX: 0
        property int maskY: 0
        Rectangle {
            id: circle
            width: 100; height: 100
            x: _mask.maskX-50; y: _mask.maskY-50
            radius: 50
            color: "#000"
            Behavior on x { NumberAnimation { duration: 400; easing.type: Easing.OutBack; easing.overshoot: 1.4 } }
            Behavior on y { NumberAnimation { duration: 400; easing.type: Easing.OutBack; easing.overshoot: 1.4 } }
        }
        layer.enabled: true
        layer.samplerName: "maskSource"
        layer.effect: ShaderEffect {
            property variant source: _bk
            fragmentShader: "
                varying highp vec2 qt_TexCoord0;
                uniform highp float qt_Opacity;
                uniform lowp sampler2D source;
                uniform lowp sampler2D maskSource;
                void main(void) {
                    gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
                }
            "
        }
    }
    Rectangle {
        id: _mask2
        anchors.fill: parent
        color: "transparent"
        visible: true
        Rectangle {
            id: circle2
            width: 150; height: 150
            x: _mask.maskX-75; y: _mask.maskY-75
            radius: 75
            color: "#000"
            Behavior on x { NumberAnimation { duration: 550; easing.type: Easing.OutBack; easing.overshoot: 2.4 } }
            Behavior on y { NumberAnimation { duration: 550; easing.type: Easing.OutBack; easing.overshoot: 2.4 } }
        }
        layer.enabled: true
        layer.samplerName: "maskSource"
        layer.effect: ShaderEffect {
            property variant source: _bk
            fragmentShader: "
                varying highp vec2 qt_TexCoord0;
                uniform highp float qt_Opacity;
                uniform lowp sampler2D source;
                uniform lowp sampler2D maskSource;
                void main(void) {
                    gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
                }
            "
        }
    }
    Rectangle {
        id: _mask3
        anchors.fill: parent
        color: "transparent"
        visible: true
        Rectangle {
            id: circle3
            width: 220; height: 220
            x: _mask.maskX-110; y: _mask.maskY-110
            radius: 110
            color: "#000"
            Behavior on x { NumberAnimation { duration: 650; easing.type: Easing.OutBack; easing.overshoot: 3.0 } }
            Behavior on y { NumberAnimation { duration: 650; easing.type: Easing.OutBack; easing.overshoot: 3.0 } }
        }
        layer.enabled: true
        layer.samplerName: "maskSource"
        layer.effect: ShaderEffect {
            property variant source: _bk
            fragmentShader: "
                varying highp vec2 qt_TexCoord0;
                uniform highp float qt_Opacity;
                uniform lowp sampler2D source;
                uniform lowp sampler2D maskSource;
                void main(void) {
                    gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
                }
            "
        }
    }
}

Opacity Mask using QML Item (Rectangle)

S.M.Mousavi
  • 5,013
  • 7
  • 44
  • 59