Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110t@outlook.com>2019-11-14 21:18:23 +0300
committerAntonio Vazquez <blendergit@gmail.com>2019-11-14 21:24:49 +0300
commit91248876e517983531c44ffc1692674684c67eed (patch)
treeb2e1bf063dedac5103a8105c50cea6ca80335b18 /source/blender/gpencil_modifiers
parent8ff9eb97fb7c0e25acaa051ea8ae196c932b10b6 (diff)
GPencil MultiStroke modifier
This patch includes a modifiers that developed for NPR rendering. - MultiStroke modifier that generates multiple strokes around the original ones. Differential Revision: https://developer.blender.org/D5795
Diffstat (limited to 'source/blender/gpencil_modifiers')
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c350
4 files changed, 353 insertions, 0 deletions
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 41543448a15..44335f4da25 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
intern/MOD_gpencilhook.c
intern/MOD_gpencillattice.c
intern/MOD_gpencilmirror.c
+ intern/MOD_gpencilmultiply.c
intern/MOD_gpencilnoise.c
intern/MOD_gpenciloffset.c
intern/MOD_gpencilopacity.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index 9fc00754744..f5c064c1c07 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -42,6 +42,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Hook;
extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
extern GpencilModifierTypeInfo modifierType_Gpencil_Armature;
extern GpencilModifierTypeInfo modifierType_Gpencil_Time;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Multiply;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 2d1a845330b..16e585705df 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -71,6 +71,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Offset);
INIT_GP_TYPE(Armature);
INIT_GP_TYPE(Time);
+ INIT_GP_TYPE(Multiply);
#undef INIT_GP_TYPE
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
new file mode 100644
index 00000000000..98988783862
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -0,0 +1,350 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilstrokes.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
+#include "BLI_alloca.h"
+
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_layer.h"
+#include "BKE_library_query.h"
+#include "BKE_collection.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
+ mmd->duplications = 3;
+ mmd->distance = 0.1f;
+ mmd->split_angle = 1.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void splitStroke(bGPDframe *gpf, bGPDstroke *gps, float split_angle)
+{
+ bGPDspoint *pt = gps->points;
+ bGPDstroke *new_gps = gps;
+ int i;
+ volatile float angle;
+
+ if (split_angle <= FLT_EPSILON) {
+ return;
+ }
+
+ for (i = 1; i < new_gps->totpoints - 1; i++) {
+ angle = angle_v3v3v3(&pt[i - 1].x, &pt[i].x, &pt[i + 1].x);
+ if (angle < split_angle) {
+ if (BKE_gpencil_split_stroke(gpf, new_gps, i, &new_gps)) {
+ pt = new_gps->points;
+ i = 0;
+ continue; /* then i == 1 again */
+ }
+ }
+ }
+}
+
+static void minter_v3_v3v3v3_ref(
+ float *result, float *left, float *middle, float *right, float *stroke_normal)
+{
+ float left_arm[3], right_arm[3], inter1[3], inter2[3];
+ float minter[3];
+ if (left) {
+ sub_v3_v3v3(left_arm, middle, left);
+ cross_v3_v3v3(inter1, stroke_normal, left_arm);
+ }
+ if (right) {
+ sub_v3_v3v3(right_arm, right, middle);
+ cross_v3_v3v3(inter2, stroke_normal, right_arm);
+ }
+ if (!left) {
+ normalize_v3(inter2);
+ copy_v3_v3(result, inter2);
+ return;
+ }
+
+ if (!right) {
+ normalize_v3(inter1);
+ copy_v3_v3(result, inter1);
+ return;
+ }
+
+ interp_v3_v3v3(minter, inter1, inter2, 0.5);
+ normalize_v3(minter);
+ copy_v3_v3(result, minter);
+}
+
+static void duplicateStroke(bGPDframe *gpf,
+ bGPDstroke *gps,
+ int count,
+ float dist,
+ float offset,
+ ListBase *results,
+ int fading,
+ float fading_center,
+ float fading_thickness,
+ float fading_opacity)
+{
+ int i;
+ bGPDstroke *new_gps;
+ float stroke_normal[3];
+ float minter[3];
+ bGPDspoint *pt;
+ float offset_factor;
+ float thickness_factor;
+ float opacity_factor;
+
+ BKE_gpencil_stroke_normal(gps, stroke_normal);
+ if (len_v3(stroke_normal) < FLT_EPSILON) {
+ add_v3_fl(stroke_normal, 1);
+ normalize_v3(stroke_normal);
+ }
+
+ float *t1_array = MEM_callocN(sizeof(float) * 3 * gps->totpoints,
+ "duplicate_temp_result_array_1");
+ float *t2_array = MEM_callocN(sizeof(float) * 3 * gps->totpoints,
+ "duplicate_temp_result_array_2");
+
+ pt = gps->points;
+
+ for (int j = 0; j < gps->totpoints; j++) {
+ if (j == 0) {
+ minter_v3_v3v3v3_ref(minter, NULL, &pt[j].x, &pt[j + 1].x, stroke_normal);
+ }
+ else if (j == gps->totpoints - 1) {
+ minter_v3_v3v3v3_ref(minter, &pt[j - 1].x, &pt[j].x, NULL, stroke_normal);
+ }
+ else {
+ minter_v3_v3v3v3_ref(minter, &pt[j - 1].x, &pt[j].x, &pt[j + 1].x, stroke_normal);
+ }
+ mul_v3_fl(minter, dist);
+ add_v3_v3v3(&t1_array[j * 3], &pt[j].x, minter);
+ sub_v3_v3v3(&t2_array[j * 3], &pt[j].x, minter);
+ }
+
+ /* This ensures the original stroke is the last one to be processed. */
+ for (i = count - 1; i >= 0; i--) {
+ if (i != 0) {
+ new_gps = BKE_gpencil_stroke_duplicate(gps);
+ new_gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ BLI_addtail(results, new_gps);
+ }
+ else {
+ new_gps = gps;
+ }
+
+ pt = new_gps->points;
+
+ if (count == 1) {
+ offset_factor = 0;
+ }
+ else {
+ offset_factor = (float)i / (float)(count - 1);
+ }
+
+ if (fading) {
+ thickness_factor = (offset_factor > fading_center) ?
+ (interpf(1 - fading_thickness, 1.0f, offset_factor - fading_center)) :
+ (interpf(
+ 1.0f, 1 - fading_thickness, offset_factor - fading_center + 1));
+ opacity_factor = (offset_factor > fading_center) ?
+ (interpf(1 - fading_opacity, 1.0f, offset_factor - fading_center)) :
+ (interpf(1.0f, 1 - fading_opacity, offset_factor - fading_center + 1));
+ }
+
+ for (int j = 0; j < new_gps->totpoints; j++) {
+ interp_v3_v3v3(&pt[j].x,
+ &t1_array[j * 3],
+ &t2_array[j * 3],
+ interpf(1 + offset, offset, offset_factor));
+ if (fading) {
+ pt[j].pressure = gps->points[j].pressure * thickness_factor;
+ pt[j].strength = gps->points[j].strength * opacity_factor;
+ }
+ }
+ }
+ MEM_freeN(t1_array);
+ MEM_freeN(t2_array);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ ListBase duplicates = {0};
+ MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
+ bGPDstroke *gps;
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->materialname,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_MIRROR_INVERT_LAYER,
+ mmd->flag & GP_MIRROR_INVERT_PASS,
+ mmd->flag & GP_MIRROR_INVERT_LAYERPASS,
+ mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
+ continue;
+ }
+ if (mmd->flags & GP_MULTIPLY_ENABLE_ANGLE_SPLITTING) {
+ splitStroke(gpf, gps, mmd->split_angle);
+ }
+ if (mmd->duplications > 0) {
+ duplicateStroke(gpf,
+ gps,
+ mmd->duplications,
+ mmd->distance,
+ mmd->offset,
+ &duplicates,
+ mmd->flags & GP_MULTIPLY_ENABLE_FADING,
+ mmd->fading_center,
+ mmd->fading_thickness,
+ mmd->fading_opacity);
+ }
+ }
+ if (duplicates.first) {
+ ((bGPDstroke *)gpf->strokes.last)->next = duplicates.first;
+ ((bGPDstroke *)duplicates.first)->prev = gpf->strokes.last;
+ gpf->strokes.last = duplicates.first;
+ }
+ }
+ }
+}
+
+/* -------------------------------- */
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
+ bGPDstroke *gps;
+ ListBase duplicates = {0};
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->materialname,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_MIRROR_INVERT_LAYER,
+ mmd->flag & GP_MIRROR_INVERT_PASS,
+ mmd->flag & GP_MIRROR_INVERT_LAYERPASS,
+ mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
+ continue;
+ }
+ if (mmd->flags & GP_MULTIPLY_ENABLE_ANGLE_SPLITTING) {
+ splitStroke(gpf, gps, mmd->split_angle);
+ }
+ if (mmd->duplications > 0) {
+ duplicateStroke(gpf,
+ gps,
+ mmd->duplications,
+ mmd->distance,
+ mmd->offset,
+ &duplicates,
+ mmd->flags & GP_MULTIPLY_ENABLE_FADING,
+ mmd->fading_center,
+ mmd->fading_thickness,
+ mmd->fading_opacity);
+ }
+ }
+ if (duplicates.first) {
+ ((bGPDstroke *)gpf->strokes.last)->next = duplicates.first;
+ ((bGPDstroke *)duplicates.first)->prev = gpf->strokes.last;
+ gpf->strokes.last = duplicates.first;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Multiply = {
+ /* name */ "Multiple Strokes",
+ /* structName */ "MultiplyGpencilModifierData",
+ /* structSize */ sizeof(MultiplyGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};