Łukasz Przeniosło
Łukasz Przeniosło

Reputation: 2949

Proper shadow drop on rotation

I am trying to create a rotatable triangle that will always cast a shadow on its base. So far I was able to create the code for making and rotating the triangle but the shadow part is problematic. Here is my minimal code example:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0

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

    Rectangle
    {
        id: rectMain
        anchors.centerIn: parent
        width: parent.width
        height: parent.height
        color: "white"

        Canvas
        {
            anchors.fill: parent

            // set properties with default values
            property real hFactor: 1    // height factor
            property real trbase: 200
            property color strokeColor: "black"
            property color fillColor: "yellow"
            property int lineWidth: 1
            property real alpha: 1
            property real rotAngle: 0
            property real parentWidth: parent.width; // try
            property real parentHeight: parent.height;

            onStrokeColorChanged: requestPaint();
            onFillColorChanged: requestPaint();
            onLineWidthChanged: requestPaint();

            onPaint:
            {
                hFactor = Math.abs(hFactor)

                var ctx = getContext("2d") // get context to draw with
                ctx.clearRect(0, 0, width, height); // remove what is painted so far
                ctx.lineWidth = lineWidth
                ctx.strokeStyle = strokeColor
                ctx.fillStyle = fillColor
                ctx.globalAlpha = alpha

                ctx.save();
                ctx.beginPath();
                ctx.translate(parentWidth / 2, parentHeight / 2);
                ctx.rotate((Math.PI / 180) * rotAngle);
                ctx.moveTo(0, 0);

                // drawing part, first calculate height using Pythagoras equation
                var trheight = Math.sqrt(Math.pow(trbase, 2) - Math.pow(trbase / 2, 2));
                trheight = trheight * hFactor;
                var hfBase = trbase * hFactor;
                ctx.lineTo(hfBase / -2, trheight); // left arm
                ctx.lineTo(hfBase / 2, trheight); // right arm

                ctx.closePath(); // base drawn automatically
                ctx.fill();
                ctx.stroke();
                ctx.restore();
            }

            DropShadow
            {
                anchors.fill: parent
                horizontalOffset: 0
                verticalOffset: 3
                radius: 3
                samples: 7
                color: "#80000000"
                source: parent
            }
        }
    }
}

I am facing the following problems:

The parser gives me some errors about ShaderEffectSource, that recursive property has to be set, but I dont know whos property is that.

Starting M:\bitbucket\qtworkspace\build-mwe-Desktop_Qt_5_11_0_MinGW_32bit-Debug\debug\mwe.exe...
QML debugging is enabled. Only use this in a safe environment.
ShaderEffectSource: 'recursive' must be set to true when rendering recursively.
ShaderEffectSource: 'recursive' must be set to true when rendering recursively.
ShaderEffectSource: 'recursive' must be set to true when rendering recursively.
ShaderEffectSource: 'recursive' must be set to true when rendering recursively.
QObject::disconnect: No such signal QObject::screenChanged(QScreen*) in items\qquickscreen.cpp:476
M:/bitbucket/qtworkspace/build-mwe-Desktop_Qt_5_11_0_MinGW_32bit-Debug/debug/mwe.exe exited with code 0

Somewhere in the web I have found a bug report that DropShadow property source cannot accept parent but since Canvas cannot be assigned with id, I am not sure how to do it. Other than this, the shadow renders correctly for rotAngle at 0 degrees:

enter image description here

It doesn't rotate correctly after adding some angle, for example 45 degrees:

enter image description here

It seems to me that the shadow is not being rotated together with the polygon. Can this be adjusted? The last thing is: How to hide shadow behind the polygon? At the moment its interfering with it.

I am not sure either the parser error is connected or not, that's why I have added it together here.

Upvotes: 0

Views: 520

Answers (1)

JustWe
JustWe

Reputation: 4484

since Canvas cannot be assigned with id

Why Canvas can't be assigned with id?

The following code won't have that warning.

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

    Rectangle
    {
        id: rectMain
        anchors.centerIn: parent
        width: parent.width
        height: parent.height
        color: "white"

        Canvas
        {
            id: canvas
            anchors.fill: parent

            // set properties with default values
            property real hFactor: 1    // height factor
            property real trbase: 200
            property color strokeColor: "black"
            property color fillColor: "yellow"
            property int lineWidth: 1
            property real alpha: 1
            property real rotAngle: 0
            property real parentWidth: parent.width; // try
            property real parentHeight: parent.height;

            onStrokeColorChanged: requestPaint();
            onFillColorChanged: requestPaint();
            onLineWidthChanged: requestPaint();

            onPaint:
            {
                hFactor = Math.abs(hFactor)

                var ctx = getContext("2d") // get context to draw with
                ctx.clearRect(0, 0, width, height); // remove what is painted so far
                ctx.lineWidth = lineWidth
                ctx.strokeStyle = strokeColor
                ctx.fillStyle = fillColor
                ctx.globalAlpha = alpha

                ctx.save();
                ctx.beginPath();
                ctx.translate(parentWidth / 2, parentHeight / 2);
                ctx.rotate((Math.PI / 180) * rotAngle);
                ctx.moveTo(0, 0);

                // drawing part, first calculate height using Pythagoras equation
                var trheight = Math.sqrt(Math.pow(trbase, 2) - Math.pow(trbase / 2, 2));
                trheight = trheight * hFactor;
                var hfBase = trbase * hFactor;
                ctx.lineTo(hfBase / -2, trheight); // left arm
                ctx.lineTo(hfBase / 2, trheight); // right arm

                ctx.closePath(); // base drawn automatically
                ctx.fill();
                ctx.stroke();
                ctx.restore();
            }
        }

        DropShadow
        {
            anchors.fill: canvas
            horizontalOffset: 0
            verticalOffset: 3
            radius: 3
            samples: 7
            color: "#80000000"
            source: canvas
        }
    }
}

About the warning:

I believe that should not consider as a BUG. DropShadow is an Item, so if you nest with its parent, it will do like render a shadow on the shadow.

Why didn't the shadow rotated?

Because you are rotating the contents of Canvas. Even rotate the polygon, these properties won't change. Always drop the shadow vertically.

horizontalOffset: 0
verticalOffset: 3

Rotate both:

enter image description here

Item {
    anchors.fill: parent
    rotation: 30
    Canvas
    {
        id: canvas
        anchors.fill: parent

        // set properties with default values
        property real hFactor: 1    // height factor
        property real trbase: 200
        property color strokeColor: "black"
        property color fillColor: "yellow"
        property int lineWidth: 1
        property real alpha: 1
        property real parentWidth: parent.width; // try
        property real parentHeight: parent.height;

        onStrokeColorChanged: requestPaint();
        onFillColorChanged: requestPaint();
        onLineWidthChanged: requestPaint();

        onPaint:
        {
            hFactor = Math.abs(hFactor)

            var ctx = getContext("2d") // get context to draw with
            ctx.clearRect(0, 0, width, height); // remove what is painted so far
            ctx.lineWidth = lineWidth
            ctx.strokeStyle = strokeColor
            ctx.fillStyle = fillColor
            ctx.globalAlpha = alpha

            ctx.save();
            ctx.beginPath();
            ctx.translate(parentWidth / 2, parentHeight / 2);
            ctx.moveTo(0, 0);

            // drawing part, first calculate height using Pythagoras equation
            var trheight = Math.sqrt(Math.pow(trbase, 2) - Math.pow(trbase / 2, 2));
            trheight = trheight * hFactor;
            var hfBase = trbase * hFactor;
            ctx.lineTo(hfBase / -2, trheight); // left arm
            ctx.lineTo(hfBase / 2, trheight); // right arm

            ctx.closePath(); // base drawn automatically
            ctx.fill();
            ctx.stroke();
            ctx.restore();
        }
    }

    DropShadow
    {
        anchors.fill: canvas
        horizontalOffset: 0
        verticalOffset: 3
        radius: 3
        samples: 7
        color: "#80000000"
        source: canvas
    }
}

Upvotes: 1

Related Questions