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

armature_envelope_vert.glsl « shaders « modes « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: fbce8ca69dda5e79f99da2af1742753864f1446b (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

uniform mat4 ViewMatrixInverse;
uniform mat4 ViewProjectionMatrix;

/* ---- 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;
}