带有 QML Shadder 的模拟速度计

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

我正在尝试使用着色器效果在 QML 中开发模拟速度计,但无法达到预期结果。 填充着色器(红色弧形图像,称为 colorSource)的目标是从圆形参考上大约 240 度开始,到大约 320 度结束。弧形图像应根据 RPM 值前进并填充圆代替针。然而,我在计算正确的起始角度和结束角度时遇到了困难。

米.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: -120; to: 120 }

您可以在线尝试!

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