diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2017-05-17 13:34:06 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2017-05-17 13:34:06 +0300 |
commit | 3c799ba8013405142430d7e20c272fe92457852d (patch) | |
tree | ca2a9aa891492b522f7ed32ce4a59142ffce7731 /source/blender | |
parent | 11c167ff763528dd0c3a5487f1dc3a49bcabef1a (diff) |
DwM: Armature: Add distance outline and wire drawing of envelope bones.
This is not complete, it does not implement 3D solid drawing of
envelope bones. 2D wire is hence always drawn for now.
Some notes:
I did not try to implement the 'capsule' approach suggested by @fclem, because:
1. I spent enough time on this already, and finally got something working.
2. I managed to get rid of geometry shader completely.
3. Current approach allows us to use same shader for
distance outline and envelope wire.
It's working fine, except for one glitch - superpositions of envelope
outlines do not work as expected, not sure what's wrong here, tried to
disable zbuff, enable GL_BLEND, no luck so far...
I think we need our own 'background' drawpass to get them working (also
to avoid them drawing over the wire lines).
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/draw/intern/draw_armature.c | 138 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 111 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.c | 18 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.h | 1 | ||||
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/gpu/GPU_shader.h | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_shader.c | 4 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_vert.glsl | 98 |
9 files changed, 364 insertions, 12 deletions
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index fcd6e003df1..1e6315d6749 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -78,6 +78,9 @@ static struct { DRWShadingGroup *bone_box_solid; DRWShadingGroup *bone_box_wire; DRWShadingGroup *bone_wire_wire; + DRWShadingGroup *bone_envelope_distance; + DRWShadingGroup *bone_envelope_wire; + DRWShadingGroup *bone_envelope_head_wire; DRWShadingGroup *bone_point_solid; DRWShadingGroup *bone_point_wire; DRWShadingGroup *bone_axes; @@ -145,6 +148,44 @@ static void DRW_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float c DRW_shgroup_call_dynamic_add(g_data.bone_wire_wire, bone_mat, color); } +/* Envelope */ +static void DRW_shgroup_bone_envelope_distance( + const float (*bone_mat)[4], const float color[4], + const float *radius_head, const float *radius_tail, const float *distance) +{ + if (g_data.bone_envelope_distance == NULL) { + struct 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(g_data.bone_wire, geom, g_data.ob->obmat); + } + + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, bone_mat, color, radius_head, radius_tail, distance); +} + +static void DRW_shgroup_bone_envelope_wire( + const float (*bone_mat)[4], const float color[4], + const float *radius_head, const float *radius_tail, const float *distance) +{ + if (g_data.bone_envelope_wire == NULL) { + struct Batch *geom = DRW_cache_bone_envelope_wire_outline_get(); + g_data.bone_envelope_wire = shgroup_instance_bone_envelope(g_data.bone_wire, geom, g_data.ob->obmat); + } + + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, bone_mat, color, radius_head, radius_tail, distance); +} + +static void DRW_shgroup_bone_envelope_head_wire( + const float (*bone_mat)[4], const float color[4], + const float *radius_head, const float *radius_tail, const float *distance) +{ + if (g_data.bone_envelope_head_wire == NULL) { + struct Batch *geom = DRW_cache_bone_envelope_head_wire_outline_get(); + g_data.bone_envelope_head_wire = shgroup_instance_bone_envelope(g_data.bone_wire, geom, g_data.ob->obmat); + } + + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_head_wire, bone_mat, color, radius_head, radius_tail, distance); +} + /* Custom (geometry) */ static void DRW_shgroup_bone_custom_solid(const float (*bone_mat)[4], const float color[4], Object *custom) @@ -837,7 +878,7 @@ static void draw_axes(EditBone *eBone, bPoseChannel *pchan) const float *col = (g_theme.const_color) ? g_theme.const_color : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? g_theme.text_hi_color : g_theme.text_color; - DRW_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_tail_mat), col); + DRW_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), col); } static void draw_points( @@ -850,6 +891,8 @@ static void draw_points( const float *col_wire_root = (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color; const float *col_wire_tail = (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color; + const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE); + /* Edit bone points can be selected */ if (eBone) { if (eBone->flag & BONE_ROOTSEL) { @@ -878,15 +921,27 @@ static void draw_points( if (eBone) { if (!((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent))) { - DRW_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root); - DRW_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root); + if (is_envelope_draw) { + DRW_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root, + &eBone->rad_head, &eBone->rad_tail, &eBone->dist); + } + else { + DRW_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root); + DRW_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root); + } } } else { Bone *bone = pchan->bone; if (!((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) { - DRW_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root); - DRW_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root); + if (is_envelope_draw) { + DRW_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root, + &bone->rad_head, &bone->rad_tail, &bone->dist); + } + else { + DRW_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root); + DRW_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root); + } } } } @@ -895,8 +950,24 @@ static void draw_points( if (select_id != -1) { DRW_select_load_id(select_id | BONESEL_TIP); } - DRW_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail); - DRW_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail); + + if (is_envelope_draw) { + const float *rad_tail, *dist; + if (eBone) { + rad_tail = &eBone->rad_tail; + dist = &eBone->dist; + } + else { + rad_tail = &pchan->bone->rad_tail; + dist = &pchan->bone->dist; + } + DRW_shgroup_bone_envelope_head_wire( + BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_root, rad_tail, rad_tail, dist); + } + else { + DRW_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail); + DRW_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail); + } if (select_id != -1) { DRW_select_load_id(-1); @@ -933,11 +1004,56 @@ static void draw_bone_custom_shape( } static void draw_bone_envelope( - EditBone *UNUSED(eBone), bPoseChannel *UNUSED(pchan), bArmature *UNUSED(arm), - const int UNUSED(boneflag), const short UNUSED(constflag), - const int UNUSED(select_id)) + EditBone *eBone, bPoseChannel *pchan, bArmature *arm, + const int boneflag, const short constflag, + const int select_id) { - /* work in progress -- fclem */ + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + +// const float *col_solid = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag); + const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag); + + static const float col_white[4] = {1.0f, 1.0f, 1.0f, 0.2f}; + + float *rad_head, *rad_tail, *distance; + if (eBone) { + rad_tail = &eBone->rad_tail; + distance = &eBone->dist; + rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail : &eBone->rad_head; + } + else { + rad_tail = &pchan->bone->rad_tail; + distance = &pchan->bone->dist; + rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail : &pchan->bone->rad_head; + } + + /* Not working! Probably needs its own drawpass... */ + glEnable(GL_BLEND); + if (v3d->zbuf) { + glDisable(GL_DEPTH_TEST); + } + + if (boneflag & BONE_SELECTED) { + DRW_shgroup_bone_envelope_distance(BONE_VAR(eBone, pchan, disp_mat), col_white, rad_head, rad_tail, distance); + } + + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + } + glDisable(GL_BLEND); + + if (select_id != -1) { + DRW_select_load_id(select_id | BONESEL_BONE); + } + + DRW_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance); + + if (select_id != -1) { + DRW_select_load_id(-1); + } + + draw_points(eBone, pchan, arm, boneflag, constflag, select_id); } static void draw_bone_line( diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 36f95afc7f4..5b9247c1024 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -70,6 +70,9 @@ static struct DRWShapeCache { Batch *drw_bone_box; Batch *drw_bone_box_wire; Batch *drw_bone_wire_wire; + Batch *drw_bone_envelope_distance; + Batch *drw_bone_envelope_wire; + Batch *drw_bone_envelope_head_wire; Batch *drw_bone_point; Batch *drw_bone_point_wire; Batch *drw_bone_arrows; @@ -110,6 +113,9 @@ void DRW_shape_cache_free(void) BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_box); BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_box_wire); BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_wire_wire); + BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_distance); + BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_wire); + BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_head_wire); BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_point); BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_point_wire); BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_arrows); @@ -1524,6 +1530,111 @@ Batch *DRW_cache_bone_wire_wire_outline_get(void) } +Batch *DRW_cache_bone_envelope_distance_outline_get(void) +{ +#define CIRCLE_RESOL 32 + if (!SHC.drw_bone_envelope_distance) { + unsigned int v_idx = 0; + + static VertexFormat format = { 0 }; + static unsigned int pos_id; + if (format.attrib_ct == 0) { + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 4, KEEP_FLOAT); + } + + /* Vertices */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(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 } */ + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 0.0f}); + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 1.0f}); + if (is_headtail_transition) { + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){x, y, 1.0f - head_tail, 0.0f}); + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){x, y, 1.0f - head_tail, 1.0f}); + } + } + + SHC.drw_bone_envelope_distance = Batch_create(PRIM_TRIANGLE_STRIP, vbo, NULL); + } + return SHC.drw_bone_envelope_distance; +#undef CIRCLE_RESOL +} + + +/* Bone body and tail. */ +Batch *DRW_cache_bone_envelope_wire_outline_get(void) +{ + if (!SHC.drw_bone_envelope_wire) { + unsigned int v_idx = 0; + + static VertexFormat format = { 0 }; + static unsigned int pos_id; + if (format.attrib_ct == 0) { + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 4, KEEP_FLOAT); + } + + /* Vertices */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(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 } */ + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 0.0f, 0.0f}); + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 1.0f, 0.0f}); + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 0.0f, 0.0f}); + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 1.0f, 0.0f}); + + SHC.drw_bone_envelope_wire = Batch_create(PRIM_LINES, vbo, NULL); + } + return SHC.drw_bone_envelope_wire; +} + + +/* Bone head. */ +Batch *DRW_cache_bone_envelope_head_wire_outline_get(void) +{ +#define CIRCLE_RESOL 32 + if (!SHC.drw_bone_envelope_head_wire) { + unsigned int v_idx = 0; + + static VertexFormat format = { 0 }; + static unsigned int pos_id; + if (format.attrib_ct == 0) { + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 4, KEEP_FLOAT); + } + + /* Vertices */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, CIRCLE_RESOL); + + /* 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); + + /* { X, Y, head/tail, inner/outer border } */ + VertexBuffer_set_attrib(vbo, pos_id, v_idx++, (const float[4]){ x, y, 0.0f, 0.0f}); + } + + SHC.drw_bone_envelope_head_wire = Batch_create(PRIM_LINE_LOOP, vbo, NULL); + } + return SHC.drw_bone_envelope_head_wire; +#undef CIRCLE_RESOL +} + + 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 417630ef935..3b99b036f21 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -82,6 +82,9 @@ struct Batch *DRW_cache_bone_octahedral_wire_outline_get(void); struct Batch *DRW_cache_bone_box_get(void); struct Batch *DRW_cache_bone_box_wire_outline_get(void); struct Batch *DRW_cache_bone_wire_wire_outline_get(void); +struct Batch *DRW_cache_bone_envelope_distance_outline_get(void); +struct Batch *DRW_cache_bone_envelope_wire_outline_get(void); +struct Batch *DRW_cache_bone_envelope_head_wire_outline_get(void); struct Batch *DRW_cache_bone_point_get(void); struct Batch *DRW_cache_bone_point_wire_outline_get(void); struct Batch *DRW_cache_bone_arrows_get(void); diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index c266c45e71c..a9b5190a523 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -293,6 +293,22 @@ DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Batch *geom) return grp; } +DRWShadingGroup *shgroup_instance_bone_envelope(DRWPass *pass, struct Batch *geom, float (*obmat)[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); + DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_attrib_float(grp, "color", 4); + DRW_shgroup_attrib_float(grp, "radius_head", 1); + DRW_shgroup_attrib_float(grp, "radius_tail", 1); + DRW_shgroup_attrib_float(grp, "distance", 1); + DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat); + + return grp; +} + + /* ******************************************** COLOR UTILS *********************************************** */ /* TODO FINISH */ @@ -387,4 +403,4 @@ float *DRW_color_background_blend_get(int theme_id) UI_GetThemeColorBlendShade4fv(theme_id, TH_BACK, 0.5, 0, ret); return ret; -}
\ No newline at end of file +} diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index d7ec08b2394..0ca754a6417 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -101,6 +101,7 @@ struct DRWShadingGroup *shgroup_instance(struct DRWPass *pass, struct Batch *geo struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct Batch *geom); struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct Batch *geom); struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Batch *geom); +struct DRWShadingGroup *shgroup_instance_bone_envelope(struct DRWPass *pass, struct Batch *geom, float (*obmat)[4]); int DRW_object_wire_theme_get(struct Object *ob, struct SceneLayer *sl, float **r_color); float *DRW_color_background_blend_get(int theme_id); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5d5ea179376..0a76f5da2ba 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -171,6 +171,7 @@ data_to_c_simple(shaders/gpu_shader_instance_camera_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_instance_distance_line_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 3f761cadfc2..076ca08cf6e 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -168,6 +168,8 @@ typedef enum GPUBuiltinShader { GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE, GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR, + GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE, + GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index d9228b42599..62f787b72ab 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -92,6 +92,7 @@ extern char datatoc_gpu_shader_instance_camera_vert_glsl[]; extern char datatoc_gpu_shader_instance_distance_line_vert_glsl[]; extern char datatoc_gpu_shader_instance_edges_variying_color_geom_glsl[]; extern char datatoc_gpu_shader_instance_edges_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_bone_envelope_vert_glsl[]; extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; extern char datatoc_gpu_shader_3D_groundline_geom_glsl[]; @@ -786,6 +787,9 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) [GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR] = { datatoc_gpu_shader_instance_edges_variying_color_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl, datatoc_gpu_shader_instance_edges_variying_color_geom_glsl}, + + [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE] = { datatoc_gpu_shader_instance_bone_envelope_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, }; if (builtin_shaders[shader] == NULL) { diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_vert.glsl new file mode 100644 index 00000000000..da0d14cd2af --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_vert.glsl @@ -0,0 +1,98 @@ + + +/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view and bone, + * and scales head/tail/distance according to per-instance attributes + * (and 'role' of current vertex, encoded in zw input, head or tail, and inner or outer for distance outline). + * It is used for both the distance outline drawing, and the wire version of envelope bone. */ + + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; +uniform mat4 ObjectModelMatrix; + + +/* ---- Instanciated Attribs ---- */ +in vec4 pos; /* z encodes head (== 0.0f), tail (== 1.0f) or in-between; w encodes inner (0.0f) or outer border. */ + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +in float radius_head; +in float radius_tail; +in float distance; + + +flat out vec4 finalColor; + + +void main() +{ + /* We get head/tail in object space. */ + mat4 bone_mat = InstanceModelMatrix; + vec4 head = bone_mat * vec4(0.0f, 0.0f, 0.0f, 1.0f); + vec4 tail = bone_mat * vec4(0.0f, 1.0f, 0.0f, 1.0f); + + /* We generate our XY axes in object space, Y axis being aligned with bone in view space. */ + mat4 obview_mat = ViewMatrix * ObjectModelMatrix; + mat4 iobview_mat = inverse(obview_mat); + + vec4 view_bone_vec = obview_mat * normalize(tail - head); + view_bone_vec.z = 0.0f; + if (length(view_bone_vec.xy) <= 1e-5f) { + /* A bit weak, but will do the job for now. + * Ideally we could compute head/tail radius in view space, and take larger one... */ + if (view_bone_vec.x > view_bone_vec.y) { + view_bone_vec.x = 1e-5f; + } + else { + view_bone_vec.y = 1e-5f; + } + } + vec3 bone_axis_y = normalize((iobview_mat * view_bone_vec).xyz); + vec3 bone_axis_x = normalize(cross(bone_axis_y, iobview_mat[2].xyz)); + + /* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */ + float size = 2.0f; + + head.xyz *= size; + tail.xyz *= size; + + float head_fac = pos.z; // == 0: head; == 1: tail; in-between: along bone. + bool do_distance_offset = (pos.w != 0.0f); + + vec2 xy_pos = pos.xy; + vec4 ob_pos; + + vec4 ob_bone_origin; + float radius; + + /* head */ + if (head_fac <= 0.0f) { + radius = radius_head; + ob_bone_origin = head; + } + /* tail */ + else if (head_fac >= 1.0f) { + radius = radius_tail; + ob_bone_origin = tail; + } + /* Body of the bone */ +#if 0 /* Note: not used currently! */ + else { + float tail_fac = 1.0f - head_fac; + radius = radius_head * head_fac + radius_tail * tail_fac; + ob_bone_origin = head * head_fac + tail * tail_fac; + } +#endif + + if (do_distance_offset) { + radius += distance; + } + + xy_pos = xy_pos * radius * size; + + ob_pos = ob_bone_origin + vec4(bone_axis_x * xy_pos.x + bone_axis_y * xy_pos.y, 1.0f); + gl_Position = ProjectionMatrix * obview_mat * ob_pos; + finalColor = color; +} |