1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
#include webgl_header.vs
// Sphere impostor vertex shader
uniform float sphere_size_scale;
attribute vec4 a_vertex_radius;
attribute vec4 a_Color;
attribute float a_rightUpFlags;
varying vec4 COLOR;
varying vec3 sphere_center;
varying float radius2;
varying vec3 point;
varying vec2 bgTextureLookup;
/*
* horizontial and vertical adjustment of outer tangent hitting the
* impostor quad, in model view space.
*/
vec2 outer_tangent_adjustment(vec3 center, float radius_sq) {
vec2 xy_dist = vec2(length(center.xz), length(center.yz));
// without clamping, this caused flickering (divide-by-zero)
vec2 cos_a = clamp(center.z / xy_dist, -1., 1.);
vec2 cos_b = xy_dist / sqrt(radius_sq + (xy_dist * xy_dist));
// numerically more stable version of:
// vec2 tan_ab_sq = pow(tan(acos(cos_b) + acos(cos_a)), 2);
vec2 cos_ab = (cos_a * cos_b + sqrt(
(1. - cos_a * cos_a) *
(1. - cos_b * cos_b)));
vec2 cos_ab_sq = cos_ab * cos_ab;
vec2 tan_ab_sq = (1. - cos_ab_sq) / cos_ab_sq;
vec2 adjustment = sqrt(tan_ab_sq + 1.);
// max out (empirical) to avoid exploding (can happen for spheres outside of the viewport)
return min(adjustment, 10.);
}
void main(void)
{
// Get billboard attributes
float radius = a_vertex_radius.w * sphere_size_scale;
// support uniform scaling
radius /= length(g_NormalMatrix[0]);
float right = -1. + 2.*mod(a_rightUpFlags, 2.);
float up = -1. + 2.*floor(mod(a_rightUpFlags/2., 2.));
vec4 tmppos = g_ModelViewMatrix * vec4(a_vertex_radius.xyz, 1.);
COLOR = a_Color;
radius2 = radius * radius; // compute squared radius
// uni-radius corner offset
vec2 corner_offset = vec2(right, up);
#ifndef ortho
// horizontial and vertical adjustment due to projection
corner_offset *= outer_tangent_adjustment(tmppos.xyz, radius2);
#endif
// corner vertex
vec4 eye_space_pos = tmppos;
eye_space_pos.xy += radius * corner_offset;
// Compute sphere position in modelview space
sphere_center = tmppos.xyz / tmppos.w;
// Compute ray direction and origin point
point = eye_space_pos.xyz / eye_space_pos.w;
#ifndef PYMOL_WEBGL_IOS
// Pass the transformed vertex for clipping plane calculations
gl_ClipVertex = eye_space_pos;
#endif
// Pass transformed vertex
gl_Position = g_ProjectionMatrix * eye_space_pos;
bgTextureLookup = (gl_Position.xy/gl_Position.w) / 2.0 + 0.5;
}
|