1 precision mediump float;
3 attribute vec2 aPosition;
5 uniform mat4 uMvpMatrix;
6 uniform mat4 uModelView;
7 uniform mat4 uViewMatrix;
8 uniform mat4 uProjection;
11 uniform mat4 uModelLastFrame;
12 float timeDelta = 0.0167;
14 uniform float uGeometryStretchFactor;
15 uniform float uSpeedScalingFactor;
18 varying vec2 vModelSpaceCenterToPos;
19 varying vec2 vScreenSpaceVelocityVector;
21 varying vec2 vTexCoord;
25 // get view space position of vertex this frame and last frame
26 vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
27 vertexPosition.xyz *= uSize;
29 vec4 viewSpaceVertex = uModelView * vertexPosition;
30 vec4 viewSpaceVertexLastFrame = uViewMatrix * uModelLastFrame * vertexPosition;
32 // work out vertex's last movement in view space
33 vec3 viewSpacePosDelta = viewSpaceVertex.xyz - viewSpaceVertexLastFrame.xyz;
34 float reciprocalTimeDelta = 1.0 / timeDelta;
36 // get clip space position of vertex this frame and last frame
37 vec4 clipSpaceVertex = uMvpMatrix * vertexPosition;
38 vec4 clipSpaceVertexLastFrame = uProjection * viewSpaceVertexLastFrame;
40 // decide how much this vertex is 'trailing', i.e. at the back of the object relative to its direction of motion. We do this
41 // by assuming the objects model space origin is at its center and taking the dot product of the vector from center to vertex with the motion direction
43 float posDeltaLength = length(viewSpacePosDelta);
44 if(posDeltaLength > 0.001) // avoid div by 0 if object has barely moved
46 vec4 viewSpaceCenterToPos = uModelView * vec4(aPosition, 0.0, 0.0);
47 float centerToVertexDist = length(viewSpaceCenterToPos);
48 if(centerToVertexDist > 0.001) // avoid div by 0 if object has vertex at model space origin
50 vec3 viewSpacePosDeltaNormalised = viewSpacePosDelta / posDeltaLength;
51 vec3 viewSpaceCenterToPosNormalised = viewSpaceCenterToPos.xyz / centerToVertexDist;
52 t = (dot(viewSpacePosDeltaNormalised, viewSpaceCenterToPosNormalised) * 0.5 ) + 0.5; // scale and bias from [-1..1] to [0..1]
56 // output vertex position lerped with its last position, based on how much it is trailing,
57 // this stretches the geom back along where it has just been, giving a warping effect
58 // We raise t to a power in order that non-trailing vertices are effected much more than trailing ones
59 // Note: we must take account of time delta to convert position delta into a velocity, so changes are smooth (take into account frame time correctly)
60 gl_Position = mix(clipSpaceVertexLastFrame, clipSpaceVertex, t * t * t * uGeometryStretchFactor * reciprocalTimeDelta);
62 // work out vertex's last movement in normalised device coordinates [-1..1] space, i.e. perspective divide
63 vec2 ndcVertex = clipSpaceVertex.xy / clipSpaceVertex.w;
64 vec2 ndcVertexLastFrame = clipSpaceVertexLastFrame.xy / clipSpaceVertexLastFrame.w;
65 // scale and bias so that a value of 1.0 corresponds to screen size (NDC is [-1..1] = 2)
66 vScreenSpaceVelocityVector = ((ndcVertex - ndcVertexLastFrame) * 0.5 * reciprocalTimeDelta);
67 vScreenSpaceVelocityVector.y = -vScreenSpaceVelocityVector.y; // TODO negated due to y being inverted in our coordinate system?
68 // calculate a scaling factor proportional to velocity, which we can use to tweak how things look
69 vSpeed = length(vScreenSpaceVelocityVector) * uSpeedScalingFactor;
70 vSpeed = clamp(vSpeed, 0.0, 1.0);
72 // provide fragment shader with vector from center of object to pixel (assumes the objects model space origin is at its center and verts have same z)
73 vModelSpaceCenterToPos = viewSpaceVertex.xy;
75 vec2 texCoord = aPosition + vec2(0.5);