qml animation trail on object
-
I'm trying to leave a trail behind an image that's moved from one position to the next, similar to when swipe keyboard when you drag your finger from one spot to the next. Basically I want a way to show where an object has been. I'm only moving the image (which is just a dot so I could change it to a Ellipse) in a horizontal line so it shouldn't be too hard.
I've looked at using a ParticleSystem, a TrailEmitter and adjusting gravity to pull the particles to where I want them but the TrailEmitter only seems to work until the particle gets to the first gravity spot. There is no subsequent trail when moving to the next gravity spot.
I feel like there should be an easier way than having two ellipses with a rectangle in between and having a changing the opaque level based on position.
Cheers.
-
I once played around trying to create an old phosphor oscilloscope look...
I came up with this:
although it does look better in its native 60FPS than as a captured GIF.Tricks I used:
- Rendering a line rather than a dot (otherwise you just end up with a collection of dots).
- Recursive shader to fade the trail with time.
- Bit of Glow effect to stop it looking too much like a jagged collection of line segments.
Maybe some ideas can be used to get whatever look you're trying to get.
Code (runs in Qt 5.9.1's qmlscene on OSX):
import QtQuick 2.2 import QtGraphicalEffects 1.0 Item { id: main width: 640 height: 480 Rectangle { id: bg anchors.fill: parent color: '#50593a' visible: false } Rectangle { id: phosphor anchors.fill: parent color: '#00000000' property real timebase: 0.0 NumberAnimation on timebase { duration: 1000 from: 0.0 to: 1.0 loops: Animation.Infinite } onTimebaseChanged: trace.advance(timebase) Item { id: trace anchors.fill: parent property real cycles: 0.0 property real noise: 0.0 function advance(t) { if (t<spot.x1) cycles+=1.0 spot.x0=spot.x1 spot.x1=t var signal=0.2+0.6*Math.pow(0.5+0.5*Math.cos(2.0*Math.PI*(cycles+t)*0.8),16) noise+=(Math.random()-0.5)*0.01-0.01*noise spot.y0=spot.y1 spot.y1=1.0-signal-noise } ShaderEffect { id: spot anchors.fill: parent blending: true property real x1: 0.0 property real y1: 0.0 property real x0: 0.0 property real y0: 0.0 property color col: '#7fffa7' 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 highp float x0; uniform highp float y0; uniform highp float x1; uniform highp float y1; uniform lowp vec4 col; varying highp vec2 coord; void main() { highp float k=1.0/distance(vec2(x1,y1),vec2(x0,y0)); highp float r=0.0001+0.00005*k; highp vec2 n=normalize(vec2(x1,y1)-vec2(x0,y0)); highp float p=dot(coord,n)-dot(vec2(x0,y0),n); highp float q=p*k; highp float d=distance(coord,vec2(x0,y0)+p*n); highp float d0=distance(coord,vec2(x0,y0)); highp float d1=distance(coord,vec2(x1,y1)); if (x1<x0) gl_FragColor=vec4(0.0,0.0,0.0,0.0); else if (0.0<=q && q<=1.0 && d<r) gl_FragColor=col*(1.0-d/r); else if (q<0.0 && d0<r) gl_FragColor=col*(1.0-d/r); else if (q>1.0 && d1<r) gl_FragColor=col*(1.0-d/r); else gl_FragColor=vec4(0.0,0.0,0.0,0.0); }" } } ShaderEffectSource { id: base anchors.fill: parent live: true sourceItem: trace hideSource: true } ShaderEffectSource { id: buffer anchors.fill: parent live: true recursive: true sourceItem: buffer wrapMode: ShaderEffectSource.ClampToEdge smooth: false ShaderEffect { anchors.fill: parent blending: false property variant src0: buffer property variant src1: base 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 sampler2D src0; uniform sampler2D src1; varying highp vec2 coord; void main() { highp vec4 src0=texture2D(src0,coord); highp vec4 src1=texture2D(src1,coord); gl_FragColor=floor(255.0*0.975*src0)/255.0+src1; }" } } } Glow { id: glow anchors.fill: parent radius: 16 samples: 32 spread: 0.75 color: '#7fffa7' source: phosphor } Blend { anchors.fill: parent source: bg foregroundSource: glow mode: 'addition' } Grid { id: graticule columns: 8 rows: 6 spacing: 0 Repeater { model: parent.rows*parent.columns Rectangle { width: 80 height: 80 color: '#00000000' border.width: 1 border.color: '#66000000' } } } }