带有 QML 着色器的模拟速度计

问题描述 投票:0回答:1

我正在尝试使用

ShaderEffect
在 QML 中开发模拟速度计,但我未能达到预期的结果。

目标是填充着色器(红色弧形图像,称为 colorSource)在圆形参考上大约 240 度处开始,并在大约 320 度处结束。弧形图像应根据 RPM 值前进并填充圆代替针。然而,我在计算正确的开始和结束角度时遇到了困难。

meter.qml

Item {
    id: rpmFillRough

    width: 536
    height: 536
    layer.enabled: true

    anchors.centerIn: parent

    layer.effect: ShaderEffect {
        readonly property real degrees: Math.PI / 180 // used for deg -> rad translations
        readonly property var colorSource: rpmFill
        readonly property var unfilledMarksSource: rpmMarksUnfilled
        readonly property var filledMarksSource: rpmMarksFilled
        property real normalizedValue: (rpm <= 10000 ? root.rpm : 10000) / 10000

        readonly property real rotDeg: 215 + (-35 - 215) * normalizedValue

        readonly property real rotRad: rotDeg * degrees
        readonly property real startCutAngleRad: rotRad - 0.5 * degrees
        readonly property real endCutAngleRad: (215 - 360 + 10) * degrees
        readonly property real textureSizePx: rpmFill.width
        readonly property real startCutRadius: 0.40
        // rotRad is negative because it's a right-handed coord system
        readonly property real s: Math.sin(-rotRad)
        readonly property real c: Math.cos(-rotRad)
        readonly property bool fillVisible: root.rpm > 1
        fragmentShader: Shader.path("tachometerShader")
    }
}

t.frag

uniform lowp sampler2D colorSource;
uniform lowp sampler2D unfilledMarksSource;
uniform lowp sampler2D filledMarksSource;
varying highp vec2 qt_TexCoord0;
uniform lowp float s;
uniform lowp float c;
uniform lowp float startCutRadius;
uniform lowp float textureSizePx;
uniform lowp float startCutAngleRad;
uniform lowp float endCutAngleRad;
uniform lowp float rotRad;
uniform bool fillVisible;

lowp float atanApprox(lowp float y, lowp float x) {
    lowp float absX = abs(x);
    lowp float absY = abs(y);
    lowp float a = min(absX, absY) / max(absX, absY);
    lowp float s = pow(a, 2.0);
    lowp float r = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a;
    if (absY > absX)
        r = 1.57079637 - r;
    if (x < 0.0)
        r = 3.14159274 - r;
    if (y < 0.0)
        r = -r;
    return r;
}

void main() {
    // background
    gl_FragColor        = texture2D(unfilledMarksSource, qt_TexCoord0);

    if (!fillVisible) {
        return;
    }

    lowp vec2 srcCoord11 = vec2(
                qt_TexCoord0.x * 2. - 1.,
                1. - qt_TexCoord0.y * 2.
                );
    //            (0,0)---+              +-----(1,1)
    //   convert    |     |   ---->      | (0,0) |
    //              +---(1,1)         (-1,-1)----+
    // From OpenGL to school math coordinates; invert Y

    // get polar coordinates of the current pixel
    lowp float curAngle = atanApprox(srcCoord11.y, srcCoord11.x);
    lowp float curRadius = sqrt(srcCoord11.x * srcCoord11.x + srcCoord11.y * srcCoord11.y) + 0.05;

    // make bottom-left quadrant compatible with all others
    if(curAngle < -2.) {
        curAngle += 1.28;
    }

    // cut out what's not needed
    if(curAngle > startCutAngleRad
            && curRadius < 1.0
            && curRadius > startCutRadius
            && fillVisible) {
        lowp mat2 rotationMatrix2x2 = mat2(c, -s,  s, c);
        lowp vec2 destCoord = srcCoord11 * rotationMatrix2x2;

        // convert to back to 0..1 system
        destCoord = vec2(
                    .5 + .5 * destCoord.x,
                    .5 - .5 * destCoord.y);

        lowp vec4 fill_color = texture2D(colorSource, destCoord);

        gl_FragColor = mix(gl_FragColor, fill_color, fill_color.a);

        lowp vec4 marks_color = texture2D(filledMarksSource, qt_TexCoord0);
        gl_FragColor = mix(gl_FragColor, marks_color, marks_color.a * fill_color.a);
    }
}

Expectation

qt qml fragment-shader
1个回答
0
投票

您可以使用两张图像来简化问题。一个来自模拟车速表背景,另一个用于车速表指针。

Image {
    source: "speed-bk.png"
    Image {
        anchors.fill: parent
        source: "speed-needle.png"
        rotation: slider.value
    }
}
Slider { id: slider; y: 400; from: -135; to: 135 }

您可以在线尝试!

© www.soinside.com 2019 - 2024. All rights reserved.