QML Circular Gauge Styling - Needle trailing colour/glow
-
ShaderEffect is made for this sort of bling
I got this:
from this:
import QtQuick 2.2 Rectangle { id: main width: 512 height: 512 color: 'black' // Put some text in the background just to check opacity Text { x: main.width/6.0-0.5*contentWidth y: main.height/2.0-0.5*contentHeight text: '30' color: 'white' } Text { x: main.width/2.0-0.5*contentWidth y: main.height/6.0-0.5*contentHeight text: '60' color: 'white' } Text { x: 5.0*main.width/6.0-0.5*contentWidth y: main.height/2.0-0.5*contentHeight text: '90' color: 'white' } // Shader effect to provide gradient-based gauge ShaderEffect { id: gauge anchors.fill: parent opacity: 0.75 // Making it totally opaque on leading edge obscures the number! // Angles measured clockwise from up, in range -pi to pi property real angleBase: -pi*0.75 property real angle readonly property real pi: 3.1415926535897932384626433832795 vertexShader: " uniform highp mat4 qt_Matrix; attribute highp vec4 qt_Vertex; attribute highp vec2 qt_MultiTexCoord0; varying highp vec2 coord; void main() { coord = qt_MultiTexCoord0; gl_Position = qt_Matrix * qt_Vertex; }" fragmentShader: " uniform lowp float qt_Opacity; uniform highp float angleBase; uniform highp float angle; varying highp vec2 coord; void main() { gl_FragColor = vec4(0.0,0.0,0.0,0.0); highp vec2 d=2.0*coord-vec2(1.0,1.0); highp float r=length(d); if (0.25<=r && r<=0.75) { highp float a=atan2(d.x,-d.y); if (angleBase<=a && a<=angle) { highp float p=(a-angleBase)/(angle-angleBase); gl_FragColor = vec4(0.0,0.0,p,p) * qt_Opacity; } } }" } // Animate the gauge position SequentialAnimation { running: true loops: Animation.Infinite NumberAnimation { from: gauge.angleBase to: gauge.angleBase+1.5*gauge.pi duration: 1000 target: gauge property: 'angle' easing.type: Easing.InOutSine } NumberAnimation { from: gauge.angleBase+1.5*gauge.pi to: gauge.angleBase duration: 1000 target: gauge property: 'angle' easing.type: Easing.InOutSine } } }
Runs in 5.10.1's qmlscene but no reason it shouldn't work in older versions.
-
I've taken the exact code presented above and am receiving the following compilation errors:
QOpenGLShader::compile(Fragment): ERROR: 0:12: Invalid call of undeclared identifier 'atan2' ERROR: 0:13: Use of undeclared identifier 'a' ERROR: 0:13: Use of undeclared identifier 'a' ERROR: 0:14: Use of undeclared identifier 'a' ERROR: 0:15: Use of undeclared identifier 'p' ERROR: 0:15: Use of undeclared identifier 'p' *** Problematic Fragment shader source code *** #define lowp #define mediump #define highp #line 1 uniform lowp float qt_Opacity; uniform highp float angleBase; uniform highp float angle; varying highp vec2 coord; void main() { gl_FragColor = vec4(0.0,0.0,0.0,0.0); highp vec2 d=2.0*coord-vec2(1.0,1.0); highp float r=length(d); if (0.25<=r && r<=0.75) { highp float a=atan2(d.x,-d.y); if (angleBase<=a && a<=angle) { highp float p=(a-angleBase)/(angle-angleBase); gl_FragColor = vec4(0.0,0.0,p,p) * qt_Opacity; } } } *** QQuickCustomMaterialShader: Shader compilation failed: "ERROR: 0:12: Invalid call of undeclared identifier 'atan2'\nERROR: 0:13: Use of undeclared identifier 'a'\nERROR: 0:13: Use of undeclared identifier 'a'\nERROR: 0:14: Use of undeclared identifier 'a'\nERROR: 0:15: Use of undeclared identifier 'p'\nERROR: 0:15: Use of undeclared identifier 'p'\n"
I've never worked with OpenGL before so am struggling somewhat to make sense of the above.
-
@jars121
why not simply use a conical gradient? (In conjunction with a opacity mask) -
@raven-worx that certainly appears to be simpler! I'll have a play with that approach now and report back, thanks!
-
@raven-worx Thanks again, I've got it working almost 100% now!
Quick question, is there a way to limit/stop the ConicalMask? At the moment the OpacityMask is working nicely, but when the needle is at very low values, the ConicalMask actually appears on the other side of the gauge! I can combat this by shortening the Gradient Stop, but I'd like to have a longer GradientStop, and simply 'turn off' the ConicalGradient at a certain value/angle.
-
@jars121
i don't quite understand your remaining issue.
But i think everything should be achievable by setting the gradient stops properly and/or the opacity mask. -
@mranger90 Oops sorry for causing confusion... I was on a system with an Nvidia card (and running Debian) when I threw the ShaderEffect version together... and it seems Nvidia do provide an
atan2
in their GLSL compiler (perhaps because their old "Cg" precursor language used to have it). Didn't try it anywhere else. GLSL's regularatan
with two arguments does indeed seem to do the same thing.Have to admit I'd completely forgotten about
ConicalGradient
! I do likeShaderEffect
though... it's QML's magic wand... you can do some really nifty stuff with it e,g https://youtu.be/FM0CbKvYpYI or https://youtu.be/BuTYBBScfMo or https://forum.qt.io/topic/84532/qml-animation-trail-on-object/2 ... -
@jars121 Could you put a sample code on how to get this effect using OpacistyMask and ConicalGradient? I am trying to implement this effect but with a poor result..