diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 147d166e8b0..46122af257c 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -134,7 +134,7 @@ static void drw_shgroup_bone_octahedral( const float bone_color[4], const float hint_color[4], const float outline_color[4]) { if (g_data.bone_octahedral_outline == NULL) { - struct Gwn_Batch *geom = DRW_cache_bone_octahedral_get(); + struct Gwn_Batch *geom = DRW_cache_bone_octahedral_wire_get(); g_data.bone_octahedral_outline = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, geom); } if (g_data.bone_octahedral_solid == NULL) { @@ -155,7 +155,7 @@ static void drw_shgroup_bone_box( const float bone_color[4], const float hint_color[4], const float outline_color[4]) { if (g_data.bone_box_wire == NULL) { - struct Gwn_Batch *geom = DRW_cache_bone_box_get(); + struct Gwn_Batch *geom = DRW_cache_bone_box_wire_get(); g_data.bone_box_outline = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, geom); } if (g_data.bone_box_solid == NULL) { diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 3c312205ec2..cd73ec4e674 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -1593,13 +1593,13 @@ static const float bone_octahedral_smooth_normals[6][3] = { { 0.0f, 1.0f, 0.0f} }; -#if 0 /* UNUSED */ static const uint bone_octahedral_wire[24] = { 0, 1, 1, 5, 5, 3, 3, 0, 0, 4, 4, 5, 5, 2, 2, 0, 1, 2, 2, 3, 3, 4, 4, 1, }; +#if 0 /* UNUSED */ /* aligned with bone_octahedral_wire * Contains adjacent normal index */ static const uint bone_octahedral_wire_adjacent_face[24] = { @@ -1632,6 +1632,13 @@ static const uint bone_octahedral_solid_tris[8][3] = { * the first vertex of the first face aka. vertex 2): * {0, 12, 1, 10, 2, 3} **/ +static const uint bone_octahedral_wire_lines_adjacency[12][4] = { + { 0, 2, 1, 6}, { 0, 1, 12, 6}, { 6, 12, 3, 0}, { 6, 3, 2, 0}, + { 1, 2, 6, 3}, { 1, 6, 12, 3}, { 3, 12, 0, 1}, { 3, 0, 2, 1}, + { 2, 1, 0, 12}, { 2, 0, 3, 12}, { 2, 3, 6, 12}, { 2, 6, 1, 12}, +}; + +#if 0 /* UNUSED */ static const uint bone_octahedral_solid_tris_adjacency[8][6] = { { 0, 12, 1, 10, 2, 3}, { 3, 15, 4, 1, 5, 6}, @@ -1643,6 +1650,7 @@ static const uint bone_octahedral_solid_tris_adjacency[8][6] = { {18, 16, 19, 8, 20, 23}, {21, 19, 22, 11, 23, 14}, }; +#endif /* aligned with bone_octahedral_solid_tris */ static const float bone_octahedral_solid_normals[8][3] = { @@ -1673,9 +1681,6 @@ Gwn_Batch *DRW_cache_bone_octahedral_get(void) Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); GWN_vertbuf_data_alloc(vbo, 24); - Gwn_IndexBufBuilder elb; - GWN_indexbuf_init_ex(&elb, GWN_PRIM_TRIS_ADJ, 6 * 8, 24, false); - for (int i = 0; i < 8; i++) { GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]); GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][0]]); @@ -1686,17 +1691,37 @@ Gwn_Batch *DRW_cache_bone_octahedral_get(void) GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]); GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][2]]); GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]); - for (int j = 0; j < 6; ++j) { - GWN_indexbuf_add_generic_vert(&elb, bone_octahedral_solid_tris_adjacency[i][j]); - } } - SHC.drw_bone_octahedral = GWN_batch_create_ex(GWN_PRIM_TRIS_ADJ, vbo, GWN_indexbuf_build(&elb), - GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); + SHC.drw_bone_octahedral = GWN_batch_create_ex(GWN_PRIM_TRIS_ADJ, vbo, NULL, + GWN_BATCH_OWNS_VBO); } return SHC.drw_bone_octahedral; } +Gwn_Batch *DRW_cache_bone_octahedral_wire_get(void) +{ + if (!SHC.drw_bone_octahedral_wire) { + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_LINES_ADJ, 12, 24); + + for (int i = 0; i < 12; i++) { + GWN_indexbuf_add_line_adj_verts(&elb, + bone_octahedral_wire_lines_adjacency[i][0], + bone_octahedral_wire_lines_adjacency[i][1], + bone_octahedral_wire_lines_adjacency[i][2], + bone_octahedral_wire_lines_adjacency[i][3]); + } + + /* HACK Reuse vertex buffer. */ + Gwn_Batch *pos_nor_batch = DRW_cache_bone_octahedral_get(); + + SHC.drw_bone_octahedral_wire = GWN_batch_create_ex(GWN_PRIM_LINES_ADJ, pos_nor_batch->verts[0], GWN_indexbuf_build(&elb), + GWN_BATCH_OWNS_INDEX); + } + return SHC.drw_bone_octahedral_wire; +} + /* XXX TODO move that 1 unit cube to more common/generic place? */ static const float bone_box_verts[8][3] = { { 1.0f, 0.0f, 1.0f}, @@ -1760,6 +1785,13 @@ static const uint bone_box_solid_tris[12][3] = { * Store indices of generated verts from bone_box_solid_tris to define adjacency infos. * See bone_octahedral_solid_tris for more infos. **/ +static const uint bone_box_wire_lines_adjacency[12][4] = { + { 4, 0, 2, 11}, { 0, 2, 1, 8}, { 2, 1, 4, 14}, { 1, 4, 0, 20}, /* bottom */ + { 0, 11, 8, 14}, { 2, 8, 14, 20}, { 1, 14, 20, 11}, { 4, 20, 11, 8}, /* top */ + { 20, 0, 11, 2}, { 11, 2, 8, 1}, { 8, 1, 14, 4}, { 14, 4, 20, 0}, /* sides */ +}; + +#if 0 /* UNUSED */ static const uint bone_box_solid_tris_adjacency[12][6] = { { 0, 5, 1, 14, 2, 8}, { 3, 26, 4, 20, 5, 1}, @@ -1779,6 +1811,7 @@ static const uint bone_box_solid_tris_adjacency[12][6] = { {30, 9, 31, 15, 32, 35}, {33, 31, 34, 21, 35, 27}, }; +#endif /* aligned with bone_box_solid_tris */ static const float bone_box_solid_normals[12][3] = { @@ -1818,26 +1851,43 @@ Gwn_Batch *DRW_cache_bone_box_get(void) Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); GWN_vertbuf_data_alloc(vbo, 36); - Gwn_IndexBufBuilder elb; - GWN_indexbuf_init_ex(&elb, GWN_PRIM_TRIS_ADJ, 6 * 12, 36, false); - for (int i = 0; i < 12; i++) { for (int j = 0; j < 3; j++) { GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_box_solid_normals[i]); GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_box_smooth_normals[bone_box_solid_tris[i][j]]); GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_box_verts[bone_box_solid_tris[i][j]]); } - for (int j = 0; j < 6; ++j) { - GWN_indexbuf_add_generic_vert(&elb, bone_box_solid_tris_adjacency[i][j]); - } } - SHC.drw_bone_box = GWN_batch_create_ex(GWN_PRIM_TRIS_ADJ, vbo, GWN_indexbuf_build(&elb), - GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); + SHC.drw_bone_box = GWN_batch_create_ex(GWN_PRIM_TRIS_ADJ, vbo, NULL, + GWN_BATCH_OWNS_VBO); } return SHC.drw_bone_box; } +Gwn_Batch *DRW_cache_bone_box_wire_get(void) +{ + if (!SHC.drw_bone_box_wire) { + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_LINES_ADJ, 12, 36); + + for (int i = 0; i < 12; i++) { + GWN_indexbuf_add_line_adj_verts(&elb, + bone_box_wire_lines_adjacency[i][0], + bone_box_wire_lines_adjacency[i][1], + bone_box_wire_lines_adjacency[i][2], + bone_box_wire_lines_adjacency[i][3]); + } + + /* HACK Reuse vertex buffer. */ + Gwn_Batch *pos_nor_batch = DRW_cache_bone_box_get(); + + SHC.drw_bone_box_wire = GWN_batch_create_ex(GWN_PRIM_LINES_ADJ, pos_nor_batch->verts[0], GWN_indexbuf_build(&elb), + GWN_BATCH_OWNS_INDEX); + } + return SHC.drw_bone_box_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]) diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index b8f2beb6fdc..870c9e3a682 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -99,7 +99,9 @@ struct Gwn_Batch *DRW_cache_lightprobe_planar_get(void); /* Bones */ struct Gwn_Batch *DRW_cache_bone_octahedral_get(void); +struct Gwn_Batch *DRW_cache_bone_octahedral_wire_get(void); struct Gwn_Batch *DRW_cache_bone_box_get(void); +struct Gwn_Batch *DRW_cache_bone_box_wire_get(void); struct Gwn_Batch *DRW_cache_bone_envelope_solid_get(void); struct Gwn_Batch *DRW_cache_bone_envelope_outline_get(void); struct Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void); diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl index dc7ed5e202a..4fb6fe5a245 100644 --- a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl @@ -1,11 +1,9 @@ -/* TODO: See perf with multiple invocations. */ -layout(triangles_adjacency) in; -layout(triangle_strip, max_vertices = 16) out; +layout(lines_adjacency) in; +layout(triangle_strip, max_vertices = 6) out; in vec4 pPos[]; -in float vZ[]; -in float vFacing[]; +in vec3 vPos[]; in vec2 ssPos[]; in vec2 ssNor[]; in vec4 vColSize[]; @@ -22,21 +20,18 @@ vec2 compute_dir(vec2 v0, vec2 v1) return dir; } -void emit_edge(const ivec3 edges, vec2 thick, bool is_persp) +void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp) { - vec2 edge_dir = compute_dir(ssPos[edges.x], ssPos[edges.y]); - vec2 hidden_dir = normalize(ssPos[edges.z] - ssPos[edges.x]); - float fac = dot(-hidden_dir, edge_dir); - vec2 t = thick * (is_persp ? vZ[edges.x] : 1.0); - gl_Position = pPos[edges.x]; + vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0); + gl_Position = pPos[1]; EmitVertex(); gl_Position.xy += t * edge_dir * sign(fac); EmitVertex(); - t = thick * (is_persp ? vZ[edges.y] : 1.0); - gl_Position = pPos[edges.y]; + t = thick * (is_persp ? abs(vPos[2].z) : 1.0); + gl_Position = pPos[2]; EmitVertex(); gl_Position.xy += t * edge_dir * sign(fac); EmitVertex(); @@ -45,7 +40,7 @@ void emit_edge(const ivec3 edges, vec2 thick, bool is_persp) void emit_corner(const int e, vec2 thick, bool is_persp) { vec2 corner_dir = ssNor[e]; - vec2 t = thick * (is_persp ? vZ[e] : 1.0); + vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0); gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0); EmitVertex(); @@ -55,41 +50,31 @@ void main(void) { finalColor = vec4(vColSize[0].rgb, 1.0); - vec2 thick = vColSize[0].w * (lineThickness / viewportSize); bool is_persp = (ProjectionMatrix[3][3] == 0.0); - const ivec3 edges = ivec3(0, 2, 4); - vec4 facing = vec4(vFacing[1], vFacing[3], vFacing[5], vFacing[0]); - bvec4 do_edge = greaterThanEqual(facing, vec4(0.0)); + vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0); + vec3 v10 = vPos[0] - vPos[1]; + vec3 v12 = vPos[2] - vPos[1]; + vec3 v13 = vPos[3] - vPos[1]; - /* Only generate outlines from backfaces. */ - if (do_edge.w) + float fac1 = dot(view_vec, cross(v10, v12)); + float fac2 = dot(view_vec, cross(v12, v13)); + + /* If both adjacent verts are facing the camera the same way, + * then it isn't an outline edge. */ + if (sign(fac1) == sign(fac2)) return; - if (do_edge.x) { - emit_corner(edges.x, thick, is_persp); - emit_edge(edges.xyz, thick, is_persp); - } + vec2 thick = vColSize[0].w * (lineThickness / viewportSize); + vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]); - if (any(do_edge.xy)) { - emit_corner(edges.y, thick, is_persp); - } - - if (do_edge.y) { - emit_edge(edges.yzx, thick, is_persp); - } - else { - EndPrimitive(); - } - - if (any(do_edge.yz)) { - emit_corner(edges.z, thick, is_persp); - } - - if (do_edge.z) { - emit_edge(edges.zxy, thick, is_persp); - emit_corner(edges.x, thick, is_persp); - } + /* Take the farthest point to compute edge direction + * (avoid problems with point behind near plane). */ + vec2 hidden_point = (vPos[0].z < vPos[3].z) ? ssPos[0] : ssPos[3]; + vec2 hidden_dir = normalize(hidden_point - ssPos[1]); + emit_corner(1, thick, is_persp); + emit_edge(edge_dir, hidden_dir, thick, is_persp); + emit_corner(2, thick, is_persp); EndPrimitive(); } diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl index 0d09114579c..3e7a185bb62 100644 --- a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl @@ -15,8 +15,7 @@ in mat4 InstanceModelMatrix; in vec4 outlineColorSize; out vec4 pPos; -out float vZ; -out float vFacing; +out vec3 vPos; out vec2 ssPos; out vec2 ssNor; out vec4 vColSize; @@ -34,25 +33,15 @@ void main() mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); vec4 viewpos = ViewMatrix * (InstanceModelMatrix * vec4(pos, 1.0)); - pPos = ProjectionMatrix * viewpos; - vZ = abs(viewpos.z); - /* if perspective */ - vec3 V = (ProjectionMatrix[3][3] == 0.0) ? normalize(-viewpos.xyz) : vec3(0.0, 0.0, 1.0); + vPos = viewpos.xyz; + pPos = ProjectionMatrix * viewpos; /* TODO FIX: there is still a problem with this vector * when the bone is scaled or in persp mode. But it's * barelly visible at the outline corners. */ ssNor = normalize((NormalMatrix * snor).xy); - vec3 normal = normalize(NormalMatrix * nor); - /* Add a small bias to avoid loosing outline - * on faces orthogonal to the view. - * (test case: octahedral bone without rotation in front view.) */ - normal.z += 1e-6; - - vFacing = dot(V, normal); - ssPos = proj(pPos); vColSize = outlineColorSize;