Search code examples
qtqmlshader

QML Item cliping shadow ShaderEffect


I'm trying to add shadow to my component using the ShaderEffect, and the problem is that the parent item clips the shader effect. Previously I used Qt Graphical Effects, but now I am using QT6, where this component is removed.

Currently I'm using shaders from ShaderEffects example.

Here is my code:

import QtQuick

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Item{
        anchors.centerIn: parent
        height: parent.height * 0.6
        width:  parent.width * 0.9
        Rectangle{
            id: mrect
            anchors.fill: parent
            radius: height * 0.2
            color: "yellow"
            visible: !shadow.visible
        }

        ShaderEffectSource{
            id: theSource
            sourceItem: mrect
        }

        ShaderEffect {
            id: shadow
            width: mrect.width
            height: mrect.height
            anchors.centerIn: parent
            property variant source: theSource
            property variant shadow: ShaderEffectSource {
                sourceItem: ShaderEffect {
                    width: mrect.width
                    height: mrect.height
                    property variant delta: Qt.size(0.0, 1.0 / height)
                    property variant source: ShaderEffectSource {
                        sourceItem: ShaderEffect {
                            width: mrect.width * 1.5
                            height: mrect.height * 1.5
                            property variant delta: Qt.size(1.0 / width, 0.0)
                            property variant source: theSource
                            fragmentShader: "shaders/blur.frag.qsb"
                        }
                    }
                    fragmentShader: "shaders/blur.frag.qsb"
                }
            }
            property real angle: 0.5
            property variant delta: Qt.size(15 / width, 15 / height)
            property real darkness: 0.2
            fragmentShader: "shaders/shadow.frag.qsb"
        }
    }
}

I read Qt documentation for this types but couldn't find any helpful information to solve my problem. But this doesn't make sense to me because shaders would be useless for dropping shadows in this case.


Solution

  • You need to give the sourceItem of the ShaderEffectSource a padding depending on how big the offset of your shadow will get. The issue is that the sourceItem is used to pick the color from and also draw on top of it.

    import QtQuick
    
    Window {
        width: 640
        height: 480
        visible: true
        title: qsTr("Hello World")
    
        ShaderEffectSource {
            id: shaderEffectSource
            sourceItem: item
        }
    
        Row {
            anchors.centerIn: parent
            spacing: 40
    
            Item {
                id: item
                width: 300
                height: 300
    
                Rectangle {
                    width: 200
                    height: 200
                    anchors.centerIn: parent
                    color: "salmon"
                }
            }
    
            ShaderEffect {
                width: 300
                height: 300
                property variant source: shaderEffectSource
                property variant shadow: ShaderEffectSource {
                    sourceItem: ShaderEffect {
                        width: item.width
                        height: item.height
                        property variant delta: Qt.size(0.0, 1.0 / height)
                        property variant source: ShaderEffectSource {
                            sourceItem: ShaderEffect {
                                width: item.width
                                height: item.height
                                property variant delta: Qt.size(1.0 / width, 0.0)
                                property variant source: shaderEffectSource
                                fragmentShader: "shaders/blur.frag.qsb"
                            }
                        }
                        fragmentShader: "shaders/blur.frag.qsb"
                    }
                }
                property real angle: 0.5
                property variant offset: Qt.point(15.0 * Math.cos(angle), 15.0 * Math.sin(angle))
                property variant delta: Qt.size(offset.x / width, offset.y / height)
                property real darkness: 0.2
                fragmentShader: "shaders/shadow.frag.qsb"
            }
        }
    }
    

    enter image description here