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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/modes/shaders/armature_envelope_vert.glsl')
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_vert.glsl96
1 files changed, 96 insertions, 0 deletions
diff --git a/source/blender/draw/modes/shaders/armature_envelope_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_vert.glsl
new file mode 100644
index 00000000000..a67b9c351c5
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_vert.glsl
@@ -0,0 +1,96 @@
+
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+/* ---- Instanciated Attribs ---- */
+in vec4 pos; /* w encodes head (== 0.0f), tail (== 1.0f). */
+
+/* ---- Per instance Attribs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec4 color;
+in vec3 xAxis;
+
+flat out vec4 finalColor;
+out vec3 normalView;
+
+struct Bone { vec3 p1, vec; float r1, rdif, vec_rsq, h_bias, h_scale; };
+
+float sdf_bone(vec3 p, Bone b)
+{
+ /* Simple capsule sdf with a minor touch and optimisations. */
+ vec3 pa = p - b.p1;
+ float h = dot(pa, b.vec) * b.vec_rsq;
+ h = h * b.h_scale + b.h_bias; /* comment this line for sharp transition. */
+ h = clamp(h, 0.0, 1.0);
+ return length(pa - b.vec * h) - (b.r1 + b.rdif * h);
+}
+
+void main()
+{
+ /* Raytracing against cone need a parametric definition of the cone
+ * using axis, angle and apex. But if both sphere are nearly the same
+ * size, the apex become ill defined, and so does the angle.
+ * So to circumvent this, we use the numerical solution: raymarching.
+ * But due to the the cost of raymarching per pixel, we choose to use it
+ * to position vertices from a VBO with the distance field.
+ * The nice thing is that we start the raymarching really near the surface
+ * so we actually need very few iterations to get a good result. */
+
+ Bone b;
+ /* Precompute everything we can to speedup iterations. */
+ b.p1 = headSphere.xyz;
+ b.r1 = headSphere.w;
+ b.rdif = tailSphere.w - headSphere.w;
+ b.vec = tailSphere.xyz - headSphere.xyz;
+ float vec_lsq = max(1e-8, dot(b.vec, b.vec));
+ b.vec_rsq = 1.0 / vec_lsq;
+ float sinb = (tailSphere.w - headSphere.w) * b.vec_rsq;
+ float ofs1 = sinb * headSphere.w;
+ float ofs2 = sinb * tailSphere.w;
+ b.h_scale = 1.0 - ofs1 + ofs2;
+ b.h_bias = ofs1 * b.h_scale;
+
+ /* Radius for the initial position */
+ float rad = b.r1 + b.rdif * pos.w;
+
+ float vec_len = sqrt(vec_lsq);
+ vec3 y_axis = b.vec / max(1e-8, vec_len);
+ vec3 z_axis = normalize(cross(xAxis, -y_axis));
+ vec3 x_axis = cross(y_axis, -z_axis); /* cannot trust xAxis to be orthogonal. */
+
+ vec3 sp = pos.xyz * rad;
+ if (pos.w == 1.0) {
+ /* Prevent tail sphere to cover the head sphere if head is really big. */
+ sp.y = max(sp.y, -(vec_len - headSphere.w));
+ sp.y += vec_len; /* Position tail on the Bone axis. */
+ }
+
+ /* p is vertex position in world space */
+ vec3 p = mat3(x_axis, y_axis, z_axis) * sp;
+ p += headSphere.xyz;
+
+ /* push vert towards the capsule boundary */
+ vec3 dir = vec3(normalize(pos.xz + 1e-8), 0.0);
+ dir = mat3(x_axis, y_axis, z_axis) * dir.xzy;
+
+ /* Signed distance field gives us the distance to the surface.
+ * Use a few iteration for precision. */
+ p = p - dir * sdf_bone(p, b);
+ p = p - dir * sdf_bone(p, b);
+ p = p - dir * sdf_bone(p, b);
+ p = p - dir * sdf_bone(p, b);
+ p = p - dir * sdf_bone(p, b);
+
+ const float eps = 0.0005;
+ normalView.x = sdf_bone(p + ViewMatrixInverse[0].xyz * eps, b);
+ normalView.y = sdf_bone(p + ViewMatrixInverse[1].xyz * eps, b);
+ normalView.z = sdf_bone(p + ViewMatrixInverse[2].xyz * eps, b);
+
+ gl_Position = ViewProjectionMatrix * vec4(p, 1.0);
+
+ finalColor = color;
+}