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:
authorClément Foucault <foucault.clem@gmail.com>2018-04-29 20:39:44 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-05-02 21:49:38 +0300
commit01cec3e0c52184f288a9af28b67d09965ebb0b03 (patch)
treedcf6256b52104d14ac16a3b1f242c270a88dbfc2 /source/blender/draw/intern
parent18071f4e0eee407f9a05a0e56f3f46b715d82b09 (diff)
Armature: Envelope Bones: Change drawing method.
We now use a more pleasant and efficient way to display enveloppe bones and their radius. For this we use a capsule geometry that is displaced (in the vertex shader) to a signed distance field that represents the bone shape. The bone distance radius are now drawn in 3D using a "pseudo-fresnel" effect. This gives a better understanding of what is inside the radius of influence. When capsules are not needed, we switch to default raytraced points. The capsules are not distorded by the bone's matrix (same as their actual influence radius) and are correctly displayed even with complex scaled parents hierarchy.
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r--source/blender/draw/intern/draw_armature.c77
-rw-r--r--source/blender/draw/intern/draw_cache.c142
-rw-r--r--source/blender/draw/intern/draw_cache.h1
-rw-r--r--source/blender/draw/intern/draw_common.c24
-rw-r--r--source/blender/draw/intern/draw_common.h2
5 files changed, 132 insertions, 114 deletions
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index 756cc3e6992..6b685f07de1 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -95,6 +95,9 @@ static struct {
DRWPass *pass_bone_envelope;
} g_data = {NULL};
+/* Prototype */
+static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4]);
+
/* -------------------------------------------------------------------- */
/** \name Shader Groups (DRW_shgroup)
@@ -171,13 +174,22 @@ static void drw_shgroup_bone_envelope_distance(
{
if (g_data.pass_bone_envelope != NULL) {
if (g_data.bone_envelope_distance == NULL) {
- struct Gwn_Batch *geom = DRW_cache_bone_envelope_distance_outline_get();
- /* Note: bone_wire draw pass is not really working, think we need another one here? */
- g_data.bone_envelope_distance = shgroup_instance_bone_envelope_wire(g_data.pass_bone_envelope, geom);
+ g_data.bone_envelope_distance = shgroup_instance_bone_envelope_solid(g_data.pass_bone_envelope);
+ /* pass_bone_envelope should have the DRW_STATE_CULL_FRONT state enabled. */
}
+ float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f};
float final_bonemat[4][4];
mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, final_bonemat, color, radius_head, radius_tail, distance);
+ /* We need matrix mul because we need shear applied. */
+ /* NOTE: could be done in shader if that becomes a bottleneck. */
+ mul_m4_v4(final_bonemat, head_sphere);
+ mul_m4_v4(final_bonemat, tail_sphere);
+ head_sphere[3] = *radius_head;
+ head_sphere[3] += *distance;
+ tail_sphere[3] = *radius_tail;
+ tail_sphere[3] += *distance;
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, head_sphere, tail_sphere, color, final_bonemat[0]);
}
}
@@ -186,12 +198,63 @@ static void drw_shgroup_bone_envelope_solid(
const float *radius_head, const float *radius_tail)
{
if (g_data.bone_envelope_solid == NULL) {
- struct Gwn_Batch *geom = DRW_cache_bone_envelope_solid_get();
- g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom);
+ g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid);
+ /* We can have a lot of overdraw if we don't do this. Also envelope are not subject to
+ * inverted matrix. */
+ DRW_shgroup_state_enable(g_data.bone_envelope_solid, DRW_STATE_CULL_BACK);
+ }
+ if (g_data.bone_point_solid == NULL) {
+ g_data.bone_point_solid = shgroup_instance_armature_sphere(g_data.pass_bone_solid);
}
+
+ float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f};
float final_bonemat[4][4];
mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
- DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, final_bonemat, color, radius_head, radius_tail);
+ mul_m4_v4(final_bonemat, head_sphere);
+ mul_m4_v4(final_bonemat, tail_sphere);
+ head_sphere[3] = *radius_head;
+ tail_sphere[3] = *radius_tail;
+
+ if (head_sphere[3] < 0.0f) {
+ /* Draw Tail only */
+ float tmp[4][4] = {{0.0f}};
+ tmp[0][0] = tmp[1][1] = tmp[2][2] = tail_sphere[3] / 0.05f;
+ tmp[3][3] = 1.0f;
+ copy_v3_v3(tmp[3], tail_sphere);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, color);
+ }
+ else if (tail_sphere[3] < 0.0f) {
+ /* Draw Head only */
+ float tmp[4][4] = {{0.0f}};
+ tmp[0][0] = tmp[1][1] = tmp[2][2] = head_sphere[3] / 0.05f;
+ tmp[3][3] = 1.0f;
+ copy_v3_v3(tmp[3], head_sphere);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, color);
+ }
+ else {
+ /* Draw Body */
+ float tmp_sphere[4];
+ float len = len_v3v3(tail_sphere, head_sphere);
+ float fac_head = (len - head_sphere[3]) / len;
+ float fac_tail = (len - tail_sphere[3]) / len;
+
+ /* Small epsilon to avoid problem with float precison in shader. */
+ if (len > (tail_sphere[3] + head_sphere[3]) + 1e-8f) {
+ copy_v4_v4(tmp_sphere, head_sphere);
+ interp_v4_v4v4(head_sphere, tail_sphere, head_sphere, fac_head);
+ interp_v4_v4v4(tail_sphere, tmp_sphere, tail_sphere, fac_tail);
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, head_sphere, tail_sphere, color, final_bonemat[0]);
+ }
+ else {
+ float tmp[4][4] = {{0.0f}};
+ float fac = max_ff(fac_head, 1.0f - fac_tail);
+ interp_v4_v4v4(tmp_sphere, tail_sphere, head_sphere, clamp_f(fac, 0.0f, 1.0f));
+ tmp[0][0] = tmp[1][1] = tmp[2][2] = tmp_sphere[3] / 0.05f;
+ tmp[3][3] = 1.0f;
+ copy_v3_v3(tmp[3], tmp_sphere);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, color);
+ }
+ }
}
static void drw_shgroup_bone_envelope_wire(
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 1dd588afc9f..1b41ff311a8 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -1878,43 +1878,24 @@ Gwn_Batch *DRW_cache_bone_wire_wire_outline_get(void)
return SHC.drw_bone_wire_wire;
}
-
/* Helpers for envelope bone's solid sphere-with-hidden-equatorial-cylinder.
* Note that here we only encode head/tail in forth component of the vector. */
static void benv_lat_lon_to_co(const float lat, const float lon, float r_nor[3])
{
/* Poles are along Y axis. */
r_nor[0] = sinf(lat) * cosf(lon);
- r_nor[1] = cosf(lat);
+ r_nor[1] = -cosf(lat);
r_nor[2] = sinf(lat) * sinf(lon);
}
-static void benv_add_tri(Gwn_VertBuf *vbo, uint pos_id, uint *v_idx, float *co1, float *co2, float *co3)
-{
- /* Given tri and its seven other mirrors along X/Y/Z axes. */
- for (int x = -1; x <= 1; x += 2) {
- for (int y = -1; y <= 1; y += 2) {
- const float head_tail = (y == -1) ? 0.0f : 1.0f;
- for (int z = -1; z <= 1; z += 2) {
- GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++,
- (const float[4]){co1[0] * x, co1[1] * y, co1[2] * z, head_tail});
- GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++,
- (const float[4]){co2[0] * x, co2[1] * y, co2[2] * z, head_tail});
- GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++,
- (const float[4]){co3[0] * x, co3[1] * y, co3[2] * z, head_tail});
- }
- }
- }
-}
-
Gwn_Batch *DRW_cache_bone_envelope_solid_get(void)
{
-#define CIRCLE_RESOL 32 /* Must be multiple of 4 */
if (!SHC.drw_bone_envelope) {
- const int lon_res = CIRCLE_RESOL / 4;
- const int lat_res = CIRCLE_RESOL / 4;
- const float lon_inc = M_PI_2 / lon_res;
- const float lat_inc = M_PI_2 / lat_res;
+ const int lon_res = 24;
+ const int lat_res = 16;
+ const float lon_inc = 2.0f * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ const float eps = 0.02f;
unsigned int v_idx = 0;
static Gwn_VertFormat format = { 0 };
@@ -1925,92 +1906,59 @@ Gwn_Batch *DRW_cache_bone_envelope_solid_get(void)
/* Vertices */
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
- GWN_vertbuf_data_alloc(vbo, lat_res * lon_res * 8 * 6);
+ GWN_vertbuf_data_alloc(vbo, ((lat_res + 1) * 2) * lon_res * 2);
- float lon = 0.0f;
+ float lon = lon_inc;
for (int i = 0; i < lon_res; i++, lon += lon_inc) {
float lat = 0.0f;
- float co1[3], co2[3], co3[3], co4[3];
+ float co1[4], co2[4];
+ co1[3] = co2[3] = 0.0f;
+ /* 1st sphere */
for (int j = 0; j < lat_res; j++, lat += lat_inc) {
- benv_lat_lon_to_co(lat, lon, co1);
- benv_lat_lon_to_co(lat, lon + lon_inc, co2);
- benv_lat_lon_to_co(lat + lat_inc, lon + lon_inc, co3);
- benv_lat_lon_to_co(lat + lat_inc, lon, co4);
+ benv_lat_lon_to_co(lat, lon, co1);
+ benv_lat_lon_to_co(lat, lon + lon_inc, co2);
- if (j != 0) { /* At pole, n1 and n2 are identical. */
- benv_add_tri(vbo, attr_id.pos, &v_idx, co1, co2, co3);
- }
- benv_add_tri(vbo, attr_id.pos, &v_idx, co1, co3, co4);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
}
-
- /* lat is at equator (i.e. lat == pi / 2). */
- /* We need to add 'cylinder' part between the equators (along XZ plane). */
- for (int x = -1; x <= 1; x += 2) {
- for (int z = -1; z <= 1; z += 2) {
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
- (const float[4]){co3[0] * x, co3[1], co3[2] * z, 0.0f});
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
- (const float[4]){co4[0] * x, co4[1], co4[2] * z, 0.0f});
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
- (const float[4]){co4[0] * x, co4[1], co4[2] * z, 1.0f});
-
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
- (const float[4]){co3[0] * x, co3[1], co3[2] * z, 0.0f});
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
- (const float[4]){co4[0] * x, co4[1], co4[2] * z, 1.0f});
- GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
- (const float[4]){co3[0] * x, co3[1], co3[2] * z, 1.0f});
- }
+ /* Need to close the sphere, but add a small gap to be able
+ * to distinguish the verts in the vertex shader. */
+ benv_lat_lon_to_co(M_PI - eps, lon, co1);
+ benv_lat_lon_to_co(M_PI - eps, lon + lon_inc, co2);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
+
+ /* Add some precision to the middle part */
+ // co1[3] = co2[3] = 0.5f;
+ // co1[1] = co2[1] = 0.0f;
+ // GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ // GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
+
+ /* 2nd sphere */
+ co1[3] = co2[3] = 1.0f;
+
+ /* Need to open the sphere */
+ benv_lat_lon_to_co(eps, lon, co1);
+ benv_lat_lon_to_co(eps, lon + lon_inc, co2);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
+
+ lat = lat_inc;
+ for (int j = 1; j < lat_res + 1; j++, lat += lat_inc) {
+ benv_lat_lon_to_co(lat, lon, co1);
+ benv_lat_lon_to_co(lat, lon + lon_inc, co2);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
}
}
- SHC.drw_bone_envelope = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ SHC.drw_bone_envelope = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
}
return SHC.drw_bone_envelope;
}
-
-Gwn_Batch *DRW_cache_bone_envelope_distance_outline_get(void)
-{
-#define CIRCLE_RESOL 32 /* Must be multiple of 2 */
- if (!SHC.drw_bone_envelope_distance) {
- 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, CIRCLE_RESOL * 2 + 6);
-
- /* Encoded triangle strip, vertex shader gives them final correct value. */
- for (int i = 0; i < CIRCLE_RESOL + 1; i++) {
- const bool is_headtail_transition = ELEM(i, CIRCLE_RESOL / 2, CIRCLE_RESOL);
- const float head_tail = (i > CIRCLE_RESOL / 2) ? 1.0f : 0.0f;
- const float alpha = 2.0f * M_PI * i / CIRCLE_RESOL;
- const float x = cosf(alpha);
- const float y = -sinf(alpha);
-
- /* { X, Y, head/tail, inner/outer border } */
- GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 0.0f});
- GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 1.0f});
- if (is_headtail_transition) {
- GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, 1.0f - head_tail, 0.0f});
- GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, 1.0f - head_tail, 1.0f});
- }
- }
-
- SHC.drw_bone_envelope_distance = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
- }
- return SHC.drw_bone_envelope_distance;
-#undef CIRCLE_RESOL
-}
-
-
/* Bone body. */
Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void)
{
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index b56f2c0218b..b2270ba57c7 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -101,7 +101,6 @@ 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_distance_outline_get(void);
struct Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void);
struct Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void);
struct Gwn_Batch *DRW_cache_bone_point_get(void);
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 6d684b1c9fb..8697d4c814e 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -158,6 +158,8 @@ void DRW_globals_update(void)
extern char datatoc_armature_sphere_vert_glsl[];
extern char datatoc_armature_sphere_frag_glsl[];
+extern char datatoc_armature_envelope_vert_glsl[];
+extern char datatoc_armature_envelope_frag_glsl[];
extern char datatoc_armature_sphere_outline_vert_glsl[];
extern char datatoc_armature_shape_outline_vert_glsl[];
extern char datatoc_armature_shape_outline_geom_glsl[];
@@ -165,6 +167,8 @@ extern char datatoc_gpu_shader_flat_color_frag_glsl[];
static struct {
struct GPUShader *shape_outline;
+ struct GPUShader *bone_envelope;
+ struct GPUShader *bone_envelope_outline;
struct GPUShader *bone_sphere;
struct GPUShader *bone_sphere_outline;
} g_armature_shaders = {NULL};
@@ -438,20 +442,24 @@ DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_B
return grp;
}
-DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_Batch *geom)
+DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass)
{
- static float light[3] = {0.0f, 0.0f, 1.0f};
- GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID);
+ if (g_armature_shaders.bone_envelope == NULL) {
+ g_armature_shaders.bone_envelope = DRW_shader_create(
+ datatoc_armature_envelope_vert_glsl, NULL,
+ datatoc_armature_envelope_frag_glsl, NULL);
+ }
DRW_shgroup_instance_format(g_formats.instance_bone_envelope_solid, {
- {"InstanceModelMatrix" , DRW_ATTRIB_FLOAT, 16},
+ {"headSphere" , DRW_ATTRIB_FLOAT, 4},
+ {"tailSphere" , DRW_ATTRIB_FLOAT, 4},
{"color" , DRW_ATTRIB_FLOAT, 4},
- {"radius_head" , DRW_ATTRIB_FLOAT, 1},
- {"radius_tail" , DRW_ATTRIB_FLOAT, 1}
+ {"xAxis" , DRW_ATTRIB_FLOAT, 3}
});
- DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_bone_envelope_solid);
- DRW_shgroup_uniform_vec3(grp, "light", light, 1);
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(g_armature_shaders.bone_envelope,
+ pass, DRW_cache_bone_envelope_solid_get(),
+ g_formats.instance_bone_envelope_solid);
return grp;
}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index ad6ab2d89fd..81974749282 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -119,7 +119,7 @@ struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct Gwn
struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom);
-struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass);
struct DRWShadingGroup *shgroup_instance_mball_handles(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_armature_shape_outline(struct DRWPass *pass, struct Gwn_Batch *geom);
struct DRWShadingGroup *shgroup_instance_armature_sphere(struct DRWPass *pass);