[Bf-blender-cvs] [b171e40d0c5] greasepencil-refactor: GPencil: Refactor: Fix outline depth mixing

Clément Foucault noreply at git.blender.org
Wed Jan 8 14:59:52 CET 2020


Commit: b171e40d0c541d13ffd10cc833d13edb0190b292
Author: Clément Foucault
Date:   Wed Jan 8 14:56:57 2020 +0100
Branches: greasepencil-refactor
https://developer.blender.org/rBb171e40d0c541d13ffd10cc833d13edb0190b292

GPencil: Refactor: Fix outline depth mixing

This uses a costly depth reprojection in the fragment shader. This might
get optimized a bit in the future.

Unfortunately it's the only way to get the same accurate depth as what the
gpencil engine outputs.

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

M	source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
M	source/blender/draw/engines/overlay/overlay_outline.c
M	source/blender/draw/engines/overlay/overlay_shader.c
M	source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl

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

diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index 08319ecd405..b1d851a394f 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -176,12 +176,12 @@ float stroke_round_cap_mask(vec2 p1, vec2 p2, float thickness)
 
 #endif
 
-#ifdef GPU_VERTEX_SHADER
-
 /* TODO UBO */
 uniform vec2 sizeViewport;
 uniform vec2 sizeViewportInv;
 
+#ifdef GPU_VERTEX_SHADER
+
 /* Per Object */
 uniform bool strokeOrder3d;
 uniform float thicknessScale;
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index 83385239ba7..72755e480f5 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -25,13 +25,66 @@
 #include "BKE_global.h"
 #include "BKE_gpencil.h"
 
-// #include "DNA_lightprobe_types.h"
+#include "BKE_object.h"
+
 #include "DNA_gpencil_types.h"
 
 #include "UI_resources.h"
 
 #include "overlay_private.h"
 
+/* Modified copy of gpencil_object_cache_add().
+ * Returns the normal plane in ndc space. */
+static void gpencil_depth_plane(Object *ob, float r_plane[4])
+{
+  /* TODO put that into private data. */
+  float viewinv[4][4];
+  DRW_view_viewmat_get(NULL, viewinv, true);
+  float *camera_z_axis = viewinv[2];
+  float *camera_pos = viewinv[3];
+
+  /* Find the normal most likely to represent the gpObject. */
+  /* TODO: This does not work quite well if you use
+   * strokes not aligned with the object axes. Maybe we could try to
+   * compute the minimum axis of all strokes. But this would be more
+   * computationaly heavy and should go into the GPData evaluation. */
+  BoundBox *bbox = BKE_object_boundbox_get(ob);
+  /* Convert bbox to matrix */
+  float mat[4][4], size[3], center[3];
+  BKE_boundbox_calc_size_aabb(bbox, size);
+  BKE_boundbox_calc_center_aabb(bbox, center);
+  unit_m4(mat);
+  copy_v3_v3(mat[3], center);
+  /* Avoid division by 0.0 later. */
+  add_v3_fl(size, 1e-8f);
+  rescale_m4(mat, size);
+  /* BBox space to World. */
+  mul_m4_m4m4(mat, ob->obmat, mat);
+  /* BBox center in world space. */
+  copy_v3_v3(center, mat[3]);
+  /* View Vector. */
+  if (DRW_view_is_persp_get(NULL)) {
+    /* BBox center to camera vector. */
+    sub_v3_v3v3(r_plane, camera_pos, mat[3]);
+  }
+  else {
+    copy_v3_v3(r_plane, camera_z_axis);
+  }
+  /* World to BBox space. */
+  invert_m4(mat);
+  /* Normalize the vector in BBox space. */
+  mul_mat3_m4_v3(mat, r_plane);
+  normalize_v3(r_plane);
+
+  transpose_m4(mat);
+  /* mat is now a "normal" matrix which will transform
+   * BBox space normal to world space.  */
+  mul_mat3_m4_v3(mat, r_plane);
+  normalize_v3(r_plane);
+
+  plane_from_point_normal_v3(r_plane, center, r_plane);
+}
+
 void OVERLAY_outline_init(OVERLAY_Data *vedata)
 {
   OVERLAY_FramebufferList *fbl = vedata->fbl;
@@ -119,6 +172,7 @@ typedef struct iterData {
   DRWShadingGroup *stroke_grp;
   DRWShadingGroup *fill_grp;
   int cfra;
+  float plane[4];
 } iterData;
 
 static void gp_layer_cache_populate(bGPDlayer *gpl,
@@ -130,6 +184,7 @@ static void gp_layer_cache_populate(bGPDlayer *gpl,
   bGPdata *gpd = (bGPdata *)iter->ob->data;
 
   const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
+  const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
 
   float object_scale = mat4_to_scale(iter->ob->obmat);
   /* Negate thickness sign to tag that strokes are in screen space.
@@ -137,12 +192,13 @@ static void gp_layer_cache_populate(bGPDlayer *gpl,
   float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
 
   DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp);
-  DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", true);
+  DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", is_stroke_order_3d);
   DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get());
   DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get());
   DRW_shgroup_uniform_float_copy(grp, "thicknessScale", object_scale);
   DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
   DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
+  DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
 }
 
 static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
@@ -199,6 +255,10 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
       .cfra = pd->cfra,
   };
 
+  if (gpd->draw_mode == GP_DRAWMODE_2D) {
+    gpencil_depth_plane(ob, iter.plane);
+  }
+
   BKE_gpencil_visible_stroke_iter(
       ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra);
 }
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index 1d906a6fc38..db3611671c5 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -1041,7 +1041,8 @@ GPUShader *OVERLAY_shader_outline_prepass_gpencil(void)
                                  datatoc_gpu_shader_common_obinfos_lib_glsl,
                                  datatoc_outline_prepass_vert_glsl,
                                  NULL},
-        .frag = (const char *[]){datatoc_gpencil_common_lib_glsl,
+        .frag = (const char *[]){datatoc_common_view_lib_glsl,
+                                 datatoc_gpencil_common_lib_glsl,
                                  datatoc_outline_prepass_frag_glsl,
                                  NULL},
         .defs = (const char *[]){sh_cfg->def,
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
index aadddd1e4da..9b11c02fd99 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
@@ -1,15 +1,44 @@
 
+uniform vec4 gpDepthPlane;
+
 flat in int objectId;
 
 /* using uint because 16bit uint can contain more ids than int. */
 out uint outId;
 
+vec3 ray_plane_intersection(vec3 ray_ori, vec3 ray_dir, vec4 plane)
+{
+  float d = dot(plane.xyz, ray_dir);
+  vec3 plane_co = plane.xyz * (-plane.w / dot(plane.xyz, plane.xyz));
+  vec3 h = ray_ori - plane_co;
+  float lambda = -dot(plane.xyz, h) / ((abs(d) < 1e-8) ? 1e-8 : d);
+  return ray_ori + ray_dir * lambda;
+}
+
 void main()
 {
 #ifdef USE_GPENCIL
   if (stroke_round_cap_mask(strokePt1, strokePt2, strokeThickness) < 0.001) {
     discard;
   }
+
+  if (depth != -1.0) {
+    /* Stroke order 2D. */
+    bool is_persp = ProjectionMatrix[3][3] == 0.0;
+    vec2 uvs = vec2(gl_FragCoord.xy) * sizeViewportInv;
+    vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0;
+    vec4 pos_world = ViewProjectionMatrixInverse * vec4(pos_ndc, 1.0);
+    vec3 pos = pos_world.xyz / pos_world.w;
+
+    vec3 ray_ori = pos;
+    vec3 ray_dir = (is_persp) ? (ViewMatrixInverse[3].xyz - pos) : ViewMatrixInverse[2].xyz;
+    vec3 isect = ray_plane_intersection(ray_ori, ray_dir, gpDepthPlane);
+    vec4 ndc = point_world_to_ndc(isect);
+    gl_FragDepth = (ndc.z / ndc.w) * 0.5 + 0.5;
+  }
+  else {
+    gl_FragDepth = gl_FragCoord.z;
+  }
 #endif
 
   outId = uint(objectId);



More information about the Bf-blender-cvs mailing list