diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-05-02 09:44:24 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-05-02 21:49:38 +0300 |
commit | 0ea329d32de1f4a137880941f648a97b3ad7874f (patch) | |
tree | 741e020b06e3b8adf774e1261c73fc6d01ef3964 /source/blender | |
parent | 73cb83d48fb9c81e064eedf6b12551c0a85d7536 (diff) |
Armature: Envelope: Revisit envelope drawing again.
Past shader was too slow and had bad artifacts. This method is much simpler
and eficient and only exhibit some popping when the raidus of the head/tail
is changed.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/draw/intern/draw_armature.c | 12 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 44 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/armature_envelope_vert.glsl | 84 |
3 files changed, 29 insertions, 111 deletions
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 5a3c03d5be2..ec2751d661b 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -189,12 +189,6 @@ static void drw_shgroup_bone_envelope_distance( head_sphere[3] += *distance; tail_sphere[3] = *radius_tail; tail_sphere[3] += *distance; - - /* Shader transform is nicer if tail is the biggest. */ - if (*radius_head > *radius_tail) { - swap_v4_v4(head_sphere, tail_sphere); - } - DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, head_sphere, tail_sphere, color, final_bonemat[0]); } } @@ -232,12 +226,6 @@ static void drw_shgroup_bone_envelope( /* Draw Body */ float tmp_sphere[4]; float len = len_v3v3(tail_sphere, head_sphere); - - /* Shader transform is nicer if tail is the biggest. */ - if (*radius_head > *radius_tail) { - swap_v4_v4(head_sphere, tail_sphere); - } - float fac_head = (len - head_sphere[3]) / len; float fac_tail = (len - tail_sphere[3]) / len; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index aa21bb7214a..be4c1783aff 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -85,7 +85,6 @@ static struct DRWShapeCache { Gwn_Batch *drw_bone_box_wire; Gwn_Batch *drw_bone_wire_wire; Gwn_Batch *drw_bone_envelope; - Gwn_Batch *drw_bone_envelope_distance; Gwn_Batch *drw_bone_envelope_outline; Gwn_Batch *drw_bone_point; Gwn_Batch *drw_bone_point_wire; @@ -1881,20 +1880,18 @@ Gwn_Batch *DRW_cache_bone_wire_wire_outline_get(void) * 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[2] = sinf(lat) * sinf(lon); + r_nor[1] = sinf(lat) * sinf(lon); + r_nor[2] = cosf(lat); } Gwn_Batch *DRW_cache_bone_envelope_solid_get(void) { if (!SHC.drw_bone_envelope) { const int lon_res = 24; - const int lat_res = 16; + const int lat_res = 24; 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 }; @@ -1905,14 +1902,16 @@ 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 + 1) * 2) * lon_res * 2); + GWN_vertbuf_data_alloc(vbo, ((lat_res + 1) * 2) * lon_res * 1); - float lon = lon_inc; + float lon = 0.0f; for (int i = 0; i < lon_res; i++, lon += lon_inc) { float lat = 0.0f; float co1[4], co2[4]; co1[3] = co2[3] = 0.0f; + /* Note: the poles are duplicated on purpose, to restart the strip. */ + /* 1st sphere */ for (int j = 0; j < lat_res; j++, lat += lat_inc) { benv_lat_lon_to_co(lat, lon, co1); @@ -1921,36 +1920,13 @@ Gwn_Batch *DRW_cache_bone_envelope_solid_get(void) GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1); GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2); } - /* 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; + /* Closing the loop */ + benv_lat_lon_to_co(M_PI, lon, co1); + benv_lat_lon_to_co(M_PI, lon + lon_inc, co2); - /* 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_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); diff --git a/source/blender/draw/modes/shaders/armature_envelope_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_vert.glsl index fbce8ca69dd..6de842fdcb2 100644 --- a/source/blender/draw/modes/shaders/armature_envelope_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_envelope_vert.glsl @@ -1,4 +1,5 @@ +uniform mat4 ViewMatrix; uniform mat4 ViewMatrixInverse; uniform mat4 ViewProjectionMatrix; @@ -15,80 +16,33 @@ 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. */ + vec3 bone_vec = tailSphere.xyz - headSphere.xyz; + float bone_len = max(1e-8, sqrt(dot(bone_vec, bone_vec))); + float bone_lenrcp = 1.0 / bone_len; + float sinb = (tailSphere.w - headSphere.w) * bone_lenrcp; - 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 y_axis = bone_vec * bone_lenrcp; 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. */ - } + vec3 x_axis = cross(y_axis, z_axis); /* cannot trust xAxis to be orthogonal. */ - /* p is vertex position in world space */ - vec3 p = mat3(x_axis, y_axis, z_axis) * sp; - p += headSphere.xyz; + vec3 sp, nor; + nor = sp = pos.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; + /* In bone space */ + bool is_head = (pos.z < -sinb); + sp *= (is_head) ? headSphere.w : tailSphere.w; + sp.z += (is_head) ? 0.0 : bone_len; - /* 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); + /* Convert to world space */ + mat3 bone_mat = mat3(x_axis, y_axis, z_axis); + sp = bone_mat * sp.xzy + headSphere.xyz; + nor = bone_mat * nor.xzy; - 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); + normalView = mat3(ViewMatrix) * nor; - gl_Position = ViewProjectionMatrix * vec4(p, 1.0); + gl_Position = ViewProjectionMatrix * vec4(sp, 1.0); finalColor = color; } |