[Bf-blender-cvs] [5f7259a0013] master: GPencil: New Outline modifier

Antonio Vazquez noreply at git.blender.org
Tue Sep 27 17:07:12 CEST 2022


Commit: 5f7259a0013bdfeff681b9e80202c0c281937bbd
Author: Antonio Vazquez
Date:   Tue Sep 27 16:42:00 2022 +0200
Branches: master
https://developer.blender.org/rB5f7259a0013bdfeff681b9e80202c0c281937bbd

GPencil: New Outline modifier

This modifier converts any stroke (no fill strokes) into perimeter
from camera view.  Also, it's possible to define an alternative 
material for the outline.

There is an option to include a target object to manipulate the start 
point of the strokes. The start point will be the nearest point 
to the target object.

Reviewed By: mendio, frogstomp

Maniphest Tasks: T100826

Differential Revision: https://developer.blender.org/D15882

Note: Icon will be updated in T101155

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

M	source/blender/gpencil_modifiers/CMakeLists.txt
M	source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
M	source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
A	source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
M	source/blender/makesdna/DNA_gpencil_modifier_defaults.h
M	source/blender/makesdna/DNA_gpencil_modifier_types.h
M	source/blender/makesdna/intern/dna_defaults.c
M	source/blender/makesrna/intern/rna_gpencil_modifier.c

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

diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 5ef9ae1bbc6..8dbac602c06 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
   intern/MOD_gpencilnoise.c
   intern/MOD_gpenciloffset.c
   intern/MOD_gpencilopacity.c
+  intern/MOD_gpenciloutline.c
   intern/MOD_gpencilshrinkwrap.c
   intern/MOD_gpencilsimplify.c
   intern/MOD_gpencilsmooth.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index 9025fecacd8..2f3cf4d2312 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -20,6 +20,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Color;
 extern GpencilModifierTypeInfo modifierType_Gpencil_Array;
 extern GpencilModifierTypeInfo modifierType_Gpencil_Build;
 extern GpencilModifierTypeInfo modifierType_Gpencil_Opacity;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Outline;
 extern GpencilModifierTypeInfo modifierType_Gpencil_Lattice;
 extern GpencilModifierTypeInfo modifierType_Gpencil_Length;
 extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index bd8fd9f72ad..d4ada842d0b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -41,6 +41,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
   INIT_GP_TYPE(Array);
   INIT_GP_TYPE(Build);
   INIT_GP_TYPE(Opacity);
+  INIT_GP_TYPE(Outline);
   INIT_GP_TYPE(Lattice);
   INIT_GP_TYPE(Length);
   INIT_GP_TYPE(Mirror);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
new file mode 100644
index 00000000000..9a0ee4d9d92
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_ui_common.h"
+#include "MOD_gpencil_util.h"
+
+static void initData(GpencilModifierData *md)
+{
+  OutlineGpencilModifierData *gpmd = (OutlineGpencilModifierData *)md;
+
+  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+  MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(OutlineGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+  BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static void free_old_strokes(Depsgraph *depsgraph, Object *ob, bGPdata *gpd)
+{
+  Scene *scene = DEG_get_evaluated_scene(depsgraph);
+  /* Free old strokes. */
+  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+    bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+    if (gpf == NULL) {
+      continue;
+    }
+    LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+      if (gps->flag & GP_STROKE_TAG) {
+        BLI_remlink(&gpf->strokes, gps);
+        BKE_gpencil_free_stroke(gps);
+      }
+    }
+  }
+}
+
+static void convert_stroke(GpencilModifierData *md,
+                           Object *ob,
+                           bGPDlayer *gpl,
+                           bGPDframe *gpf,
+                           bGPDstroke *gps,
+                           float viewmat[4][4],
+                           float diff_mat[4][4])
+{
+  OutlineGpencilModifierData *mmd = (OutlineGpencilModifierData *)md;
+  bGPdata *gpd = (bGPdata *)ob->data;
+  const bool keep = (mmd->flag & GP_OUTLINE_KEEP_SHAPE) != 0;
+
+  if (!is_stroke_affected_by_modifier(ob,
+                                      mmd->layername,
+                                      mmd->material,
+                                      mmd->pass_index,
+                                      mmd->layer_pass,
+                                      1,
+                                      gpl,
+                                      gps,
+                                      mmd->flag & GP_OUTLINE_INVERT_LAYER,
+                                      mmd->flag & GP_OUTLINE_INVERT_PASS,
+                                      mmd->flag & GP_OUTLINE_INVERT_LAYERPASS,
+                                      mmd->flag & GP_OUTLINE_INVERT_MATERIAL)) {
+    return;
+  }
+
+  MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+  const bool is_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
+  /* Only strokes type, no fill strokes. */
+  if (!is_stroke) {
+    return;
+  }
+
+  /* Duplicate the stroke to apply any layer thickness change. */
+  bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
+
+  /* Apply layer thickness change. */
+  gps_duplicate->thickness += gpl->line_change;
+  /* Apply object scale to thickness. */
+  gps_duplicate->thickness *= mat4_to_scale(ob->obmat);
+  CLAMP_MIN(gps_duplicate->thickness, 1.0f);
+
+  /* Stroke. */
+  const float ovr_thickness = keep ? mmd->thickness : 0.0f;
+  bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
+      viewmat, gpd, gpl, gps_duplicate, mmd->subdiv, diff_mat, ovr_thickness);
+  gps_perimeter->flag &= ~GP_STROKE_SELECT;
+  gps_perimeter->runtime.gps_orig = gps->runtime.gps_orig;
+
+  /* Assign material. */
+  if (mmd->outline_material) {
+    Material *ma = mmd->outline_material;
+    int mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob, ma->id.name + 2);
+    if (mat_idx > -1) {
+      gps_perimeter->mat_nr = mat_idx;
+    }
+    else {
+      gps_perimeter->mat_nr = gps->mat_nr;
+    }
+  }
+  else {
+    gps_perimeter->mat_nr = gps->mat_nr;
+  }
+
+  /* Sample stroke. */
+  if (mmd->sample_length > 0.0f) {
+    BKE_gpencil_stroke_sample(gpd, gps_perimeter, mmd->sample_length, false, 0);
+  }
+  /* Set stroke thickness. */
+  gps_perimeter->thickness = mmd->thickness;
+
+  /* Set pressure constant. */
+  int orig_idx = -1;
+  float min_distance = FLT_MAX;
+  bGPDspoint *pt;
+  for (int i = 0; i < gps_perimeter->totpoints; i++) {
+    pt = &gps_perimeter->points[i];
+    pt->pressure = 1.0f;
+    pt->runtime.pt_orig = NULL;
+    /* If any target object is defined, find the nearest point. */
+    if (mmd->object) {
+      float wpt[3];
+      mul_v3_m4v3(wpt, diff_mat, &pt->x);
+      float dist = len_squared_v3v3(wpt, mmd->object->loc);
+      if (dist < min_distance) {
+        min_distance = dist;
+        orig_idx = i;
+      }
+    }
+  }
+
+  if (orig_idx > 0) {
+    BKE_gpencil_stroke_start_set(gps_perimeter, orig_idx);
+    BKE_gpencil_stroke_geometry_update(gpd, gps_perimeter);
+  }
+
+  /* Add perimeter stroke to frame. */
+  BLI_insertlinkafter(&gpf->strokes, gps, gps_perimeter);
+
+  /* Free Temp stroke. */
+  BKE_gpencil_free_stroke(gps_duplicate);
+
+  /* Tag original stroke to be removed. */
+  gps->flag |= GP_STROKE_TAG;
+}
+
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+  bGPdata *gpd = (bGPdata *)ob->data;
+
+  /* Calc camera view matrix. */
+  Scene *scene = DEG_get_evaluated_scene(depsgraph);
+  /* Ensure the camera is the right one. */
+  BKE_scene_camera_switch_update(scene);
+
+  if (!scene->camera) {
+    return;
+  }
+  Object *cam_ob = scene->camera;
+  float viewmat[4][4];
+  invert_m4_m4(viewmat, cam_ob->obmat);
+
+  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+    bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+    if (gpf == NULL) {
+      continue;
+    }
+    /* Prepare transform matrix. */
+    float diff_mat[4][4];
+    BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
+
+    LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+      convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
+    }
+  }
+
+  /* Delete original strokes. */
+  free_old_strokes(depsgraph, ob, gpd);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+                         Depsgraph *depsgraph,
+                         GpencilModifierData *md,
+                         Object *ob)
+{
+  Scene *scene = DEG_get_evaluated_scene(depsgraph);
+  bGPdata *gpd = ob->data;
+  int oldframe = (int)DEG_get_ctime(depsgraph);
+
+  /* Calc camera view matrix. */
+  if (!scene->camera) {
+    return;
+  }
+  Object *cam_ob = scene->camera;
+  float viewmat[4][4];
+
+  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+    LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+      scene->r.cfra = gpf->framenum;
+      BKE_scene_graph_update_for_newframe(depsgraph);
+      /* Ensure the camera is the right one. */
+      BKE_scene_camera_switch_update(scene);
+      invert_m4_m4(viewmat, cam_ob->obmat);
+
+      /* Prepare transform matrix. */
+      float diff_mat[4][4];
+      BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
+
+      /* Compute all strokes of this frame. */
+      LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+        convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
+      }
+    }
+  }
+
+  /* Delete original strokes. */
+  free_old_strokes(depsgraph, ob, gpd);
+
+  /* Return frame state and DB to original 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list