attribute vec2 a_pos; attribute float a_radius; attribute vec2 a_flags; uniform mat4 u_matrix; uniform mat4 u_inv_matrix; uniform vec2 u_viewport_size; uniform float u_camera_to_center_distance; varying float v_radius; varying vec2 v_extrude; varying float v_perspective_ratio; varying float v_collision; vec3 toTilePosition(vec2 screenPos) { // Shoot a ray towards the ground to reconstruct the depth-value vec4 rayStart = u_inv_matrix * vec4(screenPos, -1.0, 1.0); vec4 rayEnd = u_inv_matrix * vec4(screenPos, 1.0, 1.0); rayStart.xyz /= rayStart.w; rayEnd.xyz /= rayEnd.w; highp float t = (0.0 - rayStart.z) / (rayEnd.z - rayStart.z); return mix(rayStart.xyz, rayEnd.xyz, t); } void main() { vec2 quadCenterPos = a_pos; float radius = a_radius; float collision = a_flags.x; float vertexIdx = a_flags.y; vec2 quadVertexOffset = vec2( mix(-1.0, 1.0, float(vertexIdx >= 2.0)), mix(-1.0, 1.0, float(vertexIdx >= 1.0 && vertexIdx <= 2.0))); vec2 quadVertexExtent = quadVertexOffset * radius; // Screen position of the quad might have been computed with different camera parameters. // Transform the point to a proper position on the current viewport vec3 tilePos = toTilePosition(quadCenterPos); vec4 clipPos = u_matrix * vec4(tilePos, 1.0); highp float camera_to_anchor_distance = clipPos.w; highp float collision_perspective_ratio = clamp( 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles 4.0); // Apply small padding for the anti-aliasing effect to fit the quad // Note that v_radius and v_extrude are in screen coordinates already float padding_factor = 1.2; v_radius = radius; v_extrude = quadVertexExtent * padding_factor; v_perspective_ratio = collision_perspective_ratio; v_collision = collision; gl_Position = vec4(clipPos.xyz / clipPos.w, 1.0) + vec4(quadVertexExtent * padding_factor / u_viewport_size * 2.0, 0.0, 0.0); }