[Bf-blender-cvs] [a76d27f6942] blender2.8: Armature: Add envelope outline shader.

Clément Foucault noreply at git.blender.org
Wed May 2 20:54:47 CEST 2018


Commit: a76d27f6942ce4497e95462fd57ca67ab5c9cc6d
Author: Clément Foucault
Date:   Mon Apr 30 22:35:30 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBa76d27f6942ce4497e95462fd57ca67ab5c9cc6d

Armature: Add envelope outline shader.

===================================================================

M	source/blender/draw/intern/draw_cache.c
M	source/blender/draw/intern/draw_cache.h
A	source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl

===================================================================

diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 1b41ff311a8..db0f891c730 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -86,8 +86,7 @@ static struct DRWShapeCache {
 	Gwn_Batch *drw_bone_wire_wire;
 	Gwn_Batch *drw_bone_envelope;
 	Gwn_Batch *drw_bone_envelope_distance;
-	Gwn_Batch *drw_bone_envelope_wire;
-	Gwn_Batch *drw_bone_envelope_head_wire;
+	Gwn_Batch *drw_bone_envelope_outline;
 	Gwn_Batch *drw_bone_point;
 	Gwn_Batch *drw_bone_point_wire;
 	Gwn_Batch *drw_bone_arrows;
@@ -1959,71 +1958,59 @@ Gwn_Batch *DRW_cache_bone_envelope_solid_get(void)
 	return SHC.drw_bone_envelope;
 }
 
-/* Bone body. */
-Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void)
+Gwn_Batch *DRW_cache_bone_envelope_outline_get(void)
 {
-	if (!SHC.drw_bone_envelope_wire) {
-		unsigned int v_idx = 0;
-
-		static Gwn_VertFormat format = { 0 };
-		static unsigned int pos_id;
-		if (format.attrib_ct == 0) {
-			pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
-		}
-
-		/* Vertices */
-		Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
-		GWN_vertbuf_data_alloc(vbo, 4);
-
-		/* Two lines between head and tail circles. */
-		/* Encoded lines, vertex shader gives them final correct value. */
-		/*                                                         { X,    Y, head/tail, inner/outer border } */
-		GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f,       0.0f, 0.0f});
-		GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f,       1.0f, 0.0f});
-		GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f,       0.0f, 0.0f});
-		GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f,       1.0f, 0.0f});
-
-		SHC.drw_bone_envelope_wire = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
-	}
-	return SHC.drw_bone_envelope_wire;
-}
-
-
-/* Bone head and tail. */
-Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void)
-{
-#define CIRCLE_RESOL 32  /* Must be multiple of 2 */
-	if (!SHC.drw_bone_envelope_head_wire) {
-		unsigned int v_idx = 0;
+	if (!SHC.drw_bone_envelope_outline) {
+#  define CIRCLE_RESOL 64
+		float v0[2], v1[2], v2[2];
+		const float radius = 1.0f;
 
+		/* Position Only 2D format */
 		static Gwn_VertFormat format = { 0 };
-		static unsigned int pos_id;
+		static struct { uint pos0, pos1, pos2; } attr_id;
 		if (format.attrib_ct == 0) {
-			pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+			attr_id.pos0 = GWN_vertformat_attr_add(&format, "pos0", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+			attr_id.pos1 = GWN_vertformat_attr_add(&format, "pos1", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+			attr_id.pos2 = GWN_vertformat_attr_add(&format, "pos2", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 		}
 
-		/* Vertices */
 		Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
-		GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
+		GWN_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
 
-		/* Encoded lines, vertex shader gives them final correct value. */
-		/* Only head circle (tail is drawn in disp_tail_mat space as a head one by draw_armature.c's draw_point()). */
-		for (int i = 0; i < CIRCLE_RESOL; i++) {
-			const float alpha = 2.0f * M_PI * i / CIRCLE_RESOL;
-			const float x = cosf(alpha);
-			const float y = -sinf(alpha);
+		v0[0] = radius * sinf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
+		v0[1] = radius * cosf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
+		v1[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
+		v1[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
 
-			/*                                                         {     X,      Y, head/tail, inner/outer border } */
-			GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){     x,      y,      0.0f, 0.0f});
+		/* Output 4 verts for each position. See shader for explanation. */
+		unsigned int v = 0;
+		for (int a = 0; a < CIRCLE_RESOL; a++) {
+			v2[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+			v2[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+			GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
+			GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
+			GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+			GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
+			GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
+			GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+			copy_v2_v2(v0, v1);
+			copy_v2_v2(v1, v2);
 		}
+		v2[0] = 0.0f;
+		v2[1] = radius;
+		GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
+		GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
+		GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+		GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
+		GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
+		GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
 
-		SHC.drw_bone_envelope_head_wire = GWN_batch_create_ex(GWN_PRIM_LINE_LOOP, vbo, NULL, GWN_BATCH_OWNS_VBO);
+		SHC.drw_bone_envelope_outline = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
+#  undef CIRCLE_RESOL
 	}
-	return SHC.drw_bone_envelope_head_wire;
-#undef CIRCLE_RESOL
+	return SHC.drw_bone_envelope_outline;
 }
 
-
 Gwn_Batch *DRW_cache_bone_point_get(void)
 {
 	if (!SHC.drw_bone_point) {
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index b2270ba57c7..22a5588599f 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -101,7 +101,7 @@ struct Gwn_Batch *DRW_cache_bone_box_get(void);
 struct Gwn_Batch *DRW_cache_bone_box_wire_outline_get(void);
 struct Gwn_Batch *DRW_cache_bone_wire_wire_outline_get(void);
 struct Gwn_Batch *DRW_cache_bone_envelope_solid_get(void);
-struct Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_envelope_outline_get(void);
 struct Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void);
 struct Gwn_Batch *DRW_cache_bone_point_get(void);
 struct Gwn_Batch *DRW_cache_bone_point_wire_outline_get(void);
diff --git a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
new file mode 100644
index 00000000000..2c38ffebca4
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
@@ -0,0 +1,165 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform vec2 viewportSize;
+uniform float lineThickness = 3.0;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 pos0;
+in vec2 pos1;
+in vec2 pos2;
+
+/* ---- 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;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+	return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+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 = (ProjectionMatrix[3][3] == 0.0);
+	vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz
+	                          : -ViewMatrixInverse[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 p1, vec; float vec_rsq, h_bias, h_scale; };
+
+bool bone_blend_starts(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. */
+	return h > 0.0; /* we just want to know when the head sphere starts interpolating. */
+	// h = clamp(h, 0.0, 1.0);
+	// return length(pa - b.vec * h) - (b.r1 + b.rdif * h);
+}
+
+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 = sph_near.xyz + 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);
+	}
+	return wpos;
+}
+
+void main()
+{
+	float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz);
+	float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz);
+	// float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz);
+	// float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz);
+
+	vec4 sph_near, sph_far;
+	if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) {
+		sph_near = tailSphere;
+		sph_far = headSphere;
+	}
+	else {
+		sph_near = headSphere;
+		sph_far = tailSphere;
+	}
+
+	Bone b;
+	/* Precompute everything we can to speedup iterations. */
+	b.p1 = sph_near.xyz;
+	b.vec = sph_far.xyz - sph_near.xyz;
+	float vec_lsq = max(1e-8, dot(b.vec, b.vec));
+	b.vec_rsq = 1.0 / vec_lsq;
+	float sinb = (sph_far.w - sph_near.w) * b.vec_rsq;
+	f

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list