Welcome to mirror list, hosted at ThFree Co, Russian Federation.

overlay_armature_envelope_outline_vert.glsl « shaders « overlay « engines « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c13698728ef6c09ef3c40ab9739a70b62ba809ee (plain)
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)

/* project to screen space */
vec2 proj(vec4 pos)
{
  return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}

vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2)
{
  vec2 dir = normalize(v2 - v0);
  dir = vec2(dir.y, -dir.x);
  return dir;
}

mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs)
{
  bool is_persp = (drw_view.winmat[3][3] == 0.0);
  vec3 cam_ray = (is_persp) ? sphere.xyz - drw_view.viewinv[3].xyz : -drw_view.viewinv[2].xyz;

  /* Sphere center distance from the camera (persp) in world space. */
  float cam_dist = length(cam_ray);

  /* Compute view aligned orthonormal space. */
  vec3 z_axis = cam_ray / cam_dist;
  vec3 x_axis = normalize(cross(bone_vec, z_axis));
  vec3 y_axis = cross(z_axis, x_axis);
  z_ofs = 0.0;

  if (is_persp) {
    /* For perspective, the projected sphere radius
     * can be bigger than the center disc. Compute the
     * max angular size and compensate by sliding the disc
     * towards the camera and scale it accordingly. */
    const float half_pi = 3.1415926 * 0.5;
    float rad = sphere.w;
    /* Let be :
     * V the view vector origin.
     * O the sphere origin.
     * T the point on the target circle.
     * We compute the angle between (OV) and (OT). */
    float a = half_pi - asin(rad / cam_dist);
    float cos_b = cos(a);
    float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));

    x_axis *= sin_b;
    y_axis *= sin_b;
    z_ofs = -rad * cos_b;
  }

  return mat3(x_axis, y_axis, z_axis);
}

struct Bone {
  vec3 vec;
  float sinb;
};

bool bone_blend_starts(vec3 p, Bone b)
{
  /* we just want to know when the head sphere starts interpolating. */
  return dot(p, b.vec) > -b.sinb;
}

vec3 get_outline_point(vec2 pos,
                       vec4 sph_near,
                       vec4 sph_far,
                       mat3 mat_near,
                       mat3 mat_far,
                       float z_ofs_near,
                       float z_ofs_far,
                       Bone b)
{
  /* Compute outline position on the nearest sphere and check
   * if it penetrates the capsule body. If it does, put this
   * vertex on the farthest sphere. */
  vec3 wpos = mat_near * vec3(pos * sph_near.w, z_ofs_near);
  if (bone_blend_starts(wpos, b)) {
    wpos = sph_far.xyz + mat_far * vec3(pos * sph_far.w, z_ofs_far);
  }
  else {
    wpos += sph_near.xyz;
  }
  return wpos;
}

void main()
{
  float dst_head = distance(headSphere.xyz, drw_view.viewinv[3].xyz);
  float dst_tail = distance(tailSphere.xyz, drw_view.viewinv[3].xyz);
  // float dst_head = -dot(headSphere.xyz, drw_view.viewmat[2].xyz);
  // float dst_tail = -dot(tailSphere.xyz, drw_view.viewmat[2].xyz);

  vec4 sph_near, sph_far;
  if ((dst_head > dst_tail) && (drw_view.winmat[3][3] == 0.0)) {
    sph_near = tailSphere;
    sph_far = headSphere;
  }
  else {
    sph_near = headSphere;
    sph_far = tailSphere;
  }

  vec3 bone_vec = (sph_far.xyz - sph_near.xyz) + 1e-8;

  Bone b;
  float bone_lenrcp = 1.0 / max(1e-8, sqrt(dot(bone_vec, bone_vec)));
  b.sinb = (sph_far.w - sph_near.w) * bone_lenrcp * sph_near.w;
  b.vec = bone_vec * bone_lenrcp;

  float z_ofs_near, z_ofs_far;
  mat3 mat_near = compute_mat(sph_near, bone_vec, z_ofs_near);
  mat3 mat_far = compute_mat(sph_far, bone_vec, z_ofs_far);

  vec3 wpos0 = get_outline_point(
      pos0, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
  vec3 wpos1 = get_outline_point(
      pos1, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
  vec3 wpos2 = get_outline_point(
      pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);

  view_clipping_distances(wpos1);

  vec4 p0 = point_world_to_ndc(wpos0);
  vec4 p1 = point_world_to_ndc(wpos1);
  vec4 p2 = point_world_to_ndc(wpos2);

  gl_Position = p1;

  /* compute position from 3 vertex because the change in direction
   * can happen very quickly and lead to very thin edges. */
  vec2 ss0 = proj(p0);
  vec2 ss1 = proj(p1);
  vec2 ss2 = proj(p2);
  vec2 ofs_dir = compute_dir(ss0, ss1, ss2);

  /* Offset away from the center to avoid overlap with solid shape. */
  gl_Position.xy += ofs_dir * sizeViewportInv * gl_Position.w;

  edgeStart = edgePos = proj(gl_Position);

  finalColor = vec4(outlineColorSize.rgb, 1.0);
}