[Bf-blender-cvs] [e42f30d45e3] greasepencil-refactor: GPencil: Refactor: Implement rounded caps

Clément Foucault noreply at git.blender.org
Sat Dec 21 21:11:34 CET 2019


Commit: e42f30d45e387b5eb8f4b95aaf877149083e1fb2
Author: Clément Foucault
Date:   Sat Dec 21 21:11:19 2019 +0100
Branches: greasepencil-refactor
https://developer.blender.org/rBe42f30d45e387b5eb8f4b95aaf877149083e1fb2

GPencil: Refactor: Implement rounded caps

This was a bit tricky to do it cleanly. We create a mask using the stroke
point coordinates and extend the stroke geometry to uncover the mask if the
round caps are needed.

This was needed to be able to workaround the projection artifact of uvs.

Note that this code could be used for stroke shape in the future.

===================================================================

M	source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
M	source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
M	source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl

===================================================================

diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
index fbf2beb809e..4aeffbd62a3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -112,18 +112,21 @@ static int gpencil_stroke_is_cyclic(const bGPDstroke *gps)
 static void gpencil_buffer_add_point(
     gpStrokeVert *verts, const bGPDstroke *gps, const bGPDspoint *pt, int v, bool is_endpoint)
 {
+  /* Note: we use the sign of stength and thickness to pass cap flag. */
+  const bool round_cap0 = (gps->caps[0] == GP_STROKE_CAP_ROUND);
+  const bool round_cap1 = (gps->caps[1] == GP_STROKE_CAP_ROUND);
   gpStrokeVert *vert = &verts[v];
   copy_v3_v3(vert->pos, &pt->x);
   copy_v2_v2(vert->uv, pt->uv_fill);
   copy_v4_v4(vert->col, pt->mix_color);
-  vert->strength = pt->strength;
+  vert->strength = (round_cap0) ? pt->strength : -pt->strength;
   vert->u_stroke = pt->uv_fac;
   vert->stroke_id = gps->runtime.stroke_start;
   vert->point_id = v;
   /* Rotation are in [-90°..90°] range, so we can encode the sign of the angle + the cosine
    * because the cosine will always be positive. */
   vert->v_rot = cosf(pt->uv_rot) * signf(pt->uv_rot);
-  vert->thickness = gps->thickness * pt->pressure;
+  vert->thickness = gps->thickness * pt->pressure * (round_cap1 ? 1.0 : -1.0);
   /* Tag endpoint material to -1 so they get discarded by vertex shader. */
   vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GPENCIL_MATERIAL_BUFFER_LEN);
 }
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
index 8b5371164ee..da144894698 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
@@ -8,6 +8,9 @@ in vec4 finalColorMul;
 in vec4 finalColorAdd;
 in vec3 finalPos;
 in vec2 finalUvs;
+noperspective in float strokeThickness;
+flat in vec2 strokePt1;
+flat in vec2 strokePt2;
 flat in int matFlag;
 flat in float depth;
 
@@ -62,6 +65,26 @@ vec3 gpencil_lighting(void)
   return clamp(light_accum, 0.0, 1e10);
 }
 
+float stroke_round_cap_mask()
+{
+  /* We create our own uv space to avoid issues with triangulation and linear
+   * interpolation artifacts. */
+  vec2 line = strokePt2.xy - strokePt1.xy;
+  vec2 pos = gl_FragCoord.xy - strokePt1.xy;
+  float line_len = sqrt(length_squared(line));
+  float half_line_len = line_len * 0.5;
+  /* Normalize */
+  line /= line_len;
+  /* Create a uv space that englobe the whole segment into a capsule. */
+  vec2 uv_end;
+  uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0);
+  uv_end.y = dot(vec2(-line.y, line.x), pos);
+  /* Divide by stroke radius. */
+  uv_end /= strokeThickness;
+
+  return (length_squared(uv_end) > 0.25) ? 0.0 : 1.0;
+}
+
 void main()
 {
   vec4 col;
@@ -86,6 +109,8 @@ void main()
 
   fragColor.rgb *= gpencil_lighting();
 
+  fragColor *= stroke_round_cap_mask();
+
   if (GP_FLAG_TEST(matFlag, GP_STROKE_DOTS)) {
     const float rad_sqr_inv = 1.0 / 0.25;
     float dist = 1.0 - rad_sqr_inv * length_squared(finalUvs - 0.5);
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
index ce2af4e5bc6..6dc667230b2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -15,8 +15,10 @@ uniform float thicknessOffset;
 uniform float vertexColorOpacity;
 uniform vec4 layerTint;
 
+in vec4 ma;
 in vec4 ma1;
 in vec4 ma2;
+in vec4 ma3;
 #define strength1 ma1.y
 #define strength2 ma2.y
 #define stroke_id1 ma1.z
@@ -39,6 +41,9 @@ out vec4 finalColorMul;
 out vec4 finalColorAdd;
 out vec3 finalPos;
 out vec2 finalUvs;
+noperspective out float strokeThickness;
+flat out vec2 strokePt1;
+flat out vec2 strokePt2;
 flat out int matFlag;
 flat out float depth;
 
@@ -80,6 +85,17 @@ vec2 safe_normalize(vec2 v)
   }
 }
 
+vec2 safe_normalize_len(vec2 v, out float len)
+{
+  len = sqrt(dot(v, v));
+  if (len > 0.0) {
+    return v / len;
+  }
+  else {
+    return vec2(0.0);
+  }
+}
+
 float stroke_thickness_modulate(float thickness)
 {
   /* Modify stroke thickness by object and layer factors.-*/
@@ -162,12 +178,15 @@ void stroke_vertex()
   vec2 ss1 = project_to_screenspace(ndc1);
   vec2 ss2 = project_to_screenspace(ndc2);
   /* Screenspace Lines tangents. */
-  vec2 line = safe_normalize(ss2 - ss1);
+  float line_len;
+  vec2 line = safe_normalize_len(ss2 - ss1, line_len);
   vec2 line_adj = safe_normalize((x == -1.0) ? (ss1 - ss_adj) : (ss_adj - ss2));
 
-  float thickness = (use_curr) ? thickness1 : thickness2;
+  float thickness = abs((use_curr) ? thickness1 : thickness2);
   thickness = stroke_thickness_modulate(thickness);
 
+  finalUvs = vec2(x, y) * 0.5 + 0.5;
+
   if (is_dot) {
     vec2 x_axis;
     vec2 y_axis;
@@ -186,6 +205,9 @@ void stroke_vertex()
     y_axis = rotate_90deg(x_axis);
 
     gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * thickness;
+
+    strokePt1 = strokePt2 = vec2(0.0);
+    strokeThickness = 1e18;
   }
   else {
     /* Mitter tangent vector. */
@@ -197,11 +219,27 @@ void stroke_vertex()
 
     vec2 miter = rotate_90deg(miter_tan);
 
-    gl_Position.xy += miter * sizeViewportInv.xy * (thickness * y);
+    strokePt1.xy = ss1;
+    strokePt2.xy = ss2;
+    strokeThickness = thickness / gl_Position.w;
+
+    /* Reminder: we packed the cap flag into the sign of stength and thickness sign. */
+    bool is_stroke_start = (ma.x == -1.0 && x == -1.0 && strength1 > 0.0);
+    bool is_stroke_end = (ma3.x == -1.0 && x == 1.0 && thickness1 > 0.0);
+
+    vec2 screen_ofs = miter * y;
+
+    if (is_stroke_start || is_stroke_end) {
+      screen_ofs += miter_tan * x * 2.0;
+    }
+
+    gl_Position.xy += screen_ofs * sizeViewportInv.xy * thickness;
+
+    finalUvs.x = (use_curr) ? uv1.z : uv2.z;
   }
 
   vec4 vert_col = (use_curr) ? col1 : col2;
-  float vert_strength = (use_curr) ? strength1 : strength2;
+  float vert_strength = abs((use_curr) ? strength1 : strength2);
   vec4 stroke_col = materials[m].stroke_color;
   float mix_tex = materials[m].stroke_texture_mix;
 
@@ -209,12 +247,6 @@ void stroke_vertex()
 
   matFlag = materials[m].flag & ~GP_FILL_FLAGS;
 
-  finalUvs = vec2(x, y) * 0.5 + 0.5;
-
-  if (!is_dot) {
-    finalUvs.x = (use_curr) ? uv1.z : uv2.z;
-  }
-
   if (strokeOrder3d) {
     /* Use the fragment depth (see fragment shader). */
     depth = -1.0;
@@ -257,6 +289,9 @@ void fill_vertex()
   mat2x2 rot_scale = mat2x2(materials[m].fill_uv_rot_scale.xy, materials[m].fill_uv_rot_scale.zw);
   finalUvs = rot_scale * uv1.xy + loc;
 
+  strokeThickness = 1e18;
+  strokePt1 = strokePt2 = vec2(0.0);
+
   if (strokeOrder3d) {
     /* Use the fragment depth (see fragment shader). */
     depth = -1.0;



More information about the Bf-blender-cvs mailing list