diff options
author | YimingWu <xp8110t@outlook.com> | 2019-11-14 21:18:23 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2019-11-14 21:24:49 +0300 |
commit | 91248876e517983531c44ffc1692674684c67eed (patch) | |
tree | b2e1bf063dedac5103a8105c50cea6ca80335b18 /source/blender/gpencil_modifiers/intern | |
parent | 8ff9eb97fb7c0e25acaa051ea8ae196c932b10b6 (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/intern')
-rw-r--r-- | source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c | 1 | ||||
-rw-r--r-- | source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c | 350 |
2 files changed, 351 insertions, 0 deletions
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, +}; |