diff options
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_armature.c | 77 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 142 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.c | 24 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.h | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/edit_armature_mode.c | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/object_mode.c | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/pose_mode.c | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/armature_envelope_frag.glsl | 15 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/armature_envelope_vert.glsl | 96 |
11 files changed, 248 insertions, 117 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 3ab0ea40990..3ccbf967b87 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -224,6 +224,8 @@ data_to_c_simple(modes/shaders/common_fullscreen_vert.glsl SRC) data_to_c_simple(modes/shaders/armature_sphere_vert.glsl SRC) data_to_c_simple(modes/shaders/armature_sphere_frag.glsl SRC) data_to_c_simple(modes/shaders/armature_sphere_outline_vert.glsl SRC) +data_to_c_simple(modes/shaders/armature_envelope_vert.glsl SRC) +data_to_c_simple(modes/shaders/armature_envelope_frag.glsl SRC) data_to_c_simple(modes/shaders/armature_shape_outline_vert.glsl SRC) data_to_c_simple(modes/shaders/armature_shape_outline_geom.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC) 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); diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c index 292e62f090c..bc992c8741a 100644 --- a/source/blender/draw/modes/edit_armature_mode.c +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -93,7 +93,7 @@ static void EDIT_ARMATURE_cache_init(void *vedata) { /* distance outline around envelope bones */ - DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_FRONT; psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state); } diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index d48c1bbc0ba..8b86fe8c9a2 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -1052,7 +1052,7 @@ static void OBJECT_cache_init(void *vedata) { /* distance outline around envelope bones */ - DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_FRONT; psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state); } diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index 5a3ed791b84..9c3d6a655a5 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -102,7 +102,7 @@ static void POSE_cache_init(void *vedata) { /* distance outline around envelope bones */ - DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_FRONT; psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state); } diff --git a/source/blender/draw/modes/shaders/armature_envelope_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_frag.glsl new file mode 100644 index 00000000000..468a04d64f0 --- /dev/null +++ b/source/blender/draw/modes/shaders/armature_envelope_frag.glsl @@ -0,0 +1,15 @@ + +flat in vec4 finalColor; +in vec3 normalView; + +out vec4 fragColor; + +void main() +{ + float n = normalize(normalView).z; + n = gl_FrontFacing ? n : -n; + n = clamp(n, 0.0, 1.0); + n = gl_FrontFacing ? n : 1.0 - n; + fragColor = finalColor; + fragColor.rgb *= n; +} 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; +} |