Armature: Modify Shape outline shader to use Line adjacency instead of tri.

This is much faster and simpler. This is also to make it compatible with
custom bone shape in the future.
This commit is contained in:
Clément Foucault 2018-05-20 22:48:35 +02:00
parent 581b021a1f
commit 6b38fa8cab
5 changed files with 102 additions and 76 deletions

View File

@ -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) {

View File

@ -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])

View File

@ -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);

View File

@ -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();
}

View File

@ -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;