#define PI 3.14159265359 precision lowp float; attribute vec2 aPosition, aCorner; uniform sampler2D raindropState, symbolState, effectState; uniform float density; uniform vec2 quadSize; uniform float glyphHeightToWidth, glyphVerticalSpacing; uniform mat4 camera, transform; uniform vec2 screenSize; uniform float time, animationSpeed, forwardSpeed; uniform bool volumetric; varying vec2 vUV; varying vec4 vRaindrop, vSymbol, vEffect; varying float vDepth; highp float rand( const in vec2 uv ) { const highp float a = 12.9898, b = 78.233, c = 43758.5453; highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); return fract(sin(sn) * c); } void main() { vUV = (aPosition + aCorner) * quadSize; vRaindrop = texture2D(raindropState, aPosition * quadSize); vSymbol = texture2D( symbolState, aPosition * quadSize); vEffect = texture2D( effectState, aPosition * quadSize); // Calculate the world space position float quadDepth = 0.0; if (volumetric) { float startDepth = rand(vec2(aPosition.x, 0.)); quadDepth = fract(startDepth + time * animationSpeed * forwardSpeed); vDepth = quadDepth; } vec2 position = (aPosition * vec2(1., glyphVerticalSpacing) + aCorner * vec2(density, 1.)) * quadSize; if (volumetric) { position.y += rand(vec2(aPosition.x, 1.)) * quadSize.y; } vec4 pos = vec4((position - 0.5) * 2.0, quadDepth, 1.0); // Convert the world space position to screen space if (volumetric) { pos.x /= glyphHeightToWidth; pos = camera * transform * pos; } else { pos.xy *= screenSize; } gl_Position = pos; }