You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QML PieSeries遮罩中PieSlice渐变透明效果实现咨询

解决QML PieSlice边缘渐变透明的问题

嘿,我之前也遇到过类似的需求——用PieSeries做遮罩时,想让黑色切片的边缘柔和过渡,而不是生硬的边界。你尝试的LinearGradient+OpacityMask思路是对的,但可能是用法没到位,或者PieSlice本身的特性导致的。下面给你两种可行的解决方案,分别适合不同的场景:

方法1:使用ShaderEffect实现精准的边缘渐变(推荐)

这种方法通过自定义GLSL片段着色器,直接计算PieSlice边缘的透明度,能精准控制渐变的范围和效果,适合需要精细调整的场景。

代码示例

import QtQuick 2.15
import QtCharts 2.15

Item {
    width: 300
    height: 300

    // 你的圆形动图
    Image {
        id: animatedCircle
        anchors.fill: parent
        source: "your_animated_gif.gif" // 替换成你的动图路径
        fillMode: Image.PreserveAspectFit
    }

    // 遮罩用的PieSeries
    PieSeries {
        id: maskSeries
        anchors.fill: parent
        holeSize: 0 // 不需要中心孔的话设为0

        // 第一个黑色切片,带边缘渐变
        PieSlice {
            id: blackSlice1
            startAngle: 0
            angleSpan: 120
            color: "black"

            effect: ShaderEffect {
                fragmentShader: "
                    varying highp vec2 qt_TexCoord0;
                    uniform lowp float qt_Opacity;
                    uniform highp vec2 center;
                    uniform highp float startAngle;
                    uniform highp float angleSpan;
                    uniform highp float edgeSoftness;

                    void main() {
                        // 将纹理坐标转换为相对于中心的坐标
                        highp vec2 pos = qt_TexCoord0 - center;
                        // 计算当前像素的角度(弧度转角度)
                        highp float angle = atan(pos.y, pos.x) * 180.0 / 3.1415926535;
                        // 转换为0-360度范围
                        if (angle < 0.0) angle += 360.0;

                        // 计算到切片起始和结束边缘的角度距离
                        highp float distToStart = abs(angle - startAngle);
                        highp float distToEnd = abs(angle - (startAngle + angleSpan));
                        // 取最小的距离(靠近哪个边缘就用哪个)
                        highp float dist = min(distToStart, distToEnd);

                        // 根据距离计算透明度:小于edgeSoftness时线性渐变透明
                        lowp float alpha = 1.0;
                        if (dist < edgeSoftness) {
                            alpha = dist / edgeSoftness;
                        }

                        // 输出最终颜色(黑色 + 计算后的透明度)
                        gl_FragColor = vec4(0.0, 0.0, 0.0, alpha * qt_Opacity);
                    }
                "

                // 传递参数给着色器
                properties: {
                    center: Qt.point(0.5, 0.5) // PieSlice的中心(纹理坐标0-1)
                    startAngle: blackSlice1.startAngle
                    angleSpan: blackSlice1.angleSpan
                    edgeSoftness: 8.0 // 渐变宽度(单位:度),可根据需求调整
                }
            }
        }

        // 第二个黑色切片,同样添加ShaderEffect
        PieSlice {
            id: blackSlice2
            startAngle: 240
            angleSpan: 120
            color: "black"

            effect: ShaderEffect {
                fragmentShader: blackSlice1.effect.fragmentShader
                properties: {
                    center: Qt.point(0.5, 0.5)
                    startAngle: blackSlice2.startAngle
                    angleSpan: blackSlice2.angleSpan
                    edgeSoftness: 8.0
                }
            }
        }

        // 透明切片,露出下方的动图
        PieSlice {
            startAngle: 120
            angleSpan: 120
            color: "transparent"
        }
    }
}

关键说明

  • edgeSoftness参数控制渐变的宽度,数值越大,边缘过渡越柔和。
  • 着色器会自动计算每个像素到切片边缘的角度距离,然后线性调整透明度,确保边缘自然过渡。

方法2:叠加渐变PieSlice(无需写Shader)

如果你不熟悉GLSL,可以用叠加PieSlice的方式实现渐变效果——在黑色切片上叠加一个角度稍大的渐变切片,让边缘呈现透明过渡。

代码示例

import QtQuick 2.15
import QtCharts 2.15

Item {
    width: 300
    height: 300

    Image {
        id: animatedCircle
        anchors.fill: parent
        source: "your_animated_gif.gif"
        fillMode: Image.PreserveAspectFit
    }

    PieSeries {
        id: maskSeries
        anchors.fill: parent
        holeSize: 0

        // 基础黑色切片
        PieSlice {
            id: baseSlice1
            startAngle: 0
            angleSpan: 120
            color: "black"
        }

        // 叠加的渐变切片(用于边缘弱化)
        PieSlice {
            startAngle: baseSlice1.startAngle - 5 // 角度比基础切片大5度
            angleSpan: baseSlice1.angleSpan + 10
            brush: LinearGradient {
                // 渐变方向指向切片内部(根据切片角度计算)
                start: Qt.point(Math.cos((baseSlice1.startAngle + baseSlice1.angleSpan - 90) * Math.PI/180), 
                                Math.sin((baseSlice1.startAngle + baseSlice1.angleSpan - 90) * Math.PI/180))
                end: Qt.point(0.5, 0.5)
                stops: [
                    GradientStop { position: 0.0; color: "transparent" },
                    GradientStop { position: 0.1; color: "black" }
                ]
            }
            opacity: 0.9
        }

        // 第二个基础黑色切片
        PieSlice {
            id: baseSlice2
            startAngle: 240
            angleSpan: 120
            color: "black"
        }

        // 第二个渐变叠加切片
        PieSlice {
            startAngle: baseSlice2.startAngle -5
            angleSpan: baseSlice2.angleSpan +10
            brush: LinearGradient {
                start: Qt.point(Math.cos((baseSlice2.startAngle + baseSlice2.angleSpan -90)*Math.PI/180), 
                                Math.sin((baseSlice2.startAngle + baseSlice2.angleSpan -90)*Math.PI/180))
                end: Qt.point(0.5,0.5)
                stops: [
                    GradientStop { position:0.0; color:"transparent" },
                    GradientStop { position:0.1; color:"black" }
                ]
            }
            opacity:0.9
        }

        // 透明切片
        PieSlice {
            startAngle: 120
            angleSpan: 120
            color: "transparent"
        }
    }
}

关键说明

  • 叠加的切片角度比基础切片大10度(左右各扩展5度),确保覆盖基础切片的边缘。
  • LinearGradient的start点通过三角函数计算,指向切片的外部边缘,这样渐变会从外部的透明过渡到内部的黑色,实现边缘柔和效果。

为什么之前的LinearGradient+OpacityMask没成功?

PieSlice本身是一个基于路径的形状,直接给它应用OpacityMask时,需要确保mask的坐标系和PieSlice的坐标系对齐,而且OpacityMask的source和mask顺序要正确——通常是把PieSlice作为source,渐变作为mask,但PieSlice的裁剪特性可能导致渐变无法正确作用到边缘。上面的两种方法避开了这个问题,直接针对PieSlice的填充效果做调整。

内容的提问来源于stack exchange,提问作者Cosmonaut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:43:56