diff options
-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; } |