diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-04-29 20:39:44 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-05-02 21:49:38 +0300 |
commit | 01cec3e0c52184f288a9af28b67d09965ebb0b03 (patch) | |
tree | dcf6256b52104d14ac16a3b1f242c270a88dbfc2 /source/blender/draw/intern/draw_armature.c | |
parent | 18071f4e0eee407f9a05a0e56f3f46b715d82b09 (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/draw_armature.c')
-rw-r--r-- | source/blender/draw/intern/draw_armature.c | 77 |
1 files changed, 70 insertions, 7 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( |