Better_Software_Header_MobileBetter_Software_Header_Web

Find what you need - explore our website and developer resources

Efficient Custom Shapes in QtQuick : Shaders

struct SectorMaterialState
{
    QColor startInnerColor, startOuterColor,
        endInnerColor, endOuterColor, borderColor;
    float startAngleRad, spanAngleRad, borderWidth, innerRadius, outerRadius;

    int compareColor(const QColor& c1, const QColor& c2) const
    {
        const uint rgb = c1.rgba();
        const uint otherRgb = c2.rgba();
        return (rgb == otherRgb) ? 0 : ((rgb < otherRgb) ? -1: 1);
    }

    int compareFloat(const float& c1, const float& c2) const
    {
        return qFuzzyCompare(c1,c2) ? 0 : (c1 < c2) ? -1 : 1;
    }

    int compare(const SectorMaterialState *other) const
    {
        int r;
        if ((r = compareFloat(startAngleRad, other->startAngleRad)) != 0)
            return r;
        if ((r = compareFloat(spanAngleRad, other->spanAngleRad)) != 0)
            return r;
        if ((r = compareFloat(borderWidth, other->borderWidth)) != 0)
            return r;
        if ((r = compareFloat(innerRadius, other->innerRadius)) != 0)
            return r;
        if ((r = compareFloat(outerRadius, other->outerRadius)) != 0)
            return r;

        if ((r = compareColor(startInnerColor, other->startInnerColor)) != 0)
            return r;
        if ((r = compareColor(startOuterColor, other->startOuterColor)) != 0)
            return r;
        if ((r = compareColor(endInnerColor, other->endInnerColor)) != 0)
            return r;
        if ((r = compareColor(borderColor, other->borderColor)) != 0)
            return r;
        return compareColor(endOuterColor, other->endOuterColor);
    }
};

Four sample fragments in our shader

uniform lowp float qt_Opacity;

uniform lowp vec4 startInnerColor;
uniform lowp vec4 startOuterColor;
uniform lowp vec4 endInnerColor;
uniform lowp vec4 endOuterColor;
uniform lowp float startAngleRad;
uniform lowp float spanAngleRad;
uniform lowp float innerRadius;
uniform lowp float outerRadius;
uniform lowp float borderWidth;
uniform lowp vec4 borderColor;
const lowp float aaWidth = 0.1;

varying lowp vec2 vpos;

void main()
{
            float theta = atan(vpos.y, vpos.x);
            float t = length(vpos);

            // are we between the inner and outer radius? With some blending at the edge based on AA width
            float baseOpacity = smoothstep(innerRadius - aaWidth, innerRadius + aaWidth, t) *
                (1.0 - smoothstep(outerRadius - aaWidth, outerRadius + aaWidth, t));

            // discard if we're outside the area
            if (baseOpacity &amp;lt; 0.05) { discard; }

            // border color handling : are within a borderWidth of either edge? Again compute an opacity
            // based on the distance and the AA width.
            float borderOpacity =
               (1.0 - smoothstep(innerRadius + borderWidth - aaWidth, innerRadius + borderWidth + aaWidth, t)) +
               smoothstep(outerRadius - borderWidth - aaWidth, outerRadius - borderWidth + aaWidth, t);

            // radial gradient: compute our t parameter which 0.0 at the inner radius and 1.0 at the outer
            float tNorm = (t - innerRadius) / (outerRadius - innerRadius);

            // gradient along the sector: compute S parameter which is 0.0 at startAngleRad, and 1.0
            // at the ending angle. Use mod() to handle wrapping
            float s = mod(theta - startAngleRad, 6.28318) / spanAngleRad;

            // mix our four gradient colors together
            vec4 sc = mix(startInnerColor, startOuterColor, tNorm);
            vec4 ec = mix(endInnerColor, endOuterColor, tNorm);
            vec4 fillColor = mix(sc, ec, s);

            // finally mix in our border based on its opacity
            vec4 srcColor = mix(fillColor, borderColor, borderOpacity);
            gl_FragColor =  srcColor * baseOpacity * qt_Opacity;
}

About KDAB


1 Comment

25 - May - 2022

S.M.Mousavi

JamesTurner

James Turner

Senior Software Engineer & Teamlead