【问题标题】:Clip QML's ShaderEffect to circular shape将 QML 的 ShaderEffect 剪辑为圆形
【发布时间】:2023-03-26 11:43:01
【问题描述】:

我在 QML 中使用ShaderEffect 来获得某些项目的缩放视觉副本。 这个副本应该是可移动的和动态的(ShaderEffectSourcelive 属性设置为true)。

我的问题是我希望它在一轮 Rectangle 内,但它不会被它剪裁。 ShaderEffect 只是与其父对象重叠并且是二次的。

我编写了一个显示问题的快速 QML 示例:

import QtQuick 2.4
import QtQuick.Controls 1.3

ApplicationWindow {
    title: qsTr("Hello Shaders")
    width: 640
    height: 480
    visible: true
    color: "green"

    Rectangle {
        id: exampleRect

        property bool redState: false

        anchors.centerIn: parent
        width: parent.width / 3
        height: parent.height / 3
        color: redState ? "red" : "cyan"


        Rectangle {
            anchors.centerIn: parent
            width: parent.width / 2; height: width;
            color: "white"

            Rectangle {
                anchors.centerIn: parent
                width: parent.width / 2; height: width;
                color: "green"

                Rectangle {
                    anchors.centerIn: parent
                    width: parent.width / 2; height: width;
                    color: "yellow"
                }
            }
        }

        Timer {
            interval: 2000
            repeat: true
            running: true

            onTriggered: {
                exampleRect.redState = !exampleRect.redState
            }
        }
    }

    MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onPositionChanged: {
            shaderEffectContainer.x = mouse.x
            shaderEffectContainer.y = mouse.y
        }
    }

    Rectangle {
        id: shaderEffectContainer

        width: 100; height: width;
        radius: width / 2;
        border.width: 2

        ShaderEffectSource {
            id: source

            sourceItem: exampleRect
            visible: false
        }

        ShaderEffect {
            anchors.fill: parent

            property variant source: source

            vertexShader: "
                uniform highp mat4 qt_Matrix;
                attribute highp vec4 qt_Vertex;
                attribute highp vec2 qt_MultiTexCoord0;
                varying highp vec2 qt_TexCoord0;
                void main() {
                    qt_TexCoord0 = qt_MultiTexCoord0 * 1.5 * vec2(0.5, 0.5);
                    gl_Position = qt_Matrix * qt_Vertex;
                }"

            fragmentShader: "
                varying highp vec2 qt_TexCoord0;
                uniform sampler2D source;
                uniform lowp float qt_Opacity;
                void main() {
                    gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;
                }"
        }
    }
}

如您所见,exampleRect 被声明为圆形,但它的子级与它重叠。

我已经尝试了clip 属性的所有可能组合,并且整天都在尝试使用片段/顶点着色器来做到这一点。没有运气,你可能猜到了。 :)

【问题讨论】:

  • 一个例子,更不用说运行的例子了,这些天是如此罕见! +1

标签: qt opengl qml qt5 qtquick2


【解决方案1】:

我已经使用layers 解决了这个问题,如this answer 所示。
感谢@DenimPowell 的提示。

下面是更新的示例代码,带有循环ShaderEffect

import QtQuick 2.4
import QtQuick.Controls 1.3

ApplicationWindow {
    title: qsTr("Hello Shaders")
    width: 640
    height: 480
    visible: true
    color: "green"

    Rectangle {
        id: exampleRect

        property bool redState: false

        anchors.centerIn: parent
        width: parent.width / 3
        height: parent.height / 3
        color: redState ? "red" : "cyan"


        Rectangle {
            anchors.centerIn: parent
            width: parent.width / 2; height: width;
            color: "white"

            Rectangle {
                anchors.centerIn: parent
                width: parent.width / 2; height: width;
                color: "green"

                Rectangle {
                    anchors.centerIn: parent
                    width: parent.width / 2; height: width;
                    color: "yellow"
                }
            }
        }

        Timer {
            interval: 2000
            repeat: true
            running: true

            onTriggered: {
                exampleRect.redState = !exampleRect.redState
            }
        }
    }

    MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onPositionChanged: {
            shaderEffectContainer.x = mouse.x
            shaderEffectContainer.y = mouse.y
        }
    }

    Rectangle {
        id: shaderEffectContainer

        width: 100; height: width;

        color: "transparent"

        Rectangle {
            id: rectangleSource

            anchors.fill: parent

            ShaderEffectSource {
                id: source

                sourceItem: exampleRect
                visible: false
            }

            ShaderEffect {
                anchors.fill: parent

                property variant source: source

                vertexShader: "
                    uniform highp mat4 qt_Matrix;
                    attribute highp vec4 qt_Vertex;
                    attribute highp vec2 qt_MultiTexCoord0;
                    varying highp vec2 qt_TexCoord0;
                    void main() {
                        qt_TexCoord0 = qt_MultiTexCoord0 * 1.5 * vec2(0.5, 0.5);
                        gl_Position = qt_Matrix * qt_Vertex;
                    }"

                fragmentShader: "
                    varying highp vec2 qt_TexCoord0;
                    uniform sampler2D source;
                    uniform lowp float qt_Opacity;
                    void main() {
                        gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;
                    }"
            }
            visible: false

            layer.enabled: true
        }

        Rectangle {
            id: maskLayer
            anchors.fill: parent
            radius: parent.width / 2

            color: "red"

            border.color: "black"

            layer.enabled: true
            layer.samplerName: "maskSource"
            layer.effect: ShaderEffect {

                property var colorSource: rectangleSource
                fragmentShader: "
                    uniform lowp sampler2D colorSource;
                    uniform lowp sampler2D maskSource;
                    uniform lowp float qt_Opacity;
                    varying highp vec2 qt_TexCoord0;
                    void main() {
                        gl_FragColor =
                            texture2D(colorSource, qt_TexCoord0)
                            * texture2D(maskSource, qt_TexCoord0).a
                            * qt_Opacity;
                    }
                "
            }
        }

        // only draw border line
        Rectangle {
            anchors.fill: parent

            radius: parent.width / 2

            border.color: "black"
            border.width: 1

            color: "transparent"
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2020-09-22
    • 1970-01-01
    • 2016-05-01
    相关资源
    最近更新 更多