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:
-rw-r--r--source/blender/draw/CMakeLists.txt2
-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
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c2
-rw-r--r--source/blender/draw/modes/object_mode.c2
-rw-r--r--source/blender/draw/modes/pose_mode.c2
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_frag.glsl15
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_vert.glsl96
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;
+}