Blender V4.3
dynamicpaint.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include <cmath>
12#include <cstdio>
13
14#include "BLI_blenlib.h"
15#include "BLI_kdtree.h"
16#include "BLI_math_color.h"
17#include "BLI_math_geom.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_vector.h"
20#include "BLI_string_utils.hh"
21#include "BLI_task.h"
22#include "BLI_threads.h"
23#include "BLI_utildefines.h"
24
25#include "BLT_translation.hh"
26
27#include "DNA_anim_types.h"
28#include "DNA_armature_types.h"
32#include "DNA_material_types.h"
33#include "DNA_mesh_types.h"
34#include "DNA_meshdata_types.h"
35#include "DNA_modifier_types.h"
37#include "DNA_object_types.h"
38#include "DNA_scene_types.h"
39#include "DNA_texture_types.h"
40
41#include "BKE_armature.hh"
42#include "BKE_bvhutils.hh" /* bvh tree */
43#include "BKE_collection.hh"
44#include "BKE_collision.h"
45#include "BKE_colorband.hh"
46#include "BKE_constraint.h"
47#include "BKE_customdata.hh"
48#include "BKE_deform.hh"
49#include "BKE_dynamicpaint.h"
50#include "BKE_effect.h"
51#include "BKE_image.hh"
52#include "BKE_image_format.hh"
53#include "BKE_lib_id.hh"
54#include "BKE_main.hh"
55#include "BKE_material.h"
56#include "BKE_mesh.hh"
57#include "BKE_mesh_mapping.hh"
58#include "BKE_mesh_runtime.hh"
59#include "BKE_modifier.hh"
60#include "BKE_object.hh"
61#include "BKE_particle.h"
62#include "BKE_pointcache.h"
63#include "BKE_scene.hh"
64
65#include "DEG_depsgraph.hh"
67
68/* for image output */
69#include "IMB_imbuf.hh"
70#include "IMB_imbuf_types.hh"
71
72#include "RE_texture.h"
73
74#include "atomic_ops.h"
75
76#include "CLG_log.h"
77
78using blender::int3;
79
80/* could enable at some point but for now there are far too many conversions */
81#ifdef __GNUC__
82// # pragma GCC diagnostic ignored "-Wdouble-promotion"
83#endif
84
85static CLG_LogRef LOG = {"bke.dynamicpaint"};
86
87/* precalculated gaussian factors for 5x super sampling */
88static const float gaussianFactors[5] = {
89 0.996849f,
90 0.596145f,
91 0.596145f,
92 0.596145f,
93 0.524141f,
94};
95static const float gaussianTotal = 3.309425f;
96
97/* UV Image neighboring pixel table x and y list */
98static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
99static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
100
101/* Neighbor x/y list that prioritizes grid directions over diagonals */
102static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
103static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
104
105/* subframe_updateObject() flags */
106#define SUBFRAME_RECURSION 5
107/* #surface_getBrushFlags() return values. */
108#define BRUSH_USES_VELOCITY (1 << 0)
109/* Brush mesh ray-cast status. */
110#define HIT_VOLUME 1
111#define HIT_PROXIMITY 2
112/* dynamicPaint_findNeighborPixel() return codes */
113#define NOT_FOUND -1
114#define ON_MESH_EDGE -2
115#define OUT_OF_TEXTURE -3
116/* paint effect default movement per frame in global units */
117#define EFF_MOVEMENT_PER_FRAME 0.05f
118/* initial wave time factor */
119#define WAVE_TIME_FAC (1.0f / 24.0f)
120#define CANVAS_REL_SIZE 5.0f
121/* drying limits */
122#define MIN_WETNESS 0.001f
123#define MAX_WETNESS 5.0f
124
125/* dissolve inline function */
126BLI_INLINE void value_dissolve(float *r_value,
127 const float time,
128 const float scale,
129 const bool is_log)
130{
131 *r_value = (is_log) ? (*r_value) * powf(MIN_WETNESS, 1.0f / (1.2f * time / scale)) :
132 (*r_value) - 1.0f / time * scale;
133}
134
135/***************************** Internal Structs ***************************/
136
137struct Bounds2D {
138 float min[2], max[2];
139};
140
141struct Bounds3D {
142 float min[3], max[3];
143 bool valid;
144};
145
162
163struct Vec3f {
164 float v[3];
165};
166
169 float dir[3];
171 float dist;
172};
173
177 float invNorm[3];
180};
181
184 /* point space data */
187 int *s_pos;
189 int *s_num;
193 float dim[3];
194
195 /* adjacency info */
199 /* space partitioning */
202
203 /* velocity and movement */
213 float prev_obmat[4][4];
215 int clear;
216};
217
220 /* Pixel / mesh data */
224 /* vertex indexes */
226
229};
230
233 Vec3f *barycentricWeights; /* b-weights for all pixel samples */
234};
235
236/* adjacency data flags */
237#define ADJ_ON_MESH_EDGE (1 << 0)
238#define ADJ_BORDER_PIXEL (1 << 1)
239
256
257/************************* Runtime evaluation store ***************************/
258
260{
261 if (runtime_data == nullptr) {
262 return;
263 }
264 if (runtime_data->canvas_mesh) {
265 BKE_id_free(nullptr, runtime_data->canvas_mesh);
266 }
267 if (runtime_data->brush_mesh) {
268 BKE_id_free(nullptr, runtime_data->brush_mesh);
269 }
270 MEM_freeN(runtime_data);
271}
272
274{
275 if (pmd->modifier.runtime == nullptr) {
276 pmd->modifier.runtime = MEM_callocN(sizeof(DynamicPaintRuntime), "dynamic paint runtime");
277 }
278 return (DynamicPaintRuntime *)pmd->modifier.runtime;
279}
280
282{
283 if (canvas->pmd->modifier.runtime == nullptr) {
284 return nullptr;
285 }
286 DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)canvas->pmd->modifier.runtime;
287 return runtime_data->canvas_mesh;
288}
289
291{
292 if (brush->pmd->modifier.runtime == nullptr) {
293 return nullptr;
294 }
296 return runtime_data->brush_mesh;
297}
298
299/***************************** General Utils ******************************/
300
301/* Set canvas error string to display at the bake report */
302static bool setError(DynamicPaintCanvasSettings *canvas, const char *string)
303{
304 /* Add error to canvas ui info label */
305 STRNCPY(canvas->error, string);
306 CLOG_STR_ERROR(&LOG, string);
307 return false;
308}
309
310/* Get number of surface points for cached types */
312{
313 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
314 return 0; /* Not supported at the moment. */
315 }
316 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
317 const Mesh *canvas_mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
318 return (canvas_mesh) ? canvas_mesh->verts_num : 0;
319 }
320
321 return 0;
322}
323
328
330{
331 const char *name;
332
333 if (output == 0) {
334 name = surface->output_name;
335 }
336 else if (output == 1) {
337 name = surface->output_name2;
338 }
339 else {
340 return false;
341 }
342
343 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
344 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
345 Mesh *mesh = static_cast<Mesh *>(ob->data);
347 -1);
348 }
349 if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
350 return (BKE_object_defgroup_name_index(ob, name) != -1);
351 }
352 }
353
354 return false;
355}
356
357static bool surface_duplicateOutputExists(void *arg, const char *name)
358{
359 DynamicPaintSurface *t_surface = static_cast<DynamicPaintSurface *>(arg);
360 DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(
361 t_surface->canvas->surfaces.first);
362
363 for (; surface; surface = surface->next) {
364 if (surface != t_surface && surface->type == t_surface->type &&
365 surface->format == t_surface->format)
366 {
367 if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
368 (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)))
369 {
370 return true;
371 }
372 }
373 }
374 return false;
375}
376
377static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
378{
379 char name[64];
380 STRNCPY(name, basename); /* in case basename is surface->name use a copy */
381 if (output == 0) {
383 surface,
384 name,
385 '.',
386 surface->output_name,
387 sizeof(surface->output_name));
388 }
389 else if (output == 1) {
391 surface,
392 name,
393 '.',
394 surface->output_name2,
395 sizeof(surface->output_name2));
396 }
397}
398
399static bool surface_duplicateNameExists(void *arg, const char *name)
400{
401 DynamicPaintSurface *t_surface = static_cast<DynamicPaintSurface *>(arg);
402 DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(
403 t_surface->canvas->surfaces.first);
404
405 for (; surface; surface = surface->next) {
406 if (surface != t_surface && STREQ(name, surface->name)) {
407 return true;
408 }
409 }
410 return false;
411}
412
413void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
414{
415 char name[64];
416 STRNCPY_UTF8(name, basename); /* in case basename is surface->name use a copy */
418 surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
419}
420
422{
423 const char *name_prefix = "";
424 const char *name_suffix_1 = "";
425 const char *name_suffix_2 = "";
426
427 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
428 surface->output_name[0] = '\0';
429 surface->output_name2[0] = '\0';
430 surface->flags |= MOD_DPAINT_ANTIALIAS;
431 surface->depth_clamp = 1.0f;
432 }
433 else {
434 name_prefix = "dp_";
435 surface->flags &= ~MOD_DPAINT_ANTIALIAS;
436 surface->depth_clamp = 0.0f;
437 }
438
439 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
440 name_suffix_1 = "paintmap";
441 name_suffix_2 = "wetmap";
442 }
443 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
444 name_suffix_1 = name_suffix_2 = "displace";
445 }
446 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
447 name_suffix_1 = name_suffix_2 = "weight";
448 }
449 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
450 name_suffix_1 = name_suffix_2 = "wave";
451 }
452
453 SNPRINTF(surface->output_name, "%s%s", name_prefix, name_suffix_1);
454 SNPRINTF(surface->output_name2, "%s%s", name_prefix, name_suffix_2);
455 const bool output_name_equal = STREQ(surface->output_name, surface->output_name2);
456
457 surface_setUniqueOutputName(surface, surface->output_name, 0);
458 if (!output_name_equal) {
459 surface_setUniqueOutputName(surface, surface->output_name2, 1);
460 }
461}
462
464{
465 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
466 return (surface->data->total_points * 5);
467 }
468 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS &&
469 surface->data->adj_data)
470 {
471 return (surface->data->total_points + surface->data->adj_data->total_targets);
472 }
473
474 return surface->data->total_points;
475}
476
477static void blendColors(const float t_color[3],
478 const float t_alpha,
479 const float s_color[3],
480 const float s_alpha,
481 float result[4])
482{
483 /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
484 float i_alpha = 1.0f - s_alpha;
485 float f_alpha = t_alpha * i_alpha + s_alpha;
486
487 /* blend colors */
488 if (f_alpha) {
489 for (int i = 0; i < 3; i++) {
490 result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
491 }
492 }
493 else {
494 copy_v3_v3(result, t_color);
495 }
496 /* return final alpha */
497 result[3] = f_alpha;
498}
499
500/* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */
501static float mixColors(
502 float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
503{
504 float weight_ratio, factor;
505 if (b_weight) {
506 /* if first value has no weight just use b_color */
507 if (!a_weight) {
508 copy_v3_v3(a_color, b_color);
509 return b_weight * ratio;
510 }
511 weight_ratio = b_weight / (a_weight + b_weight);
512 }
513 else {
514 return a_weight * (1.0f - ratio);
515 }
516
517 /* calculate final interpolation factor */
518 if (ratio <= 0.5f) {
519 factor = weight_ratio * (ratio * 2.0f);
520 }
521 else {
522 ratio = (ratio * 2.0f - 1.0f);
523 factor = weight_ratio * (1.0f - ratio) + ratio;
524 }
525 /* mix final color */
526 interp_v3_v3v3(a_color, a_color, b_color, factor);
527 return (1.0f - factor) * a_weight + factor * b_weight;
528}
529
530static void scene_setSubframe(Scene *scene, float subframe)
531{
532 /* Dynamic paint sub-frames must be done on previous frame. */
533 scene->r.cfra -= 1;
534 scene->r.subframe = subframe;
535}
536
538{
539 uint numobjects;
541 depsgraph, nullptr, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
542
543 int flags = 0;
544
545 for (int i = 0; i < numobjects; i++) {
546 Object *brushObj = objects[i];
547
551
552 if (pmd2->brush) {
553 DynamicPaintBrushSettings *brush = pmd2->brush;
554
555 if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
556 flags |= BRUSH_USES_VELOCITY;
557 }
558 }
559 }
560 }
561
563
564 return flags;
565}
566
567/* check whether two bounds intersect */
568static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
569{
570 if (!b1->valid || !b2->valid) {
571 return false;
572 }
573 for (int i = 2; i--;) {
574 if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) {
575 return false;
576 }
577 }
578 return true;
579}
580
581/* check whether two bounds intersect inside defined proximity */
582static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
583{
584 if (!b1->valid || !b2->valid) {
585 return false;
586 }
587 for (int i = 2; i--;) {
588 if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) {
589 return false;
590 }
591 }
592 return true;
593}
594
595/* check whether bounds intersects a point with given radius */
596static bool boundIntersectPoint(Bounds3D *b, const float point[3], const float radius)
597{
598 if (!b->valid) {
599 return false;
600 }
601 for (int i = 2; i--;) {
602 if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) {
603 return false;
604 }
605 }
606 return true;
607}
608
609/* expand bounds by a new point */
610static void boundInsert(Bounds3D *b, const float point[3])
611{
612 if (!b->valid) {
613 copy_v3_v3(b->min, point);
614 copy_v3_v3(b->max, point);
615 b->valid = true;
616 return;
617 }
618
619 minmax_v3v3_v3(b->min, b->max, point);
620}
621
623{
624 Bounds3D *mb = &sData->bData->mesh_bounds;
625 return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
626}
627
629{
630 PaintBakeData *bData = data->bData;
631 DynamicPaintVolumeGrid *grid = bData->grid;
632
633 if (grid->bounds) {
634 MEM_freeN(grid->bounds);
635 }
636 if (grid->s_pos) {
637 MEM_freeN(grid->s_pos);
638 }
639 if (grid->s_num) {
640 MEM_freeN(grid->s_num);
641 }
642 if (grid->t_index) {
643 MEM_freeN(grid->t_index);
644 }
645
646 MEM_freeN(bData->grid);
647 bData->grid = nullptr;
648}
649
650static void grid_bound_insert_cb_ex(void *__restrict userdata,
651 const int i,
652 const TaskParallelTLS *__restrict tls)
653{
654 PaintBakeData *bData = static_cast<PaintBakeData *>(userdata);
655
656 Bounds3D *grid_bound = static_cast<Bounds3D *>(tls->userdata_chunk);
657
658 boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
659}
660
661static void grid_bound_insert_reduce(const void *__restrict /*userdata*/,
662 void *__restrict chunk_join,
663 void *__restrict chunk)
664{
665 Bounds3D *join = static_cast<Bounds3D *>(chunk_join);
666 Bounds3D *grid_bound = static_cast<Bounds3D *>(chunk);
667
668 boundInsert(join, grid_bound->min);
669 boundInsert(join, grid_bound->max);
670}
671
672static void grid_cell_points_cb_ex(void *__restrict userdata,
673 const int i,
674 const TaskParallelTLS *__restrict tls)
675{
676 PaintBakeData *bData = static_cast<PaintBakeData *>(userdata);
677 DynamicPaintVolumeGrid *grid = bData->grid;
678 int *temp_t_index = grid->temp_t_index;
679 int *s_num = static_cast<int *>(tls->userdata_chunk);
680
681 int co[3];
682
683 for (int j = 3; j--;) {
684 co[j] = int(floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
685 bData->dim[j] * grid->dim[j]));
686 CLAMP(co[j], 0, grid->dim[j] - 1);
687 }
688
689 temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
690 s_num[temp_t_index[i]]++;
691}
692
693static void grid_cell_points_reduce(const void *__restrict userdata,
694 void *__restrict chunk_join,
695 void *__restrict chunk)
696{
697 const PaintBakeData *bData = static_cast<const PaintBakeData *>(userdata);
698 const DynamicPaintVolumeGrid *grid = bData->grid;
699 const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
700
701 int *join_s_num = static_cast<int *>(chunk_join);
702 int *s_num = static_cast<int *>(chunk);
703
704 /* calculate grid indexes */
705 for (int i = 0; i < grid_cells; i++) {
706 join_s_num[i] += s_num[i];
707 }
708}
709
710static void grid_cell_bounds_cb(void *__restrict userdata,
711 const int x,
712 const TaskParallelTLS *__restrict /*tls*/)
713{
714 PaintBakeData *bData = static_cast<PaintBakeData *>(userdata);
715 DynamicPaintVolumeGrid *grid = bData->grid;
716 float *dim = bData->dim;
717 int *grid_dim = grid->dim;
718
719 for (int y = 0; y < grid_dim[1]; y++) {
720 for (int z = 0; z < grid_dim[2]; z++) {
721 const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
722 /* set bounds */
723 for (int j = 3; j--;) {
724 const int s = (j == 0) ? x : ((j == 1) ? y : z);
725 grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
726 grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
727 }
728 grid->bounds[b_index].valid = true;
729 }
730 }
731}
732
734{
735 PaintSurfaceData *sData = surface->data;
736 PaintBakeData *bData = sData->bData;
738 int grid_cells, axis = 3;
739 int *temp_t_index = nullptr;
740 int *temp_s_num = nullptr;
741
742 if (bData->grid) {
743 freeGrid(sData);
744 }
745
746 bData->grid = MEM_cnew<DynamicPaintVolumeGrid>(__func__);
747 grid = bData->grid;
748
749 {
750 int i, error = 0;
751 float dim_factor, volume, dim[3];
752 float td[3];
753 float min_dim;
754
755 /* calculate canvas dimensions */
756 /* Important to init correctly our ref grid_bound... */
757 boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
758 {
759 TaskParallelSettings settings;
761 settings.use_threading = (sData->total_points > 1000);
762 settings.userdata_chunk = &grid->grid_bounds;
763 settings.userdata_chunk_size = sizeof(grid->grid_bounds);
766 }
767 /* get dimensions */
768 sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
769 copy_v3_v3(td, dim);
770 copy_v3_v3(bData->dim, dim);
771 min_dim = max_fff(td[0], td[1], td[2]) / 1000.0f;
772
773 /* deactivate zero axes */
774 for (i = 0; i < 3; i++) {
775 if (td[i] < min_dim) {
776 td[i] = 1.0f;
777 axis--;
778 }
779 }
780
781 if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
782 MEM_freeN(bData->grid);
783 bData->grid = nullptr;
784 return;
785 }
786
787 /* now calculate grid volume/area/width depending on num of active axis */
788 volume = td[0] * td[1] * td[2];
789
790 /* determine final grid size by trying to fit average 10.000 points per grid cell */
791 dim_factor = float(
792 pow(double(volume) / (double(sData->total_points) / 10000.0), 1.0 / double(axis)));
793
794 /* define final grid size using dim_factor, use min 3 for active axes */
795 for (i = 0; i < 3; i++) {
796 grid->dim[i] = int(floor(td[i] / dim_factor));
797 CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
798 }
799 grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
800
801 /* allocate memory for grids */
802 grid->bounds = static_cast<Bounds3D *>(
803 MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds"));
804 grid->s_pos = static_cast<int *>(
805 MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position"));
806
807 grid->s_num = static_cast<int *>(MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points"));
808 temp_s_num = static_cast<int *>(
809 MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points"));
810 grid->t_index = static_cast<int *>(
811 MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids"));
812 grid->temp_t_index = temp_t_index = static_cast<int *>(
813 MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids"));
814
815 /* in case of an allocation failure abort here */
816 if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num ||
817 !temp_t_index)
818 {
819 error = 1;
820 }
821
822 if (!error) {
823 /* calculate number of points within each cell */
824 {
825 TaskParallelSettings settings;
827 settings.use_threading = (sData->total_points > 1000);
828 settings.userdata_chunk = grid->s_num;
829 settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
831 BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
832 }
833
834 /* calculate grid indexes (not needed for first cell, which is zero). */
835 for (i = 1; i < grid_cells; i++) {
836 grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
837 }
838
839 /* save point indexes to final array */
840 for (i = 0; i < sData->total_points; i++) {
841 int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
842 grid->t_index[pos] = i;
843
844 temp_s_num[temp_t_index[i]]++;
845 }
846
847 /* calculate cell bounds */
848 {
849 TaskParallelSettings settings;
851 settings.use_threading = (grid_cells > 1000);
852 BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, &settings);
853 }
854 }
855
856 if (temp_s_num) {
857 MEM_freeN(temp_s_num);
858 }
859 MEM_SAFE_FREE(temp_t_index);
860
861 if (error || !grid->s_num) {
862 setError(surface->canvas, N_("Not enough free memory"));
863 freeGrid(sData);
864 }
865 }
866}
867
868/***************************** Freeing data ******************************/
869
871{
872 if (pmd->brush) {
873 if (pmd->brush->paint_ramp) {
875 }
876 if (pmd->brush->vel_ramp) {
877 MEM_freeN(pmd->brush->vel_ramp);
878 }
879
880 MEM_freeN(pmd->brush);
881 pmd->brush = nullptr;
882 }
883}
884
886{
887 if (data->adj_data) {
888 if (data->adj_data->n_index) {
889 MEM_freeN(data->adj_data->n_index);
890 }
891 if (data->adj_data->n_num) {
892 MEM_freeN(data->adj_data->n_num);
893 }
894 if (data->adj_data->n_target) {
895 MEM_freeN(data->adj_data->n_target);
896 }
897 if (data->adj_data->flags) {
898 MEM_freeN(data->adj_data->flags);
899 }
900 if (data->adj_data->border) {
901 MEM_freeN(data->adj_data->border);
902 }
903 MEM_freeN(data->adj_data);
904 data->adj_data = nullptr;
905 }
906}
907
909{
910 PaintBakeData *bData = data->bData;
911 if (bData) {
912 if (bData->bNormal) {
913 MEM_freeN(bData->bNormal);
914 }
915 if (bData->s_pos) {
916 MEM_freeN(bData->s_pos);
917 }
918 if (bData->s_num) {
919 MEM_freeN(bData->s_num);
920 }
921 if (bData->realCoord) {
922 MEM_freeN(bData->realCoord);
923 }
924 if (bData->bNeighs) {
925 MEM_freeN(bData->bNeighs);
926 }
927 if (bData->grid) {
928 freeGrid(data);
929 }
930 if (bData->prev_positions) {
932 }
933 if (bData->velocity) {
934 MEM_freeN(bData->velocity);
935 }
936 if (bData->prev_velocity) {
937 MEM_freeN(bData->prev_velocity);
938 }
939
940 MEM_freeN(data->bData);
941 data->bData = nullptr;
942 }
943}
944
945/* free surface data if it's not used anymore */
947{
948 if (!surface->data) {
949 return;
950 }
951
952 /* Free bake-data if not active or surface is baked. */
953 if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
954 (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED))
955 {
956 free_bakeData(surface->data);
957 }
958}
959
961{
962 PaintSurfaceData *data = surface->data;
963 if (!data) {
964 return;
965 }
966
967 if (data->format_data) {
968 /* format specific free */
969 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
970 ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
971 if (format_data->uv_p) {
972 MEM_freeN(format_data->uv_p);
973 }
974 if (format_data->barycentricWeights) {
975 MEM_freeN(format_data->barycentricWeights);
976 }
977 }
978 MEM_freeN(data->format_data);
979 }
980 /* type data */
981 if (data->type_data) {
982 MEM_freeN(data->type_data);
983 }
985 /* bake data */
987
988 MEM_freeN(surface->data);
989 surface->data = nullptr;
990}
991
993{
994 /* point cache */
995 if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
996 BKE_ptcache_free_list(&(surface->ptcaches));
997 }
998 surface->pointcache = nullptr;
999
1001
1002 BLI_remlink(&(surface->canvas->surfaces), surface);
1004 MEM_freeN(surface);
1005}
1006
1008{
1009 if (pmd->canvas) {
1010 /* Free surface data */
1011 DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(pmd->canvas->surfaces.first);
1012 DynamicPaintSurface *next_surface = nullptr;
1013
1014 while (surface) {
1015 next_surface = surface->next;
1016 dynamicPaint_freeSurface(pmd, surface);
1017 surface = next_surface;
1018 }
1019
1020 MEM_freeN(pmd->canvas);
1021 pmd->canvas = nullptr;
1022 }
1023}
1024
1026{
1027 if (pmd == nullptr) {
1028 return;
1029 }
1033}
1034
1035/***************************** Initialize and reset ******************************/
1036
1038 Scene *scene)
1039{
1040 DynamicPaintSurface *surface = MEM_cnew<DynamicPaintSurface>(__func__);
1041 if (!surface) {
1042 return nullptr;
1043 }
1044
1045 surface->canvas = canvas;
1048
1049 /* cache */
1050 surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
1051 surface->pointcache->flag |= PTCACHE_DISK_CACHE;
1052 surface->pointcache->step = 1;
1053
1054 /* Set initial values */
1058 surface->effect = 0;
1059 surface->effect_ui = 1;
1060
1061 surface->diss_speed = 250;
1062 surface->dry_speed = 500;
1063 surface->color_dry_threshold = 1.0f;
1064 surface->depth_clamp = 0.0f;
1065 surface->disp_factor = 1.0f;
1068
1069 surface->influence_scale = 1.0f;
1070 surface->radius_scale = 1.0f;
1071
1072 surface->init_color[0] = 1.0f;
1073 surface->init_color[1] = 1.0f;
1074 surface->init_color[2] = 1.0f;
1075 surface->init_color[3] = 1.0f;
1076
1077 surface->image_resolution = 256;
1078 surface->substeps = 0;
1079
1080 if (scene) {
1081 surface->start_frame = scene->r.sfra;
1082 surface->end_frame = scene->r.efra;
1083 }
1084 else {
1085 surface->start_frame = 1;
1086 surface->end_frame = 250;
1087 }
1088
1089 surface->spread_speed = 1.0f;
1090 surface->color_spread_speed = 1.0f;
1091 surface->shrink_speed = 1.0f;
1092
1093 surface->wave_damping = 0.04f;
1094 surface->wave_speed = 1.0f;
1095 surface->wave_timescale = 1.0f;
1096 surface->wave_spring = 0.20f;
1097 surface->wave_smoothness = 1.0f;
1098
1100 surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
1101
1102 /* Using ID_BRUSH i18n context, as we have no physics/dynamic-paint one for now. */
1104
1105 surface->effector_weights = BKE_effector_add_weights(nullptr);
1106
1108
1109 BLI_addtail(&canvas->surfaces, surface);
1110
1111 return surface;
1112}
1113
1115{
1116 if (pmd) {
1117 if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
1119 if (pmd->canvas) {
1121 }
1122
1123 canvas = pmd->canvas = MEM_cnew<DynamicPaintCanvasSettings>(__func__);
1124 if (!canvas) {
1125 return false;
1126 }
1127 canvas->pmd = pmd;
1128
1129 /* Create one surface */
1130 if (!dynamicPaint_createNewSurface(canvas, scene)) {
1131 return false;
1132 }
1133 }
1134 else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
1136 if (pmd->brush) {
1138 }
1139
1140 brush = pmd->brush = MEM_cnew<DynamicPaintBrushSettings>(__func__);
1141 if (!brush) {
1142 return false;
1143 }
1144 brush->pmd = pmd;
1145
1146 brush->psys = nullptr;
1147
1150
1151 brush->r = 0.15f;
1152 brush->g = 0.4f;
1153 brush->b = 0.8f;
1154 brush->alpha = 1.0f;
1155 brush->wetness = 1.0f;
1156
1157 brush->paint_distance = 1.0f;
1159
1160 brush->particle_radius = 0.2f;
1161 brush->particle_smooth = 0.05f;
1162
1164 brush->wave_factor = 1.0f;
1165 brush->wave_clamp = 0.0f;
1166 brush->smudge_strength = 0.3f;
1167 brush->max_velocity = 1.0f;
1168
1169 /* Paint proximity falloff color-ramp. */
1170 {
1171 CBData *ramp;
1172
1173 brush->paint_ramp = BKE_colorband_add(false);
1174 if (!brush->paint_ramp) {
1175 return false;
1176 }
1177 ramp = brush->paint_ramp->data;
1178 /* Add default smooth-falloff ramp. */
1179 ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
1180 ramp[0].pos = 0.0f;
1181 ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
1182 ramp[1].a = 0.0f;
1183 pmd->brush->paint_ramp->tot = 2;
1184 }
1185
1186 /* Brush velocity ramp. */
1187 {
1188 CBData *ramp;
1189
1190 brush->vel_ramp = BKE_colorband_add(false);
1191 if (!brush->vel_ramp) {
1192 return false;
1193 }
1194 ramp = brush->vel_ramp->data;
1195 ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
1196 ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
1197 brush->paint_ramp->tot = 2;
1198 }
1199 }
1200 }
1201 else {
1202 return false;
1203 }
1204
1205 return true;
1206}
1207
1210 int flag)
1211{
1212 /* Init modifier */
1213 tpmd->type = pmd->type;
1214 if (pmd->canvas) {
1216 }
1217 if (pmd->brush) {
1219 }
1220
1221 /* Copy data */
1222 if (tpmd->canvas) {
1223 DynamicPaintSurface *surface;
1224 tpmd->canvas->pmd = tpmd;
1225 /* free default surface */
1226 if (tpmd->canvas->surfaces.first) {
1228 static_cast<DynamicPaintSurface *>(tpmd->canvas->surfaces.first));
1229 }
1230
1231 tpmd->canvas->active_sur = pmd->canvas->active_sur;
1232
1233 /* copy existing surfaces */
1234 for (surface = static_cast<DynamicPaintSurface *>(pmd->canvas->surfaces.first); surface;
1235 surface = surface->next)
1236 {
1237 DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, nullptr);
1239 /* TODO(sergey): Consider passing some tips to the surface
1240 * creation to avoid this allocate-and-free cache behavior. */
1241 BKE_ptcache_free_list(&t_surface->ptcaches);
1243 t_surface->ptcaches = surface->ptcaches;
1244 t_surface->pointcache = surface->pointcache;
1245 }
1246
1247 /* surface settings */
1248 t_surface->brush_group = surface->brush_group;
1249 MEM_freeN(t_surface->effector_weights);
1250 t_surface->effector_weights = static_cast<EffectorWeights *>(
1252
1253 STRNCPY(t_surface->name, surface->name);
1254 t_surface->format = surface->format;
1255 t_surface->type = surface->type;
1256 t_surface->disp_type = surface->disp_type;
1257 t_surface->image_fileformat = surface->image_fileformat;
1258 t_surface->effect_ui = surface->effect_ui;
1259 t_surface->init_color_type = surface->init_color_type;
1260 t_surface->flags = surface->flags;
1261 t_surface->effect = surface->effect;
1262
1263 t_surface->image_resolution = surface->image_resolution;
1264 t_surface->substeps = surface->substeps;
1265 t_surface->start_frame = surface->start_frame;
1266 t_surface->end_frame = surface->end_frame;
1267
1268 copy_v4_v4(t_surface->init_color, surface->init_color);
1269 t_surface->init_texture = surface->init_texture;
1270 STRNCPY(t_surface->init_layername, surface->init_layername);
1271
1272 t_surface->dry_speed = surface->dry_speed;
1273 t_surface->diss_speed = surface->diss_speed;
1274 t_surface->color_dry_threshold = surface->color_dry_threshold;
1275 t_surface->depth_clamp = surface->depth_clamp;
1276 t_surface->disp_factor = surface->disp_factor;
1277
1278 t_surface->spread_speed = surface->spread_speed;
1279 t_surface->color_spread_speed = surface->color_spread_speed;
1280 t_surface->shrink_speed = surface->shrink_speed;
1281 t_surface->drip_vel = surface->drip_vel;
1282 t_surface->drip_acc = surface->drip_acc;
1283
1284 t_surface->influence_scale = surface->influence_scale;
1285 t_surface->radius_scale = surface->radius_scale;
1286
1287 t_surface->wave_damping = surface->wave_damping;
1288 t_surface->wave_speed = surface->wave_speed;
1289 t_surface->wave_timescale = surface->wave_timescale;
1290 t_surface->wave_spring = surface->wave_spring;
1291 t_surface->wave_smoothness = surface->wave_smoothness;
1292
1293 STRNCPY(t_surface->uvlayer_name, surface->uvlayer_name);
1294 STRNCPY(t_surface->image_output_path, surface->image_output_path);
1295 STRNCPY(t_surface->output_name, surface->output_name);
1296 STRNCPY(t_surface->output_name2, surface->output_name2);
1297 }
1298 }
1299 if (tpmd->brush) {
1300 DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
1301 t_brush->pmd = tpmd;
1302
1303 t_brush->flags = brush->flags;
1304 t_brush->collision = brush->collision;
1305
1306 t_brush->r = brush->r;
1307 t_brush->g = brush->g;
1308 t_brush->b = brush->b;
1309 t_brush->alpha = brush->alpha;
1310 t_brush->wetness = brush->wetness;
1311
1312 t_brush->particle_radius = brush->particle_radius;
1313 t_brush->particle_smooth = brush->particle_smooth;
1314 t_brush->paint_distance = brush->paint_distance;
1315
1316 /* NOTE: This is dangerous, as it will generate invalid data in case we are copying between
1317 * different objects. Extra external code has to be called then to ensure proper remapping of
1318 * that pointer. See e.g. `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
1319 t_brush->psys = brush->psys;
1320
1321 if (brush->paint_ramp) {
1322 memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
1323 }
1324 if (brush->vel_ramp) {
1325 memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
1326 }
1327
1328 t_brush->proximity_falloff = brush->proximity_falloff;
1329 t_brush->wave_type = brush->wave_type;
1330 t_brush->ray_dir = brush->ray_dir;
1331
1332 t_brush->wave_factor = brush->wave_factor;
1333 t_brush->wave_clamp = brush->wave_clamp;
1334 t_brush->max_velocity = brush->max_velocity;
1335 t_brush->smudge_strength = brush->smudge_strength;
1336 }
1337}
1338
1339/* allocates surface data depending on surface type */
1341{
1342 PaintSurfaceData *sData = surface->data;
1343
1344 switch (surface->type) {
1346 sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points,
1347 "DynamicPaintSurface Data");
1348 break;
1350 sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
1351 "DynamicPaintSurface DepthData");
1352 break;
1354 sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
1355 "DynamicPaintSurface WeightData");
1356 break;
1358 sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points,
1359 "DynamicPaintSurface WaveData");
1360 break;
1361 }
1362
1363 if (sData->type_data == nullptr) {
1364 setError(surface->canvas, N_("Not enough free memory"));
1365 }
1366}
1367
1369{
1370 return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
1371 (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
1372}
1373
1375{
1376 return (surface_usesAdjDistance(surface) || (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
1377 surface->flags & MOD_DPAINT_ANTIALIAS));
1378}
1379
1380/* initialize surface adjacency data */
1381static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
1382{
1383 PaintSurfaceData *sData = surface->data;
1384 Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
1385 PaintAdjData *ad;
1386 int *temp_data;
1387 int neigh_points = 0;
1388
1389 if (!force_init && !surface_usesAdjData(surface)) {
1390 return;
1391 }
1392
1393 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1394 /* For vertex format, neighbors are connected by edges */
1395 neigh_points = 2 * mesh->edges_num;
1396 }
1397 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1398 neigh_points = sData->total_points * 8;
1399 }
1400
1401 if (!neigh_points) {
1402 return;
1403 }
1404
1405 /* allocate memory */
1406 ad = sData->adj_data = MEM_cnew<PaintAdjData>(__func__);
1407 if (!ad) {
1408 return;
1409 }
1410 ad->n_index = static_cast<int *>(
1411 MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index"));
1412 ad->n_num = static_cast<int *>(
1413 MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts"));
1414 temp_data = static_cast<int *>(MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data"));
1415 ad->n_target = static_cast<int *>(
1416 MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets"));
1417 ad->flags = static_cast<int *>(
1418 MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags"));
1419 ad->total_targets = neigh_points;
1420 ad->border = nullptr;
1421 ad->total_border = 0;
1422
1423 /* in case of allocation error, free memory */
1424 if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
1426 if (temp_data) {
1427 MEM_freeN(temp_data);
1428 }
1429 setError(surface->canvas, N_("Not enough free memory"));
1430 return;
1431 }
1432
1433 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1434 /* For vertex format, count every vertex that is connected by an edge */
1435 int numOfEdges = mesh->edges_num;
1436 int numOfPolys = mesh->faces_num;
1437 const blender::Span<blender::int2> edges = mesh->edges();
1438 const blender::OffsetIndices faces = mesh->faces();
1439 const blender::Span<int> corner_verts = mesh->corner_verts();
1440
1441 /* count number of edges per vertex */
1442 for (int i = 0; i < numOfEdges; i++) {
1443 ad->n_num[edges[i][0]]++;
1444 ad->n_num[edges[i][1]]++;
1445
1446 temp_data[edges[i][0]]++;
1447 temp_data[edges[i][1]]++;
1448 }
1449
1450 /* also add number of vertices to temp_data
1451 * to locate points on "mesh edge" */
1452 for (int i = 0; i < numOfPolys; i++) {
1453 for (const int vert : corner_verts.slice(faces[i])) {
1454 temp_data[vert]++;
1455 }
1456 }
1457
1458 /* now check if total number of edges+faces for
1459 * each vertex is even, if not -> vertex is on mesh edge */
1460 for (int i = 0; i < sData->total_points; i++) {
1461 if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
1462 ad->flags[i] |= ADJ_ON_MESH_EDGE;
1463 }
1464
1465 /* reset temp data */
1466 temp_data[i] = 0;
1467 }
1468
1469 /* order n_index array */
1470 int n_pos = 0;
1471 for (int i = 0; i < sData->total_points; i++) {
1472 ad->n_index[i] = n_pos;
1473 n_pos += ad->n_num[i];
1474 }
1475
1476 /* and now add neighbor data using that info */
1477 for (int i = 0; i < numOfEdges; i++) {
1478 /* first vertex */
1479 int index = edges[i][0];
1480 n_pos = ad->n_index[index] + temp_data[index];
1481 ad->n_target[n_pos] = edges[i][1];
1482 temp_data[index]++;
1483
1484 /* second vertex */
1485 index = edges[i][1];
1486 n_pos = ad->n_index[index] + temp_data[index];
1487 ad->n_target[n_pos] = edges[i][0];
1488 temp_data[index]++;
1489 }
1490 }
1491 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1492 /* for image sequences, only allocate memory.
1493 * bake initialization takes care of rest */
1494 }
1495
1496 MEM_freeN(temp_data);
1497}
1498
1508
1509static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdata,
1510 const int i,
1511 const TaskParallelTLS *__restrict /*tls*/)
1512{
1513 const DynamicPaintSetInitColorData *data = static_cast<DynamicPaintSetInitColorData *>(userdata);
1514
1515 const PaintSurfaceData *sData = data->surface->data;
1516 PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1517
1518 const blender::Span<int> corner_verts = data->corner_verts;
1519 const blender::Span<int3> corner_tris = data->corner_tris;
1520 const float(*mloopuv)[2] = data->mloopuv;
1521 ImagePool *pool = data->pool;
1522 Tex *tex = data->surface->init_texture;
1523
1524 float uv[3] = {0.0f};
1525
1526 for (int j = 3; j--;) {
1527 TexResult texres = {0};
1528 const int vert = corner_verts[corner_tris[i][j]];
1529
1530 /* remap to [-1.0, 1.0] */
1531 uv[0] = mloopuv[corner_tris[i][j]][0] * 2.0f - 1.0f;
1532 uv[1] = mloopuv[corner_tris[i][j]][1] * 2.0f - 1.0f;
1533
1534 multitex_ext_safe(tex, uv, &texres, pool, true, false);
1535
1536 if (texres.tin > pPoint[vert].color[3]) {
1537 copy_v3_v3(pPoint[vert].color, texres.trgba);
1538 pPoint[vert].color[3] = texres.tin;
1539 }
1540 }
1541}
1542
1543static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *__restrict userdata,
1544 const int i,
1545 const TaskParallelTLS *__restrict /*tls*/)
1546{
1547 const DynamicPaintSetInitColorData *data = static_cast<DynamicPaintSetInitColorData *>(userdata);
1548
1549 const PaintSurfaceData *sData = data->surface->data;
1550 PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1551
1552 const blender::Span<int3> corner_tris = data->corner_tris;
1553 const float(*mloopuv)[2] = data->mloopuv;
1554 Tex *tex = data->surface->init_texture;
1555 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
1556 const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
1557
1558 float uv[9] = {0.0f};
1559 float uv_final[3] = {0.0f};
1560
1561 TexResult texres = {0};
1562
1563 /* collect all uvs */
1564 for (int j = 3; j--;) {
1565 copy_v2_v2(&uv[j * 3], mloopuv[corner_tris[f_data->uv_p[i].tri_index][j]]);
1566 }
1567
1568 /* interpolate final uv pos */
1569 interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
1570 /* remap to [-1.0, 1.0] */
1571 uv_final[0] = uv_final[0] * 2.0f - 1.0f;
1572 uv_final[1] = uv_final[1] * 2.0f - 1.0f;
1573
1574 multitex_ext_safe(tex, uv_final, &texres, nullptr, true, false);
1575
1576 /* apply color */
1577 copy_v3_v3(pPoint[i].color, texres.trgba);
1578 pPoint[i].color[3] = texres.tin;
1579}
1580
1582 void *__restrict userdata, const int i, const TaskParallelTLS *__restrict /*tls*/)
1583{
1584 const DynamicPaintSetInitColorData *data = static_cast<DynamicPaintSetInitColorData *>(userdata);
1585
1586 const PaintSurfaceData *sData = data->surface->data;
1587 PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1588
1589 const blender::Span<int3> corner_tris = data->corner_tris;
1590 const MLoopCol *mloopcol = data->mloopcol;
1591 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
1592 const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
1593
1594 const int tri_idx = f_data->uv_p[i].tri_index;
1595 float colors[3][4];
1596 float final_color[4];
1597
1598 /* collect color values */
1599 for (int j = 3; j--;) {
1600 rgba_uchar_to_float(colors[j], (const uchar *)&mloopcol[corner_tris[tri_idx][j]].r);
1601 }
1602
1603 /* interpolate final color */
1604 interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
1605
1606 copy_v4_v4(pPoint[i].color, final_color);
1607}
1608
1609static void dynamicPaint_setInitialColor(const Scene * /*scene*/, DynamicPaintSurface *surface)
1610{
1611 PaintSurfaceData *sData = surface->data;
1612 PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1613 Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
1614
1615 if (surface->type != MOD_DPAINT_SURFACE_T_PAINT) {
1616 return;
1617 }
1618
1619 if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE) {
1620 return;
1621 }
1622
1623 /* Single color */
1624 if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
1625 /* apply color to every surface point */
1626 for (int i = 0; i < sData->total_points; i++) {
1627 copy_v4_v4(pPoint[i].color, surface->init_color);
1628 }
1629 }
1630 /* UV mapped texture */
1631 else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
1632 Tex *tex = surface->init_texture;
1633
1634 const blender::Span<int> corner_verts = mesh->corner_verts();
1635 const blender::Span<int3> corner_tris = mesh->corner_tris();
1636
1637 char uvname[MAX_CUSTOMDATA_LAYER_NAME];
1638
1639 if (!tex) {
1640 return;
1641 }
1642
1643 /* get uv map */
1645 &mesh->corner_data, CD_PROP_FLOAT2, surface->init_layername, uvname);
1646 const float(*mloopuv)[2] = static_cast<const float(*)[2]>(
1648
1649 if (!mloopuv) {
1650 return;
1651 }
1652
1653 /* For vertex surface loop through `corner_tris` and find UV color
1654 * that provides highest alpha. */
1655 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1656 ImagePool *pool = BKE_image_pool_new();
1657
1658 DynamicPaintSetInitColorData data{};
1659 data.surface = surface;
1660 data.corner_verts = corner_verts;
1661 data.corner_tris = corner_tris;
1662 data.mloopuv = mloopuv;
1663 data.pool = pool;
1664
1665 TaskParallelSettings settings;
1667 settings.use_threading = (corner_tris.size() > 1000);
1669 0, corner_tris.size(), &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
1670 BKE_image_pool_free(pool);
1671 }
1672 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1674 data.surface = surface;
1675 data.corner_tris = corner_tris;
1676 data.mloopuv = mloopuv;
1677
1678 TaskParallelSettings settings;
1680 settings.use_threading = (sData->total_points > 1000);
1683 }
1684 }
1685 /* vertex color layer */
1686 else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
1687
1688 /* For vertex surface, just copy colors from #MLoopCol. */
1689 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1690 const blender::Span<int> corner_verts = mesh->corner_verts();
1691 const MLoopCol *col = static_cast<const MLoopCol *>(CustomData_get_layer_named(
1692 &mesh->corner_data, CD_PROP_BYTE_COLOR, surface->init_layername));
1693 if (!col) {
1694 return;
1695 }
1696
1697 for (const int i : corner_verts.index_range()) {
1698 rgba_uchar_to_float(pPoint[corner_verts[i]].color, (const uchar *)&col[i].r);
1699 }
1700 }
1701 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1702 const blender::Span<int3> corner_tris = mesh->corner_tris();
1703 const MLoopCol *col = static_cast<const MLoopCol *>(CustomData_get_layer_named(
1704 &mesh->corner_data, CD_PROP_BYTE_COLOR, surface->init_layername));
1705 if (!col) {
1706 return;
1707 }
1708
1710 data.surface = surface;
1711 data.corner_tris = corner_tris;
1712 data.mloopcol = col;
1713
1714 TaskParallelSettings settings;
1716 settings.use_threading = (sData->total_points > 1000);
1718 0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb, &settings);
1719 }
1720 }
1721}
1722
1724{
1725 PaintSurfaceData *sData = surface->data;
1726 if (sData && sData->type_data) {
1727 uint data_size;
1728
1729 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1730 data_size = sizeof(PaintPoint);
1731 }
1732 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
1733 data_size = sizeof(PaintWavePoint);
1734 }
1735 else {
1736 data_size = sizeof(float);
1737 }
1738
1739 memset(sData->type_data, 0, data_size * sData->total_points);
1740
1741 /* set initial color */
1742 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1743 dynamicPaint_setInitialColor(scene, surface);
1744 }
1745
1746 if (sData->bData) {
1747 sData->bData->clear = 1;
1748 }
1749 }
1750}
1751
1753{
1754 int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
1755 /* free existing data */
1756 if (surface->data) {
1758 }
1759
1760 /* don't reallocate for image sequence types. they get handled only on bake */
1761 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1762 return true;
1763 }
1764 if (numOfPoints < 1) {
1765 return false;
1766 }
1767
1768 /* allocate memory */
1769 surface->data = MEM_cnew<PaintSurfaceData>(__func__);
1770 if (!surface->data) {
1771 return false;
1772 }
1773
1774 /* allocate data depending on surface type and format */
1775 surface->data->total_points = numOfPoints;
1777 dynamicPaint_initAdjacencyData(surface, false);
1778
1779 /* set initial color */
1780 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1781 dynamicPaint_setInitialColor(scene, surface);
1782 }
1783
1784 return true;
1785}
1786
1787/* make sure allocated surface size matches current requirements */
1789{
1790 if (!surface->data || (dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))
1791 {
1792 return dynamicPaint_resetSurface(scene, surface);
1793 }
1794 return true;
1795}
1796
1797/***************************** Modifier processing ******************************/
1798
1812
1813static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
1814 const int i,
1815 const TaskParallelTLS *__restrict /*tls*/)
1816{
1818 userdata);
1819
1820 const DynamicPaintSurface *surface = data->surface;
1821
1822 const float *value = (float *)surface->data->type_data;
1823 const float val = value[i] * surface->disp_factor;
1824
1825 madd_v3_v3fl(data->vert_positions[i], data->vert_normals[i], -val);
1826}
1827
1830{
1831 PaintSurfaceData *sData = surface->data;
1832
1833 if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) {
1834 return;
1835 }
1836
1837 /* displace paint */
1838 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
1840 data.surface = surface;
1841 data.vert_positions = result->vert_positions_for_write();
1842 data.vert_normals = result->vert_normals();
1843
1844 TaskParallelSettings settings;
1846 settings.use_threading = (sData->total_points > 10000);
1849 }
1850}
1851
1852static void dynamic_paint_apply_surface_vpaint_blend_cb(void *__restrict userdata,
1853 const int i,
1854 const TaskParallelTLS *__restrict /*tls*/)
1855{
1857 userdata);
1858
1859 PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
1860 float(*fcolor)[4] = data->fcolor;
1861
1862 /* blend dry and wet layer */
1864 pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
1865}
1866
1867static void dynamic_paint_apply_surface_vpaint_cb(void *__restrict userdata,
1868 const int p_index,
1869 const TaskParallelTLS *__restrict /*tls*/)
1870{
1872 userdata);
1873
1874 const blender::Span<int> corner_verts = data->corner_verts;
1875
1876 const DynamicPaintSurface *surface = data->surface;
1877 PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
1878 float(*fcolor)[4] = data->fcolor;
1879
1880 MLoopCol *mloopcol = data->mloopcol;
1881 MLoopCol *mloopcol_wet = data->mloopcol_wet;
1882
1883 for (const int l_index : data->faces[p_index]) {
1884 const int v_index = corner_verts[l_index];
1885
1886 /* save layer data to output layer */
1887 /* apply color */
1888 if (mloopcol) {
1889 rgba_float_to_uchar((uchar *)&mloopcol[l_index].r, fcolor[v_index]);
1890 }
1891 /* apply wetness */
1892 if (mloopcol_wet) {
1893 const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
1894 mloopcol_wet[l_index].r = c;
1895 mloopcol_wet[l_index].g = c;
1896 mloopcol_wet[l_index].b = c;
1897 mloopcol_wet[l_index].a = 255;
1898 }
1899 }
1900}
1901
1902static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
1903 const int i,
1904 const TaskParallelTLS *__restrict /*tls*/)
1905{
1907 userdata);
1908
1909 PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
1910
1911 madd_v3_v3fl(data->vert_positions[i], data->vert_normals[i], wPoint[i].height);
1912}
1913
1918{
1920
1921 if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING) &&
1923 {
1924
1925 DynamicPaintSurface *surface;
1926
1927 /* loop through surfaces */
1928 for (surface = static_cast<DynamicPaintSurface *>(pmd->canvas->surfaces.first); surface;
1929 surface = surface->next)
1930 {
1931 PaintSurfaceData *sData = surface->data;
1932
1933 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
1934 if (!(surface->flags & MOD_DPAINT_ACTIVE)) {
1935 continue;
1936 }
1937
1938 /* process vertex surface previews */
1939 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1940
1941 /* vertex color paint */
1942 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1943 const blender::OffsetIndices faces = result->faces();
1944 const blender::Span<int> corner_verts = result->corner_verts();
1945
1946 /* paint is stored on dry and wet layers, so mix final color first */
1947 float(*fcolor)[4] = static_cast<float(*)[4]>(
1948 MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color"));
1949
1951 data.surface = surface;
1952 data.fcolor = fcolor;
1953
1954 {
1955 TaskParallelSettings settings;
1957 settings.use_threading = (sData->total_points > 1000);
1959 sData->total_points,
1960 &data,
1962 &settings);
1963 }
1964
1965 /* paint layer */
1966 MLoopCol *mloopcol = static_cast<MLoopCol *>(
1969 surface->output_name,
1970 result->corners_num));
1971 /* if output layer is lost from a constructive modifier, re-add it */
1972 if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
1973 mloopcol = static_cast<MLoopCol *>(CustomData_add_layer_named(&result->corner_data,
1976 corner_verts.size(),
1977 surface->output_name));
1978 }
1979
1980 /* wet layer */
1981 MLoopCol *mloopcol_wet = static_cast<MLoopCol *>(
1984 surface->output_name2,
1985 result->corners_num));
1986 /* if output layer is lost from a constructive modifier, re-add it */
1987 if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
1988 mloopcol_wet = static_cast<MLoopCol *>(
1989 CustomData_add_layer_named(&result->corner_data,
1992 corner_verts.size(),
1993 surface->output_name2));
1994 }
1995
1996 data.ob = ob;
1997 data.corner_verts = corner_verts;
1998 data.faces = faces;
1999 data.mloopcol = mloopcol;
2000 data.mloopcol_wet = mloopcol_wet;
2001
2002 {
2003 TaskParallelSettings settings;
2005 settings.use_threading = (faces.size() > 1000);
2007 0, faces.size(), &data, dynamic_paint_apply_surface_vpaint_cb, &settings);
2008 }
2009
2010 MEM_freeN(fcolor);
2011 }
2012 /* vertex group paint */
2013 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
2014 int defgrp_index = BKE_object_defgroup_name_index(ob, surface->output_name);
2016 &result->vert_data, CD_MDEFORMVERT, result->verts_num));
2017 float *weight = (float *)sData->type_data;
2018
2019 /* apply weights into a vertex group, if doesn't exists add a new layer */
2020 if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
2021 dvert = static_cast<MDeformVert *>(CustomData_add_layer(
2022 &result->vert_data, CD_MDEFORMVERT, CD_SET_DEFAULT, sData->total_points));
2023 }
2024 if (defgrp_index != -1 && dvert) {
2025 for (int i = 0; i < sData->total_points; i++) {
2026 MDeformVert *dv = &dvert[i];
2027 MDeformWeight *def_weight = BKE_defvert_find_index(dv, defgrp_index);
2028
2029 /* skip if weight value is 0 and no existing weight is found */
2030 if ((def_weight != nullptr) || (weight[i] != 0.0f)) {
2031 /* if not found, add a weight for it */
2032 if (def_weight == nullptr) {
2033 def_weight = BKE_defvert_ensure_index(dv, defgrp_index);
2034 }
2035
2036 /* set weight value */
2037 def_weight->weight = weight[i];
2038 }
2039 }
2040 }
2041 }
2042 /* wave simulation */
2043 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
2045 data.surface = surface;
2046 data.vert_positions = result->vert_positions_for_write();
2047 data.vert_normals = result->vert_normals();
2048
2049 TaskParallelSettings settings;
2051 settings.use_threading = (sData->total_points > 1000);
2053 0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
2054 result->tag_positions_changed();
2055 }
2056
2057 /* displace */
2058 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
2060 result->tag_positions_changed();
2061 }
2062 }
2063 }
2064 }
2065 }
2066 /* make a copy of mesh to use as brush data */
2067 else if (pmd->brush && pmd->type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
2069 if (runtime_data->brush_mesh != nullptr) {
2070 BKE_id_free(nullptr, runtime_data->brush_mesh);
2071 }
2072 runtime_data->brush_mesh = BKE_mesh_copy_for_eval(*result);
2073 }
2074
2075 return result;
2076}
2077
2079{
2080 if (surface->pointcache) {
2081 surface->pointcache->startframe = surface->start_frame;
2082 surface->pointcache->endframe = surface->end_frame;
2083 }
2084}
2085
2087{
2089 if (runtime->canvas_mesh != nullptr) {
2090 BKE_id_free(nullptr, runtime->canvas_mesh);
2091 }
2092
2093 runtime->canvas_mesh = BKE_mesh_copy_for_eval(*mesh);
2094}
2095
2096/*
2097 * Updates evaluated-mesh copy and processes dynamic paint step / caches.
2098 */
2100 DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
2101{
2102 if (pmd->canvas) {
2103 DynamicPaintCanvasSettings *canvas = pmd->canvas;
2104 DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(canvas->surfaces.first);
2105
2106 /* update evaluated-mesh copy */
2107 canvas_copyMesh(canvas, mesh);
2108
2109 /* in case image sequence baking, stop here */
2110 if (canvas->flags & MOD_DPAINT_BAKING) {
2111 return;
2112 }
2113
2114 /* loop through surfaces */
2115 for (; surface; surface = surface->next) {
2116 int current_frame = int(scene->r.cfra);
2117 bool no_surface_data;
2118
2119 /* free bake data if not required anymore */
2120 surface_freeUnusedData(surface);
2121
2122 /* image sequences are handled by bake operator */
2123 if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) ||
2124 !(surface->flags & MOD_DPAINT_ACTIVE))
2125 {
2126 continue;
2127 }
2128
2129 /* make sure surface is valid */
2130 no_surface_data = surface->data == nullptr;
2131 if (!dynamicPaint_checkSurfaceData(scene, surface)) {
2132 continue;
2133 }
2134
2135 /* limit frame range */
2136 CLAMP(current_frame, surface->start_frame, surface->end_frame);
2137
2138 if (no_surface_data || current_frame != surface->current_frame ||
2139 int(scene->r.cfra) == surface->start_frame)
2140 {
2141 PointCache *cache = surface->pointcache;
2142 PTCacheID pid;
2143 surface->current_frame = current_frame;
2144
2145 /* read point cache */
2146 BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
2147 pid.cache->startframe = surface->start_frame;
2148 pid.cache->endframe = surface->end_frame;
2149 BKE_ptcache_id_time(&pid, scene, float(scene->r.cfra), nullptr, nullptr, nullptr);
2150
2151 /* reset non-baked cache at first frame */
2152 if (int(scene->r.cfra) == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
2153 cache->flag |= PTCACHE_REDO_NEEDED;
2155 cache->flag &= ~PTCACHE_REDO_NEEDED;
2156 }
2157
2158 /* try to read from cache */
2159 bool can_simulate = (int(scene->r.cfra) == current_frame) &&
2160 !(cache->flag & PTCACHE_BAKED);
2161
2162 if (BKE_ptcache_read(&pid, float(scene->r.cfra), can_simulate)) {
2163 BKE_ptcache_validate(cache, int(scene->r.cfra));
2164 }
2165 /* if read failed and we're on surface range do recalculate */
2166 else if (can_simulate) {
2167 /* calculate surface frame */
2168 canvas->flags |= MOD_DPAINT_BAKING;
2169 dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
2170 canvas->flags &= ~MOD_DPAINT_BAKING;
2171
2172 /* restore canvas mesh if required */
2173 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
2174 surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
2175 {
2176 canvas_copyMesh(canvas, mesh);
2177 }
2178
2179 BKE_ptcache_validate(cache, surface->current_frame);
2180 BKE_ptcache_write(&pid, surface->current_frame);
2181 }
2182 }
2183 }
2184 }
2185}
2186
2188 DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
2189{
2190 /* Update canvas data for a new frame */
2191 dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
2192
2193 /* Return output mesh */
2194 return dynamicPaint_Modifier_apply(pmd, ob, mesh);
2195}
2196
2197/* -------------------------------------------------------------------- */
2200
2201/* Create a surface for uv image sequence format. */
2202#define JITTER_SAMPLES \
2203 { \
2204 0.0f, 0.0f, -0.2f, -0.4f, 0.2f, 0.4f, 0.4f, -0.2f, -0.4f, 0.3f, \
2205 }
2206
2220
2221static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
2222 const int ty,
2223 const TaskParallelTLS *__restrict /*tls*/)
2224{
2226 static_cast<const DynamicPaintCreateUVSurfaceData *>(userdata);
2227
2228 const DynamicPaintSurface *surface = data->surface;
2229 PaintUVPoint *tempPoints = data->tempPoints;
2230 Vec3f *tempWeights = data->tempWeights;
2231
2232 const blender::Span<int3> corner_tris = data->corner_tris;
2233 const float(*mloopuv)[2] = data->mloopuv;
2234 const blender::Span<int> corner_verts = data->corner_verts;
2235
2236 const Bounds2D *faceBB = data->faceBB;
2237
2238 const float jitter5sample[10] = JITTER_SAMPLES;
2239 const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2240 const int w = surface->image_resolution;
2241 const int h = w;
2242
2243 for (int tx = 0; tx < w; tx++) {
2244 const int index = tx + w * ty;
2245 PaintUVPoint *tPoint = &tempPoints[index];
2246 float point[5][2];
2247
2248 /* Init per pixel settings */
2249 tPoint->tri_index = -1;
2250 tPoint->neighbor_pixel = -1;
2251 tPoint->pixel_index = index;
2252
2253 /* Actual pixel center, used when collision is found */
2254 point[0][0] = (float(tx) + 0.5f) / w;
2255 point[0][1] = (float(ty) + 0.5f) / h;
2256
2257 /*
2258 * A pixel middle sample isn't enough to find very narrow polygons
2259 * So using 4 samples of each corner too
2260 */
2261 point[1][0] = float(tx) / w;
2262 point[1][1] = float(ty) / h;
2263
2264 point[2][0] = (float(tx) + 1) / w;
2265 point[2][1] = float(ty) / h;
2266
2267 point[3][0] = float(tx) / w;
2268 point[3][1] = (float(ty) + 1) / h;
2269
2270 point[4][0] = (float(tx) + 1) / w;
2271 point[4][1] = (float(ty) + 1) / h;
2272
2273 /* Loop through samples, starting from middle point */
2274 for (int sample = 0; sample < 5; sample++) {
2275 /* Loop through every face in the mesh */
2276 /* XXX TODO: This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here!
2277 */
2278 for (const int i : corner_tris.index_range()) {
2279 /* Check uv bb */
2280 if ((faceBB[i].min[0] > point[sample][0]) || (faceBB[i].min[1] > point[sample][1]) ||
2281 (faceBB[i].max[0] < point[sample][0]) || (faceBB[i].max[1] < point[sample][1]))
2282 {
2283 continue;
2284 }
2285
2286 const float *uv1 = mloopuv[corner_tris[i][0]];
2287 const float *uv2 = mloopuv[corner_tris[i][1]];
2288 const float *uv3 = mloopuv[corner_tris[i][2]];
2289
2290 /* If point is inside the face */
2291 if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
2292 float uv[2];
2293
2294 /* Add b-weights per anti-aliasing sample */
2295 for (int j = 0; j < aa_samples; j++) {
2296 uv[0] = point[0][0] + jitter5sample[j * 2] / w;
2297 uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
2298
2299 barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
2300 }
2301
2302 /* Set surface point face values */
2303 tPoint->tri_index = i;
2304
2305 /* save vertex indexes */
2306 tPoint->v1 = corner_verts[corner_tris[i][0]];
2307 tPoint->v2 = corner_verts[corner_tris[i][1]];
2308 tPoint->v3 = corner_verts[corner_tris[i][2]];
2309
2310 sample = 5; /* make sure we exit sample loop as well */
2311 break;
2312 }
2313 }
2314 }
2315 }
2316}
2317
2318static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdata,
2319 const int ty,
2320 const TaskParallelTLS *__restrict /*tls*/)
2321{
2323 static_cast<const DynamicPaintCreateUVSurfaceData *>(userdata);
2324
2325 const DynamicPaintSurface *surface = data->surface;
2326 PaintUVPoint *tempPoints = data->tempPoints;
2327 Vec3f *tempWeights = data->tempWeights;
2328
2329 const blender::Span<int3> corner_tris = data->corner_tris;
2330 const float(*mloopuv)[2] = data->mloopuv;
2331 const blender::Span<int> corner_verts = data->corner_verts;
2332
2333 uint32_t *active_points = data->active_points;
2334
2335 const float jitter5sample[10] = JITTER_SAMPLES;
2336 const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2337 const int w = surface->image_resolution;
2338 const int h = w;
2339
2340 for (int tx = 0; tx < w; tx++) {
2341 const int index = tx + w * ty;
2342 PaintUVPoint *tPoint = &tempPoints[index];
2343
2344 /* If point isn't on canvas mesh */
2345 if (tPoint->tri_index == -1) {
2346 float point[2];
2347
2348 /* get loop area */
2349 const int u_min = (tx > 0) ? -1 : 0;
2350 const int u_max = (tx < (w - 1)) ? 1 : 0;
2351 const int v_min = (ty > 0) ? -1 : 0;
2352 const int v_max = (ty < (h - 1)) ? 1 : 0;
2353
2354 point[0] = (float(tx) + 0.5f) / w;
2355 point[1] = (float(ty) + 0.5f) / h;
2356
2357 /* search through defined area for neighbor, checking grid directions first */
2358 for (int ni = 0; ni < 8; ni++) {
2359 int u = neighStraightX[ni];
2360 int v = neighStraightY[ni];
2361
2362 if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
2363 /* if not this pixel itself */
2364 if (u != 0 || v != 0) {
2365 const int ind = (tx + u) + w * (ty + v);
2366
2367 /* if neighbor has index */
2368 if (tempPoints[ind].neighbor_pixel == -1 && tempPoints[ind].tri_index != -1) {
2369 float uv[2];
2370 const int i = tempPoints[ind].tri_index;
2371 const float *uv1 = mloopuv[corner_tris[i][0]];
2372 const float *uv2 = mloopuv[corner_tris[i][1]];
2373 const float *uv3 = mloopuv[corner_tris[i][2]];
2374
2375 /* tri index */
2376 /* There is a low possibility of actually having a neighbor point which tri is
2377 * already set from another neighbor in a separate thread here.
2378 * Checking for both tri_index and neighbor_pixel above reduces that probability
2379 * but it remains possible.
2380 * That atomic op (and its memory fence) ensures tPoint->neighbor_pixel is set
2381 * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbor).
2382 */
2383 tPoint->neighbor_pixel = ind - 1;
2385 tPoint->tri_index = i;
2386
2387 /* Now calculate pixel data for this pixel as it was on face surface */
2388 /* Add b-weights per anti-aliasing sample */
2389 for (int j = 0; j < aa_samples; j++) {
2390 uv[0] = point[0] + jitter5sample[j * 2] / w;
2391 uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
2392 barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
2393 }
2394
2395 /* save vertex indexes */
2396 tPoint->v1 = corner_verts[corner_tris[i][0]];
2397 tPoint->v2 = corner_verts[corner_tris[i][1]];
2398 tPoint->v3 = corner_verts[corner_tris[i][2]];
2399
2400 break;
2401 }
2402 }
2403 }
2404 }
2405 }
2406
2407 /* Increase the final number of active surface points if relevant. */
2408 if (tPoint->tri_index != -1) {
2409 atomic_add_and_fetch_uint32(active_points, 1);
2410 }
2411 }
2412}
2413
2414#undef JITTER_SAMPLES
2415
2417 const float (*mloopuv)[2],
2418 int tri_index,
2419 const float point[2])
2420{
2421 BLI_assert(tri_index >= 0);
2422
2423 float min_distance = FLT_MAX;
2424
2425 for (int i = 0; i < 3; i++) {
2426 const float dist_squared = dist_squared_to_line_segment_v2(
2427 point,
2428 mloopuv[corner_tris[tri_index][(i + 0)]],
2429 mloopuv[corner_tris[tri_index][(i + 1) % 3]]);
2430
2431 if (dist_squared < min_distance) {
2432 min_distance = dist_squared;
2433 }
2434 }
2435
2436 return min_distance;
2437}
2438
2446
2449 int tri_index,
2450 const float pixel[2],
2451 int in_edge,
2452 int depth);
2453
2454/* Tries to find the neighboring pixel in given (uv space) direction.
2455 * Result is used by effect system to move paint on the surface.
2456 *
2457 * px, py : origin pixel x and y
2458 * n_index : lookup direction index (use neighX, neighY to get final index)
2459 */
2461 const MeshElemMap *vert_to_tri_map,
2462 const int w,
2463 const int h,
2464 const int px,
2465 const int py,
2466 const int n_index)
2467{
2468 /* NOTE: Current method only uses face edges to detect neighboring pixels.
2469 * -> It doesn't always lead to the optimum pixel but is accurate enough
2470 * and faster/simpler than including possible face tip point links)
2471 */
2472
2473 /* shift position by given n_index */
2474 const int x = px + neighX[n_index];
2475 const int y = py + neighY[n_index];
2476
2477 if (x < 0 || x >= w || y < 0 || y >= h) {
2478 return OUT_OF_TEXTURE;
2479 }
2480
2481 const PaintUVPoint *tempPoints = data->tempPoints;
2482 const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
2483 const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
2484
2485 /* Check if shifted point is on same face -> it's a correct neighbor
2486 * (and if it isn't marked as an "edge pixel") */
2487 if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbor_pixel == -1)) {
2488 return (x + w * y);
2489 }
2490
2491 /* Even if shifted point is on another face
2492 * -> use this point.
2493 *
2494 * !! Replace with "is uv faces linked" check !!
2495 * This should work fine as long as uv island margin is > 1 pixel.
2496 */
2497 if ((tPoint->tri_index != -1) && (tPoint->neighbor_pixel == -1)) {
2498 return (x + w * y);
2499 }
2500
2501 /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
2502 * and we have to find its "real" position.
2503 *
2504 * Simple neighboring face finding algorithm:
2505 * - find closest uv edge to shifted pixel and get the another face that shares that edge
2506 * - find corresponding position of that new face edge in uv space
2507 *
2508 * TODO: Implement something more accurate / optimized?
2509 */
2510 {
2512 bdata.vert_to_tri_map = vert_to_tri_map;
2513 bdata.w = w;
2514 bdata.h = h;
2515 bdata.px = px;
2516 bdata.py = py;
2517 bdata.best_index = NOT_FOUND;
2518 bdata.best_weight = 1.0f;
2519
2520 float pixel[2];
2521
2522 pixel[0] = (float(px + neighX[n_index]) + 0.5f) / float(w);
2523 pixel[1] = (float(py + neighY[n_index]) + 0.5f) / float(h);
2524
2525 /* Do a small recursive search for the best island edge. */
2526 dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
2527
2528 return bdata.best_index;
2529 }
2530}
2531
2534 int tri_index,
2535 const float pixel[2],
2536 int in_edge,
2537 int depth)
2538{
2539 const blender::Span<int> corner_verts = data->corner_verts;
2540 const blender::Span<int3> corner_tris = data->corner_tris;
2541 const float(*mloopuv)[2] = data->mloopuv;
2542
2543 const int3 loop_idx = corner_tris[tri_index];
2544
2545 /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
2546 for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
2547 /* but not the edge we have just recursed through */
2548 if (edge_idx == in_edge) {
2549 continue;
2550 }
2551
2552 float uv0[2], uv1[2], uv2[2];
2553
2554 copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]]);
2555 copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]]);
2556 copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]]);
2557
2558 /* Verify the target point is on the opposite side of the edge from the third triangle
2559 * vertex, to ensure that we always move closer to the goal point. */
2560 const float sidep = line_point_side_v2(uv0, uv1, pixel);
2561 const float side2 = line_point_side_v2(uv0, uv1, uv2);
2562
2563 if (side2 == 0.0f) {
2564 continue;
2565 }
2566
2567 /* Hack: allow all edges of the original triangle */
2568 const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) ||
2569 (sidep > 0 && side2 < 0);
2570
2571 /* Allow exactly on edge for the non-recursive case */
2572 if (!correct_side && sidep != 0.0f) {
2573 continue;
2574 }
2575
2576 /* Now find another face that is linked to that edge. */
2577 const int vert0 = corner_verts[loop_idx[(edge_idx + 0)]];
2578 const int vert1 = corner_verts[loop_idx[(edge_idx + 1) % 3]];
2579
2580 /* Use a pre-computed vert-to-corner_tri mapping,
2581 * speeds up things a lot compared to looping over all corner_tris. */
2582 const MeshElemMap *map = &bdata->vert_to_tri_map[vert0];
2583
2584 bool found_other = false;
2585 int target_tri = -1;
2586 int target_edge = -1;
2587
2588 float ouv0[2], ouv1[2];
2589
2590 for (int i = 0; i < map->count && !found_other; i++) {
2591 const int tri_other_index = map->indices[i];
2592
2593 if (tri_other_index == tri_index) {
2594 continue;
2595 }
2596
2597 const int3 other_tri = corner_tris[tri_other_index];
2598
2599 /* Check edges for match, looping in the same order as the outer loop. */
2600 for (int j = 0; j < 3; j++) {
2601 const int overt0 = corner_verts[other_tri[(j + 0)]];
2602 const int overt1 = corner_verts[other_tri[(j + 1) % 3]];
2603
2604 /* Allow for swapped vertex order */
2605 if (overt0 == vert0 && overt1 == vert1) {
2606 found_other = true;
2607 copy_v2_v2(ouv0, mloopuv[other_tri[(j + 0)]]);
2608 copy_v2_v2(ouv1, mloopuv[other_tri[(j + 1) % 3]]);
2609 }
2610 else if (overt0 == vert1 && overt1 == vert0) {
2611 found_other = true;
2612 copy_v2_v2(ouv1, mloopuv[other_tri[(j + 0)]]);
2613 copy_v2_v2(ouv0, mloopuv[other_tri[(j + 1) % 3]]);
2614 }
2615
2616 if (found_other) {
2617 target_tri = tri_other_index;
2618 target_edge = j;
2619 break;
2620 }
2621 }
2622 }
2623
2624 if (!found_other) {
2625 if (bdata->best_index < 0) {
2626 bdata->best_index = ON_MESH_EDGE;
2627 }
2628
2629 continue;
2630 }
2631
2632 /* If this edge is connected in UV space too, recurse */
2633 if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
2634 if (depth > 0 && correct_side) {
2635 dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
2636 }
2637
2638 continue;
2639 }
2640
2641 /* Otherwise try to map to the other side of the edge.
2642 * First check if there already is a better solution. */
2643 const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
2644
2645 if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight) {
2646 continue;
2647 }
2648
2649 /*
2650 * Find a point that is relatively at same edge position
2651 * on this other face UV
2652 */
2653 float closest_point[2], dir_vec[2], tgt_pixel[2];
2654
2655 float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
2656 CLAMP(lambda, 0.0f, 1.0f);
2657
2658 sub_v2_v2v2(dir_vec, ouv1, ouv0);
2659 madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
2660
2661 int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
2662
2663 const int final_pixel[2] = {int(floorf(tgt_pixel[0] * w)), int(floorf(tgt_pixel[1] * h))};
2664
2665 /* If current pixel uv is outside of texture */
2666 if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
2667 if (bdata->best_index == NOT_FOUND) {
2668 bdata->best_index = OUT_OF_TEXTURE;
2669 }
2670
2671 continue;
2672 }
2673
2674 const PaintUVPoint *tempPoints = data->tempPoints;
2675 int final_index = final_pixel[0] + w * final_pixel[1];
2676
2677 /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
2678 if (final_index == (px + w * py)) {
2679 continue;
2680 }
2681
2682 /* If final point is an "edge pixel", use its "real" neighbor instead */
2683 if (tempPoints[final_index].neighbor_pixel != -1) {
2684 final_index = tempPoints[final_index].neighbor_pixel;
2685
2686 /* If we ended up to our origin point */
2687 if (final_index == (px + w * py)) {
2688 continue;
2689 }
2690 }
2691
2692 const int final_tri_index = tempPoints[final_index].tri_index;
2693 /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
2694 if (!ELEM(final_tri_index, target_tri, -1)) {
2695 /* Check if it's close enough to likely touch the intended triangle. Any triangle
2696 * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
2697 const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
2698 const float threshold = square_f(0.7f) / (w * h);
2699
2700 if (dist_squared_to_corner_tris_uv_edges(corner_tris, mloopuv, final_tri_index, final_pt) >
2701 threshold)
2702 {
2703 continue;
2704 }
2705 }
2706
2707 bdata->best_index = final_index;
2708 bdata->best_weight = dist_squared;
2709 }
2710}
2711
2712static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
2713{
2714 const int idx = ed->n_index[index];
2715
2716 for (int i = 0; i < ed->n_num[index]; i++) {
2717 if (ed->n_target[idx + i] == neighbor) {
2718 return true;
2719 }
2720 }
2721
2722 return false;
2723}
2724
2725/* Makes the adjacency data symmetric, except for border pixels.
2726 * I.e. if A is neighbor of B, B is neighbor of A. */
2727static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
2728{
2729 int *new_n_index = static_cast<int *>(
2730 MEM_callocN(sizeof(int) * active_points, "Surface Adj Index"));
2731 int *new_n_num = static_cast<int *>(
2732 MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts"));
2733
2734 if (new_n_num && new_n_index) {
2735 /* Count symmetrized neighbors */
2736 int total_targets = 0;
2737
2738 for (int index = 0; index < active_points; index++) {
2739 total_targets += ed->n_num[index];
2740 new_n_num[index] = ed->n_num[index];
2741 }
2742
2743 for (int index = 0; index < active_points; index++) {
2744 if (ed->flags[index] & ADJ_BORDER_PIXEL) {
2745 continue;
2746 }
2747
2748 for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
2749 const int target = ed->n_target[idx + i];
2750
2751 BLI_assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
2752
2753 if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
2754 new_n_num[target]++;
2755 total_targets++;
2756 }
2757 }
2758 }
2759
2760 /* Allocate a new target map */
2761 int *new_n_target = static_cast<int *>(
2762 MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets"));
2763
2764 if (new_n_target) {
2765 /* Copy existing neighbors to the new map */
2766 int n_pos = 0;
2767
2768 for (int index = 0; index < active_points; index++) {
2769 new_n_index[index] = n_pos;
2770 memcpy(&new_n_target[n_pos],
2771 &ed->n_target[ed->n_index[index]],
2772 sizeof(int) * ed->n_num[index]);
2773
2774 /* Reset count to old, but advance position by new, leaving a gap to fill below. */
2775 n_pos += new_n_num[index];
2776 new_n_num[index] = ed->n_num[index];
2777 }
2778
2779 BLI_assert(n_pos == total_targets);
2780
2781 /* Add symmetrized - this loop behavior must exactly match the count pass above */
2782 for (int index = 0; index < active_points; index++) {
2783 if (ed->flags[index] & ADJ_BORDER_PIXEL) {
2784 continue;
2785 }
2786
2787 for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
2788 const int target = ed->n_target[idx + i];
2789
2790 if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
2791 const int num = new_n_num[target]++;
2792 new_n_target[new_n_index[target] + num] = index;
2793 }
2794 }
2795 }
2796
2797 /* Swap maps */
2798 MEM_freeN(ed->n_target);
2799 ed->n_target = new_n_target;
2800
2801 MEM_freeN(ed->n_index);
2802 ed->n_index = new_n_index;
2803
2804 MEM_freeN(ed->n_num);
2805 ed->n_num = new_n_num;
2806
2807 ed->total_targets = total_targets;
2808 return true;
2809 }
2810 }
2811
2812 if (new_n_index) {
2813 MEM_freeN(new_n_index);
2814 }
2815 if (new_n_num) {
2816 MEM_freeN(new_n_num);
2817 }
2818
2819 return false;
2820}
2821
2823 DynamicPaintSurface *surface,
2824 float *progress,
2825 bool *do_update)
2826{
2827 /* Anti-alias jitter point relative coords. */
2828 const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2829 char uvname[MAX_CUSTOMDATA_LAYER_NAME];
2830 uint32_t active_points = 0;
2831 bool error = false;
2832
2833 PaintSurfaceData *sData;
2834 DynamicPaintCanvasSettings *canvas = surface->canvas;
2835 Mesh *mesh = dynamicPaint_canvas_mesh_get(canvas);
2836
2837 PaintUVPoint *tempPoints = nullptr;
2838 Vec3f *tempWeights = nullptr;
2839 const float(*mloopuv)[2] = nullptr;
2840
2841 Bounds2D *faceBB = nullptr;
2842 int *final_index;
2843
2844 *progress = 0.0f;
2845 *do_update = true;
2846
2847 if (!mesh) {
2848 return setError(canvas, N_("Canvas mesh not updated"));
2849 }
2850 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) {
2851 return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
2852 }
2853
2854 const blender::Span<int> corner_verts = mesh->corner_verts();
2855 const blender::Span<int3> corner_tris = mesh->corner_tris();
2856
2857 /* get uv map */
2860 &mesh->corner_data, CD_PROP_FLOAT2, surface->uvlayer_name, uvname);
2861 mloopuv = static_cast<const float(*)[2]>(
2863 }
2864
2865 /* Check for validity */
2866 if (!mloopuv) {
2867 return setError(canvas, N_("No UV data on canvas"));
2868 }
2869 if (surface->image_resolution < 16 || surface->image_resolution > 8192) {
2870 return setError(canvas, N_("Invalid resolution"));
2871 }
2872
2873 const int w = surface->image_resolution;
2874 const int h = w;
2875
2876 /*
2877 * Start generating the surface
2878 */
2879 CLOG_INFO(
2880 &LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, int(corner_tris.size()));
2881
2882 /* Init data struct */
2883 if (surface->data) {
2885 }
2886 sData = surface->data = MEM_cnew<PaintSurfaceData>(__func__);
2887 if (!surface->data) {
2888 return setError(canvas, N_("Not enough free memory"));
2889 }
2890
2891 tempPoints = static_cast<PaintUVPoint *>(
2892 MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint"));
2893 if (!tempPoints) {
2894 error = true;
2895 }
2896
2897 final_index = static_cast<int *>(
2898 MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes"));
2899 if (!final_index) {
2900 error = true;
2901 }
2902
2903 tempWeights = static_cast<Vec3f *>(
2904 MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights"));
2905 if (!tempWeights) {
2906 error = true;
2907 }
2908
2909 /*
2910 * Generate a temporary bounding box array for UV faces to optimize
2911 * the pixel-inside-a-face search.
2912 */
2913 if (!error) {
2914 faceBB = static_cast<Bounds2D *>(
2915 MEM_malloc_arrayN(corner_tris.size(), sizeof(*faceBB), "MPCanvasFaceBB"));
2916 if (!faceBB) {
2917 error = true;
2918 }
2919 }
2920
2921 *progress = 0.01f;
2922 *do_update = true;
2923
2924 if (!error) {
2925 for (const int i : corner_tris.index_range()) {
2926 copy_v2_v2(faceBB[i].min, mloopuv[corner_tris[i][0]]);
2927 copy_v2_v2(faceBB[i].max, mloopuv[corner_tris[i][0]]);
2928
2929 for (int j = 1; j < 3; j++) {
2930 minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[corner_tris[i][j]]);
2931 }
2932 }
2933
2934 *progress = 0.02f;
2935 *do_update = true;
2936
2937 /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
2939 data.surface = surface;
2940 data.tempPoints = tempPoints;
2941 data.tempWeights = tempWeights;
2942 data.corner_tris = corner_tris;
2943 data.mloopuv = mloopuv;
2944 data.corner_verts = corner_verts;
2945 data.faceBB = faceBB;
2946
2947 {
2948 TaskParallelSettings settings;
2950 settings.use_threading = (h > 64 || corner_tris.size() > 1000);
2952 }
2953
2954 *progress = 0.04f;
2955 *do_update = true;
2956
2957 /*
2958 * Now loop through every pixel that was left without index
2959 * and find if they have neighboring pixels that have an index.
2960 * If so use that face as pixel surface.
2961 * (To avoid seams on uv island edges)
2962 */
2963 data.active_points = &active_points;
2964 {
2965 TaskParallelSettings settings;
2967 settings.use_threading = (h > 64);
2969 }
2970
2971 *progress = 0.06f;
2972 *do_update = true;
2973
2974 /* Generate surface adjacency data. */
2975 {
2976 int cursor = 0;
2977
2978 /* Create a temporary array of final indexes (before unassigned
2979 * pixels have been dropped) */
2980 for (int i = 0; i < w * h; i++) {
2981 if (tempPoints[i].tri_index != -1) {
2982 final_index[i] = cursor;
2983 cursor++;
2984 }
2985 }
2986 /* allocate memory */
2987 sData->total_points = w * h;
2988 dynamicPaint_initAdjacencyData(surface, true);
2989
2990 if (sData->adj_data) {
2991 PaintAdjData *ed = sData->adj_data;
2992 int n_pos = 0;
2993
2994 MeshElemMap *vert_to_tri_map;
2995 int *vert_to_tri_map_mem;
2996
2997 BKE_mesh_vert_corner_tri_map_create(&vert_to_tri_map,
2998 &vert_to_tri_map_mem,
2999 mesh->verts_num,
3000 corner_tris.data(),
3001 corner_tris.size(),
3002 corner_verts.data(),
3003 mesh->corners_num);
3004
3005 int total_border = 0;
3006
3007 for (int ty = 0; ty < h; ty++) {
3008 for (int tx = 0; tx < w; tx++) {
3009 const int index = tx + w * ty;
3010
3011 if (tempPoints[index].tri_index != -1) {
3012 ed->n_index[final_index[index]] = n_pos;
3013 ed->n_num[final_index[index]] = 0;
3014
3015 if (tempPoints[index].neighbor_pixel != -1) {
3016 ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
3017 total_border++;
3018 }
3019
3020 for (int i = 0; i < 8; i++) {
3021 /* Try to find a neighboring pixel in defined direction.
3022 * If not found, -1 is returned */
3023 const int n_target = dynamic_paint_find_neighbor_pixel(
3024 &data, vert_to_tri_map, w, h, tx, ty, i);
3025
3026 if (n_target >= 0 && n_target != index) {
3028 ed, final_index[index], final_index[n_target]))
3029 {
3030 ed->n_target[n_pos] = final_index[n_target];
3031 ed->n_num[final_index[index]]++;
3032 n_pos++;
3033 }
3034 }
3035 else if (ELEM(n_target, ON_MESH_EDGE, OUT_OF_TEXTURE)) {
3036 ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
3037 }
3038 }
3039 }
3040 }
3041 }
3042
3043 MEM_freeN(vert_to_tri_map);
3044 MEM_freeN(vert_to_tri_map_mem);
3045
3046 /* Make neighbors symmetric */
3047 if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
3048 error = true;
3049 }
3050
3051 /* Create a list of border pixels */
3052 ed->border = static_cast<int *>(
3053 MEM_callocN(sizeof(int) * total_border, "Border Pixel Index"));
3054
3055 if (ed->border) {
3056 ed->total_border = total_border;
3057
3058 for (int i = 0, next = 0; i < active_points; i++) {
3059 if (ed->flags[i] & ADJ_BORDER_PIXEL) {
3060 ed->border[next++] = i;
3061 }
3062 }
3063 }
3064
3065#if 0
3066 /* -----------------------------------------------------------------
3067 * For debug, write a dump of adjacency data to a file.
3068 * ----------------------------------------------------------------- */
3069 FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
3070 int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
3071 for (int ty = 0; ty < h; ty++) {
3072 for (int tx = 0; tx < w; tx++) {
3073 const int index = tx + w * ty;
3074 if (tempPoints[index].tri_index != -1) {
3075 tmp[final_index[index]] = index;
3076 }
3077 }
3078 }
3079 for (int ty = 0; ty < h; ty++) {
3080 for (int tx = 0; tx < w; tx++) {
3081 const int index = tx + w * ty;
3082 const int fidx = final_index[index];
3083
3084 if (tempPoints[index].tri_index != -1) {
3085 int nidx = tempPoints[index].neighbor_pixel;
3086 fprintf(dump_file,
3087 "%d\t%d,%d\t%u\t%d,%d\t%d\t",
3088 fidx,
3089 tx,
3090 h - 1 - ty,
3091 tempPoints[index].tri_index,
3092 nidx < 0 ? -1 : (nidx % w),
3093 nidx < 0 ? -1 : h - 1 - (nidx / w),
3094 ed->flags[fidx]);
3095 for (int i = 0; i < ed->n_num[fidx]; i++) {
3096 int tgt = tmp[ed->n_target[ed->n_index[fidx] + i]];
3097 fprintf(dump_file, "%s%d,%d", i ? " " : "", tgt % w, h - 1 - tgt / w);
3098 }
3099 fprintf(dump_file, "\n");
3100 }
3101 }
3102 }
3103 MEM_freeN(tmp);
3104 fclose(dump_file);
3105#endif
3106 }
3107 }
3108
3109 *progress = 0.08f;
3110 *do_update = true;
3111
3112 /* Create final surface data without inactive points */
3113 ImgSeqFormatData *f_data = MEM_cnew<ImgSeqFormatData>(__func__);
3114 if (f_data) {
3115 f_data->uv_p = static_cast<PaintUVPoint *>(
3116 MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint"));
3117 f_data->barycentricWeights = static_cast<Vec3f *>(MEM_callocN(
3118 active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint"));
3119
3120 if (!f_data->uv_p || !f_data->barycentricWeights) {
3121 error = true;
3122 }
3123 }
3124 else {
3125 error = true;
3126 }
3127
3128 /* in case of allocation error, free everything */
3129 if (error) {
3130 if (f_data) {
3131 if (f_data->uv_p) {
3132 MEM_freeN(f_data->uv_p);
3133 }
3134 if (f_data->barycentricWeights) {
3136 }
3137 MEM_freeN(f_data);
3138 }
3139 sData->total_points = 0;
3140 }
3141 else {
3142 sData->total_points = int(active_points);
3143 sData->format_data = f_data;
3144
3145 for (int index = 0, cursor = 0; index < (w * h); index++) {
3146 if (tempPoints[index].tri_index != -1) {
3147 memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
3148 memcpy(&f_data->barycentricWeights[cursor * aa_samples],
3149 &tempWeights[index * aa_samples],
3150 sizeof(*tempWeights) * aa_samples);
3151 cursor++;
3152 }
3153 }
3154 }
3155 }
3156 if (error == 1) {
3157 setError(canvas, N_("Not enough free memory"));
3158 }
3159
3160 if (faceBB) {
3161 MEM_freeN(faceBB);
3162 }
3163 if (tempPoints) {
3164 MEM_freeN(tempPoints);
3165 }
3166 if (tempWeights) {
3167 MEM_freeN(tempWeights);
3168 }
3169 if (final_index) {
3170 MEM_freeN(final_index);
3171 }
3172
3173 /* Init surface type data */
3174 if (!error) {
3176
3177#if 0
3178 /* -----------------------------------------------------------------
3179 * For debug, output pixel statuses to the color map
3180 * ----------------------------------------------------------------- */
3181 for (index = 0; index < sData->total_points; index++) {
3182 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
3183 PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
3184 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
3185 pPoint->alpha = 1.0f;
3186
3187 /* Every pixel that is assigned as "edge pixel" gets blue color */
3188 if (uvPoint->neighbor_pixel != -1) {
3189 pPoint->color[2] = 1.0f;
3190 }
3191 /* and every pixel that finally got an face gets red color */
3192 /* green color shows pixel face index hash */
3193 if (uvPoint->tri_index != -1) {
3194 pPoint->color[0] = 1.0f;
3195 pPoint->color[1] = float(uvPoint->tri_index % 255) / 256.0f;
3196 }
3197 }
3198#endif
3199
3200 dynamicPaint_setInitialColor(scene, surface);
3201 }
3202
3203 *progress = 0.09f;
3204 *do_update = true;
3205
3206 return (error == 0);
3207}
3208
3209/*
3210 * Outputs an image file from uv surface data.
3211 */
3216
3217static void dynamic_paint_output_surface_image_paint_cb(void *__restrict userdata,
3218 const int index,
3219 const TaskParallelTLS *__restrict /*tls*/)
3220{
3222 static_cast<const DynamicPaintOutputSurfaceImageData *>(userdata);
3223
3224 const DynamicPaintSurface *surface = data->surface;
3225 const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
3226
3227 ImBuf *ibuf = data->ibuf;
3228 /* image buffer position */
3229 const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3230
3231 /* blend wet and dry layers */
3232 blendColors(point->color,
3233 point->color[3],
3234 point->e_color,
3235 point->e_color[3],
3236 &ibuf->float_buffer.data[pos]);
3237
3238 /* Multiply color by alpha if enabled */
3239 if (surface->flags & MOD_DPAINT_MULALPHA) {
3240 mul_v3_fl(&ibuf->float_buffer.data[pos], ibuf->float_buffer.data[pos + 3]);
3241 }
3242}
3243
3245 void *__restrict userdata, const int index, const TaskParallelTLS *__restrict /*tls*/)
3246{
3248 static_cast<const DynamicPaintOutputSurfaceImageData *>(userdata);
3249
3250 const DynamicPaintSurface *surface = data->surface;
3251 float depth = ((float *)surface->data->type_data)[index];
3252
3253 ImBuf *ibuf = data->ibuf;
3254 /* image buffer position */
3255 const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3256
3257 if (surface->depth_clamp) {
3258 depth /= surface->depth_clamp;
3259 }
3260
3261 if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
3262 depth = (0.5f - depth / 2.0f);
3263 }
3264
3265 CLAMP(depth, 0.0f, 1.0f);
3266
3267 copy_v3_fl(&ibuf->float_buffer.data[pos], depth);
3268 ibuf->float_buffer.data[pos + 3] = 1.0f;
3269}
3270
3271static void dynamic_paint_output_surface_image_wave_cb(void *__restrict userdata,
3272 const int index,
3273 const TaskParallelTLS *__restrict /*tls*/)
3274{
3276 static_cast<const DynamicPaintOutputSurfaceImageData *>(userdata);
3277
3278 const DynamicPaintSurface *surface = data->surface;
3279 const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
3280 float depth = wPoint->height;
3281
3282 ImBuf *ibuf = data->ibuf;
3283 /* image buffer position */
3284 const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3285
3286 if (surface->depth_clamp) {
3287 depth /= surface->depth_clamp;
3288 }
3289
3290 depth = (0.5f + depth / 2.0f);
3291 CLAMP(depth, 0.0f, 1.0f);
3292
3293 copy_v3_fl(&ibuf->float_buffer.data[pos], depth);
3294 ibuf->float_buffer.data[pos + 3] = 1.0f;
3295}
3296
3297static void dynamic_paint_output_surface_image_wetmap_cb(void *__restrict userdata,
3298 const int index,
3299 const TaskParallelTLS *__restrict /*tls*/)
3300{
3302 static_cast<const DynamicPaintOutputSurfaceImageData *>(userdata);
3303
3304 const DynamicPaintSurface *surface = data->surface;
3305 const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
3306
3307 ImBuf *ibuf = data->ibuf;
3308 /* image buffer position */
3309 const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3310
3311 copy_v3_fl(&ibuf->float_buffer.data[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
3312 ibuf->float_buffer.data[pos + 3] = 1.0f;
3313}
3314
3316 const char *filepath,
3317 short output_layer)
3318{
3319 ImBuf *ibuf = nullptr;
3320 PaintSurfaceData *sData = surface->data;
3321 /* OpenEXR or PNG */
3324 char output_file[FILE_MAX];
3325
3326 if (!sData->type_data) {
3327 setError(surface->canvas, N_("Image save failed: invalid surface"));
3328 return;
3329 }
3330 /* if selected format is openexr, but current build doesn't support one */
3331#ifndef WITH_OPENEXR
3334 }
3335#endif
3336 STRNCPY(output_file, filepath);
3337 BKE_image_path_ext_from_imtype_ensure(output_file, sizeof(output_file), format);
3338
3339 /* Validate output file path */
3342
3343 /* Init image buffer */
3344 ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
3345 if (ibuf == nullptr) {
3346 setError(surface->canvas, N_("Image save failed: not enough free memory"));
3347 return;
3348 }
3349
3351 data.surface = surface;
3352 data.ibuf = ibuf;
3353
3354 switch (surface->type) {
3356 switch (output_layer) {
3357 case 0: {
3358 TaskParallelSettings settings;
3360 settings.use_threading = (sData->total_points > 10000);
3362 sData->total_points,
3363 &data,
3365 &settings);
3366 break;
3367 }
3368 case 1: {
3369 TaskParallelSettings settings;
3371 settings.use_threading = (sData->total_points > 10000);
3373 sData->total_points,
3374 &data,
3376 &settings);
3377 break;
3378 }
3379 default:
3380 BLI_assert(0);
3381 break;
3382 }
3383 break;
3385 switch (output_layer) {
3386 case 0: {
3387 TaskParallelSettings settings;
3389 settings.use_threading = (sData->total_points > 10000);
3391 sData->total_points,
3392 &data,
3394 &settings);
3395 break;
3396 }
3397 case 1:
3398 break;
3399 default:
3400 BLI_assert(0);
3401 break;
3402 }
3403 break;
3405 switch (output_layer) {
3406 case 0: {
3407 TaskParallelSettings settings;
3409 settings.use_threading = (sData->total_points > 10000);
3411 sData->total_points,
3412 &data,
3414 &settings);
3415 break;
3416 }
3417 case 1:
3418 break;
3419 default:
3420 BLI_assert(0);
3421 break;
3422 }
3423 break;
3424 default:
3425 BLI_assert(0);
3426 break;
3427 }
3428
3429 /* Set output format, PNG in case EXR isn't supported. */
3430#ifdef WITH_OPENEXR
3431 if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
3432 ibuf->ftype = IMB_FTYPE_OPENEXR;
3434 }
3435 else
3436#endif
3437 {
3438 ibuf->ftype = IMB_FTYPE_PNG;
3439 ibuf->foptions.quality = 15;
3440 }
3441
3442 /* Save image */
3443 IMB_saveiff(ibuf, output_file, IB_rectfloat);
3444 IMB_freeImBuf(ibuf);
3445}
3446
3448
3449/***************************** Ray / Nearest Point Utils ******************************/
3450
3451/* A modified callback to bvh tree ray-cast.
3452 * The tree must have been built using bvhtree_from_mesh_corner_tri.
3453 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
3454 *
3455 * To optimize brush detection speed this doesn't calculate hit coordinates or normal.
3456 */
3457static void mesh_tris_spherecast_dp(void *userdata,
3458 int index,
3459 const BVHTreeRay *ray,
3460 BVHTreeRayHit *hit)
3461{
3462 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
3463 const blender::Span<blender::float3> positions = data->vert_positions;
3464 const int3 *corner_tris = data->corner_tris.data();
3465 const int *corner_verts = data->corner_verts.data();
3466
3467 const float *t0, *t1, *t2;
3468 float dist;
3469
3470 t0 = positions[corner_verts[corner_tris[index][0]]];
3471 t1 = positions[corner_verts[corner_tris[index][1]]];
3472 t2 = positions[corner_verts[corner_tris[index][2]]];
3473
3474 dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
3475
3476 if (dist >= 0 && dist < hit->dist) {
3477 hit->index = index;
3478 hit->dist = dist;
3479 hit->no[0] = 0.0f;
3480 }
3481}
3482
3483/* A modified callback to bvh tree nearest point.
3484 * The tree must have been built using bvhtree_from_mesh_corner_tri.
3485 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
3486 *
3487 * To optimize brush detection speed this doesn't calculate hit normal.
3488 */
3489static void mesh_tris_nearest_point_dp(void *userdata,
3490 int index,
3491 const float co[3],
3492 BVHTreeNearest *nearest)
3493{
3494 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
3495 const blender::Span<blender::float3> positions = data->vert_positions;
3496 const int3 *corner_tris = data->corner_tris.data();
3497 const int *corner_verts = data->corner_verts.data();
3498 float nearest_tmp[3], dist_sq;
3499
3500 const float *t0, *t1, *t2;
3501 t0 = positions[corner_verts[corner_tris[index][0]]];
3502 t1 = positions[corner_verts[corner_tris[index][1]]];
3503 t2 = positions[corner_verts[corner_tris[index][2]]];
3504
3505 closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
3506 dist_sq = len_squared_v3v3(co, nearest_tmp);
3507
3508 if (dist_sq < nearest->dist_sq) {
3509 nearest->index = index;
3510 nearest->dist_sq = dist_sq;
3511 copy_v3_v3(nearest->co, nearest_tmp);
3512 nearest->no[0] = 0.0f;
3513 }
3514}
3515
3516/***************************** Brush Painting Calls ******************************/
3517
3529 const int index,
3530 const int paintFlags,
3531 const float paintColor[3],
3532 const float paintAlpha,
3533 const float paintWetness,
3534 const float timescale)
3535{
3536 PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
3537
3538 /* Add paint */
3539 if (!(paintFlags & MOD_DPAINT_ERASE)) {
3540 float mix[4];
3541 float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
3542
3543 /* mix brush color with wet layer color */
3544 blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
3545 copy_v3_v3(pPoint->e_color, mix);
3546
3547 /* mix wetness and alpha depending on selected alpha mode */
3548 if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
3549 /* update values to the brush level unless they're higher already */
3550 CLAMP_MIN(pPoint->e_color[3], paintAlpha);
3551 CLAMP_MIN(pPoint->wetness, paintWetness);
3552 }
3553 else {
3554 float wetness = paintWetness;
3555 CLAMP(wetness, 0.0f, 1.0f);
3556 pPoint->e_color[3] = mix[3];
3557 pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
3558 }
3559
3560 CLAMP_MIN(pPoint->wetness, MIN_WETNESS);
3561
3562 pPoint->state = DPAINT_PAINT_NEW;
3563 }
3564 /* Erase paint */
3565 else {
3566 float a_ratio, a_highest;
3567 float wetness;
3568 float invFact = 1.0f - paintAlpha;
3569
3570 /*
3571 * Make highest alpha to match erased value
3572 * but maintain alpha ratio
3573 */
3574 if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
3575 a_highest = max_ff(pPoint->color[3], pPoint->e_color[3]);
3576 if (a_highest > invFact) {
3577 a_ratio = invFact / a_highest;
3578
3579 pPoint->e_color[3] *= a_ratio;
3580 pPoint->color[3] *= a_ratio;
3581 }
3582 }
3583 else {
3584 pPoint->e_color[3] -= paintAlpha * timescale;
3585 CLAMP_MIN(pPoint->e_color[3], 0.0f);
3586 pPoint->color[3] -= paintAlpha * timescale;
3587 CLAMP_MIN(pPoint->color[3], 0.0f);
3588 }
3589
3590 wetness = (1.0f - paintWetness) * pPoint->e_color[3];
3591 CLAMP_MAX(pPoint->wetness, wetness);
3592 }
3593}
3594
3595/* applies given brush intersection value for wave surface */
3597 const DynamicPaintBrushSettings *brush,
3598 float isect_height)
3599{
3600 const float isect_change = isect_height - wPoint->brush_isect;
3601 const float wave_factor = brush->wave_factor;
3602 bool hit = false;
3603
3604 /* intersection marked regardless of brush type or hit */
3605 wPoint->brush_isect = isect_height;
3607
3608 isect_height *= wave_factor;
3609
3610 /* determine hit depending on wave_factor */
3611 if (wave_factor > 0.0f && wPoint->height > isect_height) {
3612 hit = true;
3613 }
3614 else if (wave_factor < 0.0f && wPoint->height < isect_height) {
3615 hit = true;
3616 }
3617
3618 if (hit) {
3619 switch (brush->wave_type) {
3621 wPoint->height = isect_height;
3622 wPoint->state = DPAINT_WAVE_OBSTACLE;
3623 wPoint->velocity = 0.0f;
3624 break;
3626 wPoint->velocity = isect_height;
3627 break;
3630 break;
3632 if (isect_change < 0.0f) {
3633 wPoint->height += isect_change * wave_factor;
3634 }
3635 break;
3636 default:
3637 BLI_assert(0);
3638 break;
3639 }
3640 }
3641}
3642
3643/*
3644 * add brush results to the surface data depending on surface type
3645 */
3647 const int index,
3648 const DynamicPaintBrushSettings *brush,
3649 float paint[3],
3650 float influence,
3651 float depth,
3652 float vel_factor,
3653 const float timescale)
3654{
3655 PaintSurfaceData *sData = surface->data;
3656 float strength;
3657
3658 /* apply influence scale */
3659 influence *= surface->influence_scale;
3660 depth *= surface->influence_scale;
3661
3662 strength = influence * brush->alpha;
3663 CLAMP(strength, 0.0f, 1.0f);
3664
3665 /* Sample velocity colorband if required */
3666 if (brush->flags &
3668 {
3669 float coba_res[4];
3670 vel_factor /= brush->max_velocity;
3671 CLAMP(vel_factor, 0.0f, 1.0f);
3672
3673 if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
3674 if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
3675 copy_v3_v3(paint, coba_res);
3676 }
3677 if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA) {
3678 strength *= coba_res[3];
3679 }
3680 if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH) {
3681 depth *= coba_res[3];
3682 }
3683 }
3684 }
3685
3686 /* mix paint surface */
3687 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
3688 float paintWetness = brush->wetness * strength;
3689 float paintAlpha = strength;
3690
3692 surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
3693 }
3694 /* displace surface */
3695 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
3696 float *value = (float *)sData->type_data;
3697
3698 if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
3699 depth = value[index] + depth;
3700 }
3701
3702 if (surface->depth_clamp) {
3703 CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
3704 }
3705
3706 if (brush->flags & MOD_DPAINT_ERASE) {
3707 value[index] *= (1.0f - strength);
3708 CLAMP_MIN(value[index], 0.0f);
3709 }
3710 else {
3711 CLAMP_MIN(value[index], depth);
3712 }
3713 }
3714 /* vertex weight group surface */
3715 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
3716 float *value = (float *)sData->type_data;
3717
3718 if (brush->flags & MOD_DPAINT_ERASE) {
3719 value[index] *= (1.0f - strength);
3720 CLAMP_MIN(value[index], 0.0f);
3721 }
3722 else {
3723 CLAMP_MIN(value[index], strength);
3724 }
3725 }
3726 /* wave surface */
3727 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
3728 if (brush->wave_clamp) {
3729 CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
3730 }
3731
3732 dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
3733 }
3734
3735 /* doing velocity based painting */
3736 if (sData->bData->brush_velocity) {
3737 sData->bData->brush_velocity[index * 4 + 3] *= influence;
3738 }
3739}
3740
3741/* checks whether surface and brush bounds intersect depending on brush type */
3743 Bounds3D *b2,
3745 float brush_radius)
3746{
3747 if (brush->collision == MOD_DPAINT_COL_VOLUME) {
3748 return boundsIntersect(b1, b2);
3749 }
3751 return boundsIntersectDist(b1, b2, brush_radius);
3752 }
3753 return true;
3754}
3755
3756/* calculate velocity for mesh vertices */
3759
3760 const float (*positions_p)[3];
3761 const float (*positions_c)[3];
3762
3763 const float (*obmat)[4];
3765
3767};
3768
3769static void dynamic_paint_brush_velocity_compute_cb(void *__restrict userdata,
3770 const int i,
3771 const TaskParallelTLS *__restrict /*tls*/)
3772{
3774 userdata);
3775
3776 Vec3f *brush_vel = data->brush_vel;
3777
3778 const float(*positions_p)[3] = data->positions_p;
3779 const float(*positions_c)[3] = data->positions_c;
3780
3781 const float(*obmat)[4] = data->obmat;
3782 float(*prev_obmat)[4] = data->prev_obmat;
3783
3784 const float timescale = data->timescale;
3785
3786 float p1[3], p2[3];
3787
3788 copy_v3_v3(p1, positions_p[i]);
3789 mul_m4_v3(prev_obmat, p1);
3790
3791 copy_v3_v3(p2, positions_c[i]);
3792 mul_m4_v3(obmat, p2);
3793
3794 sub_v3_v3v3(brush_vel[i].v, p2, p1);
3795 mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
3796}
3797
3799 Scene *scene,
3800 Object *ob,
3802 Vec3f **brushVel,
3803 float timescale)
3804{
3805 float prev_obmat[4][4];
3806 Mesh *mesh_p, *mesh_c;
3807 int numOfVerts_p, numOfVerts_c;
3808
3809 float cur_sfra = scene->r.subframe;
3810 int cur_fra = scene->r.cfra;
3811 float prev_sfra = cur_sfra - timescale;
3812 int prev_fra = cur_fra;
3813
3814 if (prev_sfra < 0.0f) {
3815 prev_sfra += 1.0f;
3816 prev_fra = cur_fra - 1;
3817 }
3818
3819 /* previous frame mesh */
3820 scene->r.cfra = prev_fra;
3821 scene->r.subframe = prev_sfra;
3822
3824 scene,
3825 ob,
3826 true,
3828 BKE_scene_ctime_get(scene),
3831 numOfVerts_p = mesh_p->verts_num;
3832
3833 float(*positions_p)[3] = reinterpret_cast<float(*)[3]>(
3834 mesh_p->vert_positions_for_write().data());
3835 copy_m4_m4(prev_obmat, ob->object_to_world().ptr());
3836
3837 /* current frame mesh */
3838 scene->r.cfra = cur_fra;
3839 scene->r.subframe = cur_sfra;
3840
3842 scene,
3843 ob,
3844 true,
3846 BKE_scene_ctime_get(scene),
3848 mesh_c = dynamicPaint_brush_mesh_get(brush);
3849 numOfVerts_c = mesh_c->verts_num;
3850 float(*positions_c)[3] = reinterpret_cast<float(*)[3]>(
3851 mesh_c->vert_positions_for_write().data());
3852
3853 (*brushVel) = (Vec3f *)MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
3854 if (!(*brushVel)) {
3855 return;
3856 }
3857
3858 /* If mesh is constructive -> num of verts has changed,
3859 * only use current frame evaluated-mesh. */
3860 if (numOfVerts_p != numOfVerts_c) {
3861 positions_p = positions_c;
3862 }
3863
3864 /* calculate speed */
3866 data.brush_vel = *brushVel;
3867 data.positions_p = positions_p;
3868 data.positions_c = positions_c;
3869 data.obmat = ob->object_to_world().ptr();
3870 data.prev_obmat = prev_obmat;
3871 data.timescale = timescale;
3872
3873 TaskParallelSettings settings;
3875 settings.use_threading = (numOfVerts_c > 10000);
3877 0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, &settings);
3878
3879 BKE_id_free(nullptr, mesh_p);
3880}
3881
3882/* calculate velocity for object center point */
3884 Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
3885{
3886 float prev_obmat[4][4];
3887 float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
3888
3889 float cur_sfra = scene->r.subframe;
3890 int cur_fra = scene->r.cfra;
3891 float prev_sfra = cur_sfra - timescale;
3892 int prev_fra = cur_fra;
3893
3894 if (prev_sfra < 0.0f) {
3895 prev_sfra += 1.0f;
3896 prev_fra = cur_fra - 1;
3897 }
3898
3899 /* previous frame mesh */
3900 scene->r.cfra = prev_fra;
3901 scene->r.subframe = prev_sfra;
3903 scene,
3904 ob,
3905 false,
3907 BKE_scene_ctime_get(scene),
3909 copy_m4_m4(prev_obmat, ob->object_to_world().ptr());
3910
3911 /* current frame mesh */
3912 scene->r.cfra = cur_fra;
3913 scene->r.subframe = cur_sfra;
3915 scene,
3916 ob,
3917 false,
3919 BKE_scene_ctime_get(scene),
3921
3922 /* calculate speed */
3923 mul_m4_v3(prev_obmat, prev_loc);
3924 mul_m4_v3(ob->object_to_world().ptr(), cur_loc);
3925
3926 sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
3927 mul_v3_fl(brushVel->v, 1.0f / timescale);
3928}
3929
3953
3954/*
3955 * Paint a brush object mesh to the surface
3956 */
3957static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata,
3958 const int id,
3959 const TaskParallelTLS *__restrict /*tls*/)
3960{
3961 const DynamicPaintPaintData *data = static_cast<const DynamicPaintPaintData *>(userdata);
3962
3963 const DynamicPaintSurface *surface = data->surface;
3964 const PaintSurfaceData *sData = surface->data;
3965 const PaintBakeData *bData = sData->bData;
3966 DynamicPaintVolumeGrid *grid = bData->grid;
3967
3968 const DynamicPaintBrushSettings *brush = data->brush;
3969
3970 const float timescale = data->timescale;
3971 const int c_index = data->c_index;
3972
3973 const blender::Span<blender::float3> positions = data->positions;
3974 const blender::Span<int> corner_verts = data->corner_verts;
3975 const blender::Span<int3> corner_tris = data->corner_tris;
3976 const float brush_radius = data->brush_radius;
3977 const float *avg_brushNor = data->avg_brushNor;
3978 const Vec3f *brushVelocity = data->brushVelocity;
3979
3980 BVHTreeFromMesh *treeData = static_cast<BVHTreeFromMesh *>(data->treeData);
3981
3982 const int index = grid->t_index[grid->s_pos[c_index] + id];
3983 const int samples = bData->s_num[index];
3984 int ss;
3985 float total_sample = float(samples);
3986 float brushStrength = 0.0f; /* brush influence factor */
3987 float depth = 0.0f; /* brush intersection depth */
3988 float velocity_val = 0.0f;
3989
3990 float paintColor[3] = {0.0f};
3991 int numOfHits = 0;
3992
3993 /* for image sequence anti-aliasing, use gaussian factors */
3994 if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
3995 total_sample = gaussianTotal;
3996 }
3997
3998 /* Super-sampling */
3999 for (ss = 0; ss < samples; ss++) {
4000 float ray_start[3], ray_dir[3];
4001 float sample_factor = 0.0f;
4002 float sampleStrength = 0.0f;
4003 BVHTreeRayHit hit;
4004 BVHTreeNearest nearest;
4005 short hit_found = 0;
4006
4007 /* volume sample */
4008 float volume_factor = 0.0f;
4009 /* proximity sample */
4010 float proximity_factor = 0.0f;
4011 float prox_colorband[4] = {0.0f};
4012 const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
4014
4015 /* hit data */
4016 float hitCoord[3];
4017 int hitTri = -1;
4018
4019 /* Super-sampling factor. */
4020 if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
4021 sample_factor = gaussianFactors[ss];
4022 }
4023 else {
4024 sample_factor = 1.0f;
4025 }
4026
4027 /* Get current sample position in world coordinates */
4028 copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
4029 copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
4030
4031 /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
4032 add_v3_fl(ray_start, 0.001f);
4033
4034 hit.index = -1;
4036 nearest.index = -1;
4037 nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
4038
4039 /* Check volume collision */
4042 treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
4043 if (hit.index != -1) {
4044 /* We hit a triangle, now check if collision point normal is facing the point */
4045
4046 /* For optimization sake, hit point normal isn't calculated in ray cast loop */
4047 const int vtri[3] = {
4048 corner_verts[corner_tris[hit.index][0]],
4049 corner_verts[corner_tris[hit.index][1]],
4050 corner_verts[corner_tris[hit.index][2]],
4051 };
4052 float dot;
4053
4054 normal_tri_v3(hit.no, positions[vtri[0]], positions[vtri[1]], positions[vtri[2]]);
4055 dot = dot_v3v3(ray_dir, hit.no);
4056
4057 /* If ray and hit face normal are facing same direction
4058 * hit point is inside a closed mesh. */
4059 if (dot >= 0.0f) {
4060 const float dist = hit.dist;
4061 const int f_index = hit.index;
4062
4063 /* Also cast a ray in opposite direction to make sure
4064 * point is at least surrounded by two brush faces */
4065 negate_v3(ray_dir);
4066 hit.index = -1;
4068
4070 treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
4071
4072 if (hit.index != -1) {
4073 /* Add factor on super-sample filter. */
4074 volume_factor = 1.0f;
4075 hit_found = HIT_VOLUME;
4076
4077 /* Mark hit info */
4078
4079 /* Calculate final hit coordinates */
4080 madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist);
4081
4082 depth += dist * sample_factor;
4083 hitTri = f_index;
4084 }
4085 }
4086 }
4087 }
4088
4089 /* Check proximity collision */
4091 (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
4092 {
4093 float proxDist = -1.0f;
4094 float hitCo[3] = {0.0f, 0.0f, 0.0f};
4095 int tri = 0;
4096
4097 /* if inverse prox and no hit found, skip this sample */
4098 if (inner_proximity && !hit_found) {
4099 continue;
4100 }
4101
4102 /* If pure distance proximity, find the nearest point on the mesh */
4103 if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
4105 treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
4106 if (nearest.index != -1) {
4107 proxDist = sqrtf(nearest.dist_sq);
4108 copy_v3_v3(hitCo, nearest.co);
4109 tri = nearest.index;
4110 }
4111 }
4112 else { /* else cast a ray in defined projection direction */
4113 float proj_ray[3] = {0.0f};
4114
4115 if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
4116 copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
4117 negate_v3(proj_ray);
4118 }
4119 else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
4120 copy_v3_v3(proj_ray, avg_brushNor);
4121 }
4122 else { /* MOD_DPAINT_RAY_ZPLUS */
4123 proj_ray[2] = 1.0f;
4124 }
4125 hit.index = -1;
4126 hit.dist = brush_radius;
4127
4128 /* Do a face normal directional ray-cast, and use that distance. */
4130 treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
4131 if (hit.index != -1) {
4132 proxDist = hit.dist;
4133
4134 /* Calculate final hit coordinates */
4135 madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist);
4136
4137 tri = hit.index;
4138 }
4139 }
4140
4141 /* If a hit was found, calculate required values */
4142 if (proxDist >= 0.0f && proxDist <= brush_radius) {
4143 proximity_factor = proxDist / brush_radius;
4144 CLAMP(proximity_factor, 0.0f, 1.0f);
4145 if (!inner_proximity) {
4146 proximity_factor = 1.0f - proximity_factor;
4147 }
4148
4149 hit_found = HIT_PROXIMITY;
4150
4151 /* if no volume hit, use prox point face info */
4152 if (hitTri == -1) {
4153 copy_v3_v3(hitCoord, hitCo);
4154 hitTri = tri;
4155 }
4156 }
4157 }
4158
4159 /* mix final sample strength depending on brush settings */
4160 if (hit_found) {
4161 /* If "negate volume" enabled, negate all factors within volume. */
4163 volume_factor = 1.0f - volume_factor;
4164 if (inner_proximity) {
4165 proximity_factor = 1.0f - proximity_factor;
4166 }
4167 }
4168
4169 /* apply final sample depending on final hit type */
4170 if (hit_found == HIT_VOLUME) {
4171 sampleStrength = volume_factor;
4172 }
4173 else if (hit_found == HIT_PROXIMITY) {
4174 /* apply falloff curve to the proximity_factor */
4176 BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
4177 {
4178 proximity_factor = prox_colorband[3];
4179 }
4180 else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
4181 proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f :
4182 0.0f;
4183 }
4184 /* apply sample */
4185 sampleStrength = proximity_factor;
4186 }
4187
4188 sampleStrength *= sample_factor;
4189 }
4190 else {
4191 continue;
4192 }
4193
4194 /* velocity brush, only do on main sample */
4195 if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
4196 float weights[3];
4197 float brushPointVelocity[3];
4198 float velocity[3];
4199
4200 const int v1 = corner_verts[corner_tris[hitTri][0]];
4201 const int v2 = corner_verts[corner_tris[hitTri][1]];
4202 const int v3 = corner_verts[corner_tris[hitTri][2]];
4203
4204 /* calculate barycentric weights for hit point */
4205 interp_weights_tri_v3(weights, positions[v1], positions[v2], positions[v3], hitCoord);
4206
4207 /* Simple check based on brush surface velocity,
4208 * TODO: perhaps implement something that handles volume movement as well. */
4209
4210 /* interpolate vertex speed vectors to get hit point velocity */
4211 interp_v3_v3v3v3(brushPointVelocity,
4212 brushVelocity[v1].v,
4213 brushVelocity[v2].v,
4214 brushVelocity[v3].v,
4215 weights);
4216
4217 /* subtract canvas point velocity */
4218 if (bData->velocity) {
4219 sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
4220 }
4221 else {
4222 copy_v3_v3(velocity, brushPointVelocity);
4223 }
4224 velocity_val = normalize_v3(velocity);
4225
4226 /* if brush has smudge enabled store brush velocity */
4227 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
4228 bData->brush_velocity)
4229 {
4230 copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
4231 bData->brush_velocity[index * 4 + 3] = velocity_val;
4232 }
4233 }
4234
4235 /*
4236 * Process hit color and alpha
4237 */
4238 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4239 float sampleColor[3];
4240 float alpha_factor = 1.0f;
4241
4242 sampleColor[0] = brush->r;
4243 sampleColor[1] = brush->g;
4244 sampleColor[2] = brush->b;
4245
4246 /* Sample proximity colorband if required */
4247 if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
4248 if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
4249 sampleColor[0] = prox_colorband[0];
4250 sampleColor[1] = prox_colorband[1];
4251 sampleColor[2] = prox_colorband[2];
4252 }
4253 }
4254
4255 /* Add AA sample */
4256 paintColor[0] += sampleColor[0];
4257 paintColor[1] += sampleColor[1];
4258 paintColor[2] += sampleColor[2];
4259 sampleStrength *= alpha_factor;
4260 numOfHits++;
4261 }
4262
4263 /* Apply sample strength. */
4264 brushStrength += sampleStrength;
4265 } /* End super-sampling. */
4266
4267 /* If any sample was inside paint range. */
4268 if (brushStrength > 0.0f || depth > 0.0f) {
4269 /* Apply super-sampling results. */
4270 if (samples > 1) {
4271 brushStrength /= total_sample;
4272 }
4273 CLAMP(brushStrength, 0.0f, 1.0f);
4274
4275 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4276 /* Get final pixel color and alpha. */
4277 paintColor[0] /= numOfHits;
4278 paintColor[1] /= numOfHits;
4279 paintColor[2] /= numOfHits;
4280 }
4281 /* Get final object space depth. */
4283 depth /= bData->bNormal[index].normal_scale * total_sample;
4284 }
4285
4287 surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
4288 }
4289}
4290
4291static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
4292 DynamicPaintSurface *surface,
4294 Object *brushOb,
4295 Scene *scene,
4296 float timescale)
4297{
4298 PaintSurfaceData *sData = surface->data;
4299 PaintBakeData *bData = sData->bData;
4300 Mesh *mesh = nullptr;
4301 Vec3f *brushVelocity = nullptr;
4302
4303 if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
4305 depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
4306 }
4307
4308 Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
4309 if (brush_mesh == nullptr) {
4310 return false;
4311 }
4312
4313 {
4314 BVHTreeFromMesh treeData = {nullptr};
4315 float avg_brushNor[3] = {0.0f};
4316 const float brush_radius = brush->paint_distance * surface->radius_scale;
4317 int numOfVerts;
4318 int ii;
4319 Bounds3D mesh_bb = {{0}};
4320 DynamicPaintVolumeGrid *grid = bData->grid;
4321
4322 mesh = BKE_mesh_copy_for_eval(*brush_mesh);
4323 blender::MutableSpan<blender::float3> positions = mesh->vert_positions_for_write();
4324 const blender::Span<blender::float3> vert_normals = mesh->vert_normals();
4325 const blender::Span<int> corner_verts = mesh->corner_verts();
4326 const blender::Span<int3> corner_tris = mesh->corner_tris();
4327 numOfVerts = mesh->verts_num;
4328
4329 /* Transform collider vertices to global space
4330 * (Faster than transforming per surface point
4331 * coordinates and normals to object space) */
4332 for (ii = 0; ii < numOfVerts; ii++) {
4333 mul_m4_v3(brushOb->object_to_world().ptr(), positions[ii]);
4334 boundInsert(&mesh_bb, positions[ii]);
4335
4336 /* for proximity project calculate average normal */
4338 float nor[3];
4339 copy_v3_v3(nor, vert_normals[ii]);
4340 mul_mat3_m4_v3(brushOb->object_to_world().ptr(), nor);
4342
4343 add_v3_v3(avg_brushNor, nor);
4344 }
4345 }
4346
4348 mul_v3_fl(avg_brushNor, 1.0f / float(numOfVerts));
4349 /* instead of null vector use positive z */
4350 if (UNLIKELY(normalize_v3(avg_brushNor) == 0.0f)) {
4351 avg_brushNor[2] = 1.0f;
4352 }
4353 }
4354
4355 /* check bounding box collision */
4356 if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
4357 /* Build a bvh tree from transformed vertices */
4358 if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_CORNER_TRIS, 4)) {
4359 int c_index;
4360 int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
4361
4362 /* loop through space partitioning grid */
4363 for (c_index = 0; c_index < total_cells; c_index++) {
4364 /* check grid cell bounding box */
4365 if (!grid->s_num[c_index] ||
4366 !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
4367 {
4368 continue;
4369 }
4370
4371 /* loop through cell points and process brush */
4373 data.surface = surface;
4374 data.brush = brush;
4375 data.brushOb = brushOb;
4376 data.scene = scene;
4377 data.timescale = timescale;
4378 data.c_index = c_index;
4379 data.mesh = mesh;
4380 data.positions = positions;
4381 data.corner_verts = corner_verts;
4382 data.corner_tris = corner_tris;
4383 data.brush_radius = brush_radius;
4384 data.avg_brushNor = avg_brushNor;
4385 data.brushVelocity = brushVelocity;
4386 data.treeData = &treeData;
4387
4388 TaskParallelSettings settings;
4390 settings.use_threading = (grid->s_num[c_index] > 250);
4392 grid->s_num[c_index],
4393 &data,
4395 &settings);
4396 }
4397 }
4398 }
4399 /* free bvh tree */
4400 free_bvhtree_from_mesh(&treeData);
4401 BKE_id_free(nullptr, mesh);
4402 }
4403
4404 /* free brush velocity data */
4405 if (brushVelocity) {
4406 MEM_freeN(brushVelocity);
4407 }
4408
4409 return true;
4410}
4411
4412/*
4413 * Paint a particle system to the surface
4414 */
4416 void *__restrict userdata, const int id, const TaskParallelTLS *__restrict /*tls*/)
4417{
4418 const DynamicPaintPaintData *data = static_cast<const DynamicPaintPaintData *>(userdata);
4419
4420 const DynamicPaintSurface *surface = data->surface;
4421 const PaintSurfaceData *sData = surface->data;
4422 const PaintBakeData *bData = sData->bData;
4423 DynamicPaintVolumeGrid *grid = bData->grid;
4424
4425 const DynamicPaintBrushSettings *brush = data->brush;
4426
4427 const ParticleSystem *psys = data->psys;
4428
4429 const float timescale = data->timescale;
4430 const int c_index = data->c_index;
4431
4432 KDTree_3d *tree = static_cast<KDTree_3d *>(data->treeData);
4433
4434 const float solidradius = data->solidradius;
4435 const float smooth = brush->particle_smooth * surface->radius_scale;
4436 const float range = solidradius + smooth;
4437 const float particle_timestep = 0.04f * psys->part->timetweak;
4438
4439 const int index = grid->t_index[grid->s_pos[c_index] + id];
4440 float disp_intersect = 0.0f;
4441 float radius = 0.0f;
4442 float strength = 0.0f;
4443 int part_index = -1;
4444
4445 /*
4446 * With predefined radius, there is no variation between particles.
4447 * It's enough to just find the nearest one.
4448 */
4449 {
4450 KDTreeNearest_3d nearest;
4451 float smooth_range, part_solidradius;
4452
4453 /* Find nearest particle and get distance to it */
4454 BLI_kdtree_3d_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
4455 /* if outside maximum range, no other particle can influence either */
4456 if (nearest.dist > range) {
4457 return;
4458 }
4459
4460 if (brush->flags & MOD_DPAINT_PART_RAD) {
4461 /* use particles individual size */
4462 ParticleData *pa = psys->particles + nearest.index;
4463 part_solidradius = pa->size;
4464 }
4465 else {
4466 part_solidradius = solidradius;
4467 }
4468 radius = part_solidradius + smooth;
4469 if (nearest.dist < radius) {
4470 /* distances inside solid radius has maximum influence -> dist = 0 */
4471 smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
4472 /* do smoothness if enabled */
4473 if (smooth) {
4474 smooth_range /= smooth;
4475 }
4476
4477 strength = 1.0f - smooth_range;
4478 disp_intersect = radius - nearest.dist;
4479 part_index = nearest.index;
4480 }
4481 }
4482 /* If using random per particle radius and closest particle didn't give max influence */
4483 if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
4484 /*
4485 * If we use per particle radius, we have to sample all particles
4486 * within max radius range
4487 */
4488 KDTreeNearest_3d *nearest;
4489
4490 float smooth_range = smooth * (1.0f - strength), dist;
4491 /* calculate max range that can have particles with higher influence than the nearest one */
4492 const float max_range = smooth - strength * smooth + solidradius;
4493 /* Make gcc happy! */
4494 dist = max_range;
4495
4496 const int particles = BLI_kdtree_3d_range_search(
4497 tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
4498
4499 /* Find particle that produces highest influence */
4500 for (int n = 0; n < particles; n++) {
4501 ParticleData *pa = &psys->particles[nearest[n].index];
4502
4503 /* skip if out of range */
4504 if (nearest[n].dist > (pa->size + smooth)) {
4505 continue;
4506 }
4507
4508 /* update hit data */
4509 const float s_range = nearest[n].dist - pa->size;
4510 /* skip if higher influence is already found */
4511 if (smooth_range < s_range) {
4512 continue;
4513 }
4514
4515 /* update hit data */
4516 smooth_range = s_range;
4517 dist = nearest[n].dist;
4518 part_index = nearest[n].index;
4519
4520 /* If inside solid range and no disp depth required, no need to seek further */
4521 if ((s_range < 0.0f) &&
4523 {
4524 break;
4525 }
4526 }
4527
4528 if (nearest) {
4529 MEM_freeN(nearest);
4530 }
4531
4532 /* now calculate influence for this particle */
4533 const float rad = radius + smooth;
4534 if ((rad - dist) > disp_intersect) {
4535 disp_intersect = radius - dist;
4536 radius = rad;
4537 }
4538
4539 /* do smoothness if enabled */
4540 CLAMP_MIN(smooth_range, 0.0f);
4541 if (smooth) {
4542 smooth_range /= smooth;
4543 }
4544
4545 const float str = 1.0f - smooth_range;
4546 /* if influence is greater, use this one */
4547 if (str > strength) {
4548 strength = str;
4549 }
4550 }
4551
4552 if (strength > 0.001f) {
4553 float paintColor[4] = {0.0f};
4554 float depth = 0.0f;
4555 float velocity_val = 0.0f;
4556
4557 /* apply velocity */
4558 if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
4559 float velocity[3];
4560 ParticleData *pa = psys->particles + part_index;
4561 mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
4562
4563 /* subtract canvas point velocity */
4564 if (bData->velocity) {
4565 sub_v3_v3(velocity, bData->velocity[index].v);
4566 }
4567 velocity_val = normalize_v3(velocity);
4568
4569 /* store brush velocity for smudge */
4570 if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
4571 (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
4572 {
4573 copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
4574 bData->brush_velocity[index * 4 + 3] = velocity_val;
4575 }
4576 }
4577
4578 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4579 copy_v3_v3(paintColor, &brush->r);
4580 }
4582 /* get displace depth */
4583 disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
4584 depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
4585 }
4586
4588 surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
4589 }
4590}
4591
4593 ParticleSystem *psys,
4595 float timescale)
4596{
4597 ParticleSettings *part = psys->part;
4598 PaintSurfaceData *sData = surface->data;
4599 PaintBakeData *bData = sData->bData;
4600 DynamicPaintVolumeGrid *grid = bData->grid;
4601
4602 KDTree_3d *tree;
4603 int particlesAdded = 0;
4604 int invalidParticles = 0;
4605 int p = 0;
4606
4607 const float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ?
4608 part->size :
4609 brush->particle_radius);
4610 const float smooth = brush->particle_smooth * surface->radius_scale;
4611
4612 const float range = solidradius + smooth;
4613
4614 Bounds3D part_bb = {{0}};
4615
4616 if (psys->totpart < 1) {
4617 return true;
4618 }
4619
4620 /*
4621 * Build a KD-tree to optimize distance search
4622 */
4623 tree = BLI_kdtree_3d_new(psys->totpart);
4624
4625 /* loop through particles and insert valid ones to the tree */
4626 p = 0;
4627 for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
4628 /* Proceed only if particle is active */
4629 if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
4630 (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) || (pa->flag & PARS_UNEXIST))
4631 {
4632 continue;
4633 }
4634
4635 /* for debug purposes check if any NAN particle proceeds
4636 * For some reason they get past activity check, this should rule most of them out */
4637 if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
4638 invalidParticles++;
4639 continue;
4640 }
4641
4642 /* make sure particle is close enough to canvas */
4643 if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) {
4644 continue;
4645 }
4646
4647 BLI_kdtree_3d_insert(tree, p, pa->state.co);
4648
4649 /* calc particle system bounds */
4650 boundInsert(&part_bb, pa->state.co);
4651
4652 particlesAdded++;
4653 }
4654 if (invalidParticles) {
4655 CLOG_WARN(&LOG, "Invalid particle(s) found!");
4656 }
4657
4658 /* If no suitable particles were found, exit */
4659 if (particlesAdded < 1) {
4660 BLI_kdtree_3d_free(tree);
4661 return true;
4662 }
4663
4664 /* only continue if particle bb is close enough to canvas bb */
4665 if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
4666 int c_index;
4667 int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
4668
4669 /* balance tree */
4670 BLI_kdtree_3d_balance(tree);
4671
4672 /* loop through space partitioning grid */
4673 for (c_index = 0; c_index < total_cells; c_index++) {
4674 /* check cell bounding box */
4675 if (!grid->s_num[c_index] || !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range)) {
4676 continue;
4677 }
4678
4679 /* loop through cell points */
4681 data.surface = surface;
4682 data.brush = brush;
4683 data.psys = psys;
4684 data.solidradius = solidradius;
4685 data.timescale = timescale;
4686 data.c_index = c_index;
4687 data.treeData = tree;
4688
4689 TaskParallelSettings settings;
4691 settings.use_threading = (grid->s_num[c_index] > 250);
4693 grid->s_num[c_index],
4694 &data,
4696 &settings);
4697 }
4698 }
4699 BLI_kdtree_3d_free(tree);
4700
4701 return true;
4702}
4703
4704/* paint a single point of defined proximity radius to the surface */
4705static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata,
4706 const int index,
4707 const TaskParallelTLS *__restrict /*tls*/)
4708{
4709 const DynamicPaintPaintData *data = static_cast<const DynamicPaintPaintData *>(userdata);
4710
4711 const DynamicPaintSurface *surface = data->surface;
4712 const PaintSurfaceData *sData = surface->data;
4713 const PaintBakeData *bData = sData->bData;
4714
4715 const DynamicPaintBrushSettings *brush = data->brush;
4716
4717 const float timescale = data->timescale;
4718
4719 const float brush_radius = data->brush_radius;
4720 const Vec3f *brushVelocity = data->brushVelocity;
4721
4722 float *pointCoord = data->pointCoord;
4723
4724 const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
4725 float colorband[4] = {0.0f};
4726 float strength;
4727
4728 if (distance > brush_radius) {
4729 return;
4730 }
4731
4732 /* Smooth range or color ramp */
4734 strength = 1.0f - distance / brush_radius;
4735 CLAMP(strength, 0.0f, 1.0f);
4736 }
4737 else {
4738 strength = 1.0f;
4739 }
4740
4741 if (strength >= 0.001f) {
4742 float paintColor[3] = {0.0f};
4743 float depth = 0.0f;
4744 float velocity_val = 0.0f;
4745
4746 /* color ramp */
4748 BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
4749 {
4750 strength = colorband[3];
4751 }
4752
4753 if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
4754 float velocity[3];
4755
4756 /* subtract canvas point velocity */
4757 if (bData->velocity) {
4758 sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
4759 }
4760 else {
4761 copy_v3_v3(velocity, brushVelocity->v);
4762 }
4763 velocity_val = len_v3(velocity);
4764
4765 /* store brush velocity for smudge */
4766 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
4767 bData->brush_velocity)
4768 {
4769 mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
4770 bData->brush_velocity[index * 4 + 3] = velocity_val;
4771 }
4772 }
4773
4774 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4776 !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
4777 {
4778 paintColor[0] = colorband[0];
4779 paintColor[1] = colorband[1];
4780 paintColor[2] = colorband[2];
4781 }
4782 else {
4783 paintColor[0] = brush->r;
4784 paintColor[1] = brush->g;
4785 paintColor[2] = brush->b;
4786 }
4787 }
4789 /* get displace depth */
4790 const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) *
4791 brush_radius;
4792 depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
4793 }
4795 surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
4796 }
4797}
4798
4800 Depsgraph *depsgraph,
4801 DynamicPaintSurface *surface,
4802 /* Cannot be const, because it is assigned to non-const variable.
4803 * NOLINTNEXTLINE: readability-non-const-parameter. */
4804 float *pointCoord,
4806 Object *brushOb,
4807 Scene *scene,
4808 float timescale)
4809{
4810 PaintSurfaceData *sData = surface->data;
4811 float brush_radius = brush->paint_distance * surface->radius_scale;
4812 Vec3f brushVel;
4813
4814 if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
4815 dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
4816 }
4817
4818 const Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
4819
4820 /*
4821 * Loop through every surface point
4822 */
4824 data.surface = surface;
4825 data.brush = brush;
4826 data.brushOb = brushOb;
4827 data.scene = scene;
4828 data.timescale = timescale;
4829 data.positions = brush_mesh->vert_positions();
4830 data.brush_radius = brush_radius;
4831 data.brushVelocity = &brushVel;
4832 data.pointCoord = pointCoord;
4833
4834 TaskParallelSettings settings;
4836 settings.use_threading = (sData->total_points > 1000);
4839
4840 return true;
4841}
4842
4843/***************************** Dynamic Paint Step / Baking ******************************/
4844
4845/*
4846 * Calculate current frame distances and directions for adjacency data
4847 */
4848
4849static void dynamic_paint_prepare_adjacency_cb(void *__restrict userdata,
4850 const int index,
4851 const TaskParallelTLS *__restrict /*tls*/)
4852{
4853 PaintSurfaceData *sData = static_cast<PaintSurfaceData *>(userdata);
4854 PaintBakeData *bData = sData->bData;
4855 BakeAdjPoint *bNeighs = bData->bNeighs;
4856 PaintAdjData *adj_data = sData->adj_data;
4857 Vec3f *realCoord = bData->realCoord;
4858
4859 const int num_neighs = adj_data->n_num[index];
4860
4861 for (int i = 0; i < num_neighs; i++) {
4862 const int n_index = adj_data->n_index[index] + i;
4863 const int t_index = adj_data->n_target[n_index];
4864
4865 /* dir vec */
4866 sub_v3_v3v3(bNeighs[n_index].dir,
4867 realCoord[bData->s_pos[t_index]].v,
4868 realCoord[bData->s_pos[index]].v);
4869 /* dist */
4870 bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
4871 }
4872}
4873
4874static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
4875{
4876 PaintSurfaceData *sData = surface->data;
4877 PaintBakeData *bData = sData->bData;
4878 BakeAdjPoint *bNeighs;
4879 PaintAdjData *adj_data = sData->adj_data;
4880
4881 int index;
4882
4883 if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) {
4884 return;
4885 }
4886
4887 if (bData->bNeighs) {
4888 MEM_freeN(bData->bNeighs);
4889 }
4890 bNeighs = bData->bNeighs = static_cast<BakeAdjPoint *>(
4891 MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake"));
4892 if (!bNeighs) {
4893 return;
4894 }
4895
4896 TaskParallelSettings settings;
4898 settings.use_threading = (sData->total_points > 1000);
4900 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
4901
4902 /* calculate average values (single thread).
4903 * NOTE: tried to put this in threaded callback (using _reduce feature),
4904 * but gave ~30% slower result! */
4905 bData->average_dist = 0.0;
4906 for (index = 0; index < sData->total_points; index++) {
4907 int numOfNeighs = adj_data->n_num[index];
4908
4909 for (int i = 0; i < numOfNeighs; i++) {
4910 bData->average_dist += double(bNeighs[adj_data->n_index[index] + i].dist);
4911 }
4912 }
4913 bData->average_dist /= adj_data->total_targets;
4914}
4915
4916/* Find two adjacency points (closest_id) and influence (closest_d)
4917 * to move paint towards when affected by a force. */
4919 const int index,
4920 const float force[3],
4921 float closest_d[2],
4922 int closest_id[2])
4923{
4924 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
4925 const int numOfNeighs = sData->adj_data->n_num[index];
4926
4927 closest_id[0] = closest_id[1] = -1;
4928 closest_d[0] = closest_d[1] = -1.0f;
4929
4930 /* find closest neigh */
4931 for (int i = 0; i < numOfNeighs; i++) {
4932 const int n_index = sData->adj_data->n_index[index] + i;
4933 const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
4934
4935 if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
4936 closest_d[0] = dir_dot;
4937 closest_id[0] = n_index;
4938 }
4939 }
4940
4941 if (closest_d[0] < 0.0f) {
4942 return;
4943 }
4944
4945 /* find second closest neigh */
4946 for (int i = 0; i < numOfNeighs; i++) {
4947 const int n_index = sData->adj_data->n_index[index] + i;
4948
4949 if (n_index == closest_id[0]) {
4950 continue;
4951 }
4952
4953 const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
4954 const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
4955
4956 /* only accept neighbor at "other side" of the first one in relation to force dir
4957 * so make sure angle between this and closest neigh is greater than first angle. */
4958 if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
4959 closest_d[1] = dir_dot;
4960 closest_id[1] = n_index;
4961 }
4962 }
4963
4964 /* if two valid neighs found, calculate how force effect is divided evenly between them
4965 * (so that d[0] + d[1] = 1.0) */
4966 if (closest_id[1] != -1) {
4967 float force_proj[3];
4968 float tangent[3];
4969 const float neigh_diff = acosf(
4970 dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
4971 float force_intersect;
4972 float temp;
4973
4974 /* project force vector on the plane determined by these two neighbor points
4975 * and calculate relative force angle from it. */
4976 cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
4977 normalize_v3(tangent);
4978 force_intersect = dot_v3v3(force, tangent);
4979 madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
4980 normalize_v3(force_proj);
4981
4982 /* get drip factor based on force dir in relation to angle between those neighbors */
4983 temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
4984 CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
4985 closest_d[1] = acosf(temp) / neigh_diff;
4986 closest_d[0] = 1.0f - closest_d[1];
4987
4988 /* and multiply depending on how deeply force intersects surface */
4989 temp = fabsf(force_intersect);
4990 CLAMP(temp, 0.0f, 1.0f);
4991 mul_v2_fl(closest_d, acosf(temp) / float(M_PI_2));
4992 }
4993 else {
4994 /* if only single neighbor, still linearize force intersection effect */
4995 closest_d[0] = 1.0f - acosf(closest_d[0]) / float(M_PI_2);
4996 }
4997}
4998
5001 float timescale)
5002{
5003 PaintSurfaceData *sData = surface->data;
5004 PaintBakeData *bData = sData->bData;
5005 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5006 float max_velocity = 0.0f;
5007
5008 if (!sData->adj_data) {
5009 return;
5010 }
5011
5012 /* find max velocity */
5013 for (int index = 0; index < sData->total_points; index++) {
5014 float vel = bData->brush_velocity[index * 4 + 3];
5015 CLAMP_MIN(max_velocity, vel);
5016 }
5017
5018 int steps = int(ceil(double(max_velocity) / bData->average_dist * double(timescale)));
5019 CLAMP(steps, 0, 12);
5020 float eff_scale = brush->smudge_strength / float(steps) * timescale;
5021
5022 for (int step = 0; step < steps; step++) {
5023 for (int index = 0; index < sData->total_points; index++) {
5024
5025 if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5026 continue;
5027 }
5028
5029 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5030 float smudge_str = bData->brush_velocity[index * 4 + 3];
5031
5032 /* force targets */
5033 int closest_id[2];
5034 float closest_d[2];
5035
5036 if (!smudge_str) {
5037 continue;
5038 }
5039
5040 /* get force affect points */
5042 sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
5043
5044 /* Apply movement towards those two points */
5045 for (int i = 0; i < 2; i++) {
5046 int n_index = closest_id[i];
5047 if (n_index != -1 && closest_d[i] > 0.0f) {
5048 float dir_dot = closest_d[i], dir_factor;
5049 float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
5050 PaintPoint *ePoint = &(
5051 (PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
5052
5053 /* just skip if angle is too extreme */
5054 if (dir_dot <= 0.0f) {
5055 continue;
5056 }
5057
5058 dir_factor = dir_dot * speed_scale;
5059 CLAMP_MAX(dir_factor, brush->smudge_strength);
5060
5061 /* mix new color and alpha */
5062 mixColors(ePoint->color, ePoint->color[3], pPoint->color, pPoint->color[3], dir_factor);
5063 ePoint->color[3] = ePoint->color[3] * (1.0f - dir_factor) +
5064 pPoint->color[3] * dir_factor;
5065
5066 /* smudge "wet layer" */
5067 mixColors(ePoint->e_color,
5068 ePoint->e_color[3],
5069 pPoint->e_color,
5070 pPoint->e_color[3],
5071 dir_factor);
5072 ePoint->e_color[3] = ePoint->e_color[3] * (1.0f - dir_factor) +
5073 pPoint->e_color[3] * dir_factor;
5074 pPoint->wetness *= (1.0f - dir_factor);
5075 }
5076 }
5077 }
5078 }
5079}
5080
5101
5102/*
5103 * Prepare data required by effects for current frame.
5104 * Returns number of steps required
5105 */
5106static void dynamic_paint_prepare_effect_cb(void *__restrict userdata,
5107 const int index,
5108 const TaskParallelTLS *__restrict /*tls*/)
5109{
5110 const DynamicPaintEffectData *data = static_cast<const DynamicPaintEffectData *>(userdata);
5111
5112 const DynamicPaintSurface *surface = data->surface;
5113 const PaintSurfaceData *sData = surface->data;
5114 const PaintBakeData *bData = sData->bData;
5115 Vec3f *realCoord = bData->realCoord;
5116
5117 Scene *scene = data->scene;
5118
5119 float *force = data->force;
5120 ListBase *effectors = data->effectors;
5121
5122 float forc[3] = {0};
5123 float vel[3] = {0};
5124
5125 /* apply force fields */
5126 if (effectors) {
5127 EffectedPoint epoint;
5128 pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
5129 epoint.vel_to_sec = 1.0f;
5131 effectors, nullptr, surface->effector_weights, &epoint, forc, nullptr, nullptr);
5132 }
5133
5134 /* if global gravity is enabled, add it too */
5136 /* also divide by 10 to about match default gravity
5137 * with default force strength (1.0). */
5138 madd_v3_v3fl(forc,
5140 surface->effector_weights->global_gravity * surface->effector_weights->weight[0] /
5141 10.0f);
5142 }
5143
5144 /* add surface point velocity and acceleration if enabled */
5145 if (bData->velocity) {
5146 if (surface->drip_vel) {
5147 madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
5148 }
5149
5150 /* acceleration */
5151 if (bData->prev_velocity && surface->drip_acc) {
5152 float acc[3];
5153 copy_v3_v3(acc, bData->velocity[index].v);
5154 sub_v3_v3(acc, bData->prev_velocity[index].v);
5155 madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
5156 }
5157 }
5158
5159 /* force strength, and normalize force vec */
5160 force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
5161}
5162
5164 DynamicPaintSurface *surface,
5165 Scene *scene,
5166 Object *ob,
5167 float **force,
5168 float timescale)
5169{
5170 double average_force = 0.0f;
5171 float shrink_speed = 0.0f, spread_speed = 0.0f;
5172 float fastest_effect, avg_dist;
5173 int steps;
5174 PaintSurfaceData *sData = surface->data;
5175 PaintBakeData *bData = sData->bData;
5176
5177 /* Init force data if required */
5178 if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
5179 ListBase *effectors = BKE_effectors_create(
5180 depsgraph, ob, nullptr, surface->effector_weights, false);
5181
5182 /* allocate memory for force data (dir vector + strength) */
5183 *force = static_cast<float *>(
5184 MEM_mallocN(sizeof(float[4]) * sData->total_points, "PaintEffectForces"));
5185
5186 if (*force) {
5188 data.surface = surface;
5189 data.scene = scene;
5190 data.force = *force;
5191 data.effectors = effectors;
5192
5193 TaskParallelSettings settings;
5195 settings.use_threading = (sData->total_points > 1000);
5197 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, &settings);
5198
5199 /* calculate average values (single thread) */
5200 for (int index = 0; index < sData->total_points; index++) {
5201 average_force += double((*force)[index * 4 + 3]);
5202 }
5203 average_force /= sData->total_points;
5204 }
5205 BKE_effectors_free(effectors);
5206 }
5207
5208 /* Get number of required steps using average point distance
5209 * so that just a few ultra close pixels won't increase sub-steps to max. */
5210
5211 /* Adjust number of required sub-step by fastest active effect. */
5212 if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
5213 spread_speed = surface->spread_speed;
5214 }
5215 if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
5216 shrink_speed = surface->shrink_speed;
5217 }
5218
5219 fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
5220 avg_dist = bData->average_dist * double(CANVAS_REL_SIZE) / double(getSurfaceDimension(sData));
5221
5222 steps = int(ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale));
5223 CLAMP(steps, 1, 20);
5224
5225 return steps;
5226}
5227
5231static void dynamic_paint_effect_spread_cb(void *__restrict userdata,
5232 const int index,
5233 const TaskParallelTLS *__restrict /*tls*/)
5234{
5235 const DynamicPaintEffectData *data = static_cast<const DynamicPaintEffectData *>(userdata);
5236
5237 const DynamicPaintSurface *surface = data->surface;
5238 const PaintSurfaceData *sData = surface->data;
5239
5240 if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5241 return;
5242 }
5243
5244 const int numOfNeighs = sData->adj_data->n_num[index];
5245 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5246 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5247 const PaintPoint *prevPoint = static_cast<const PaintPoint *>(data->prevPoint);
5248 const float eff_scale = data->eff_scale;
5249
5250 const int *n_index = sData->adj_data->n_index;
5251 const int *n_target = sData->adj_data->n_target;
5252
5253 /* Loop through neighboring points */
5254 for (int i = 0; i < numOfNeighs; i++) {
5255 const int n_idx = n_index[index] + i;
5256 float w_factor;
5257 const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
5258 const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
5259 eff_scale / bNeighs[n_idx].dist;
5260 const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f *
5261 surface->color_spread_speed;
5262
5263 /* do color mixing */
5264 if (color_mix) {
5265 mixColors(pPoint->e_color,
5266 pPoint->e_color[3],
5267 pPoint_prev->e_color,
5268 pPoint_prev->e_color[3],
5269 color_mix);
5270 }
5271
5272 /* Only continue if surrounding point has higher wetness */
5273 if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS) {
5274 continue;
5275 }
5276
5277 w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
5278 CLAMP(w_factor, 0.0f, 1.0f);
5279
5280 /* mix new wetness and color */
5281 pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
5282 pPoint->e_color[3] = mixColors(pPoint->e_color,
5283 pPoint->e_color[3],
5284 pPoint_prev->e_color,
5285 pPoint_prev->e_color[3],
5286 w_factor);
5287 }
5288}
5289
5290static void dynamic_paint_effect_shrink_cb(void *__restrict userdata,
5291 const int index,
5292 const TaskParallelTLS *__restrict /*tls*/)
5293{
5294 const DynamicPaintEffectData *data = static_cast<const DynamicPaintEffectData *>(userdata);
5295
5296 const DynamicPaintSurface *surface = data->surface;
5297 const PaintSurfaceData *sData = surface->data;
5298
5299 if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5300 return;
5301 }
5302
5303 const int numOfNeighs = sData->adj_data->n_num[index];
5304 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5305 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5306 const PaintPoint *prevPoint = static_cast<const PaintPoint *>(data->prevPoint);
5307 const float eff_scale = data->eff_scale;
5308
5309 const int *n_index = sData->adj_data->n_index;
5310 const int *n_target = sData->adj_data->n_target;
5311
5312 /* Loop through neighboring points */
5313 for (int i = 0; i < numOfNeighs; i++) {
5314 const int n_idx = n_index[index] + i;
5315 const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
5316 eff_scale / bNeighs[n_idx].dist;
5317 const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
5318 float a_factor, ea_factor, w_factor;
5319
5320 /* Check if neighboring point has lower alpha,
5321 * if so, decrease this point's alpha as well. */
5322 if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f) {
5323 continue;
5324 }
5325
5326 /* decrease factor for dry paint alpha */
5327 a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs *
5328 (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale,
5329 0.0f);
5330 /* decrease factor for wet paint alpha */
5331 ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 *
5332 (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale,
5333 0.0f);
5334 /* decrease factor for paint wetness */
5335 w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 *
5336 (pPoint->wetness - pPoint_prev->wetness) * speed_scale,
5337 0.0f);
5338
5339 pPoint->color[3] -= a_factor;
5340 CLAMP_MIN(pPoint->color[3], 0.0f);
5341 pPoint->e_color[3] -= ea_factor;
5342 CLAMP_MIN(pPoint->e_color[3], 0.0f);
5343 pPoint->wetness -= w_factor;
5344 CLAMP_MIN(pPoint->wetness, 0.0f);
5345 }
5346}
5347
5348static void dynamic_paint_effect_drip_cb(void *__restrict userdata,
5349 const int index,
5350 const TaskParallelTLS *__restrict /*tls*/)
5351{
5352 const DynamicPaintEffectData *data = static_cast<const DynamicPaintEffectData *>(userdata);
5353
5354 const DynamicPaintSurface *surface = data->surface;
5355 const PaintSurfaceData *sData = surface->data;
5356
5357 if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5358 return;
5359 }
5360
5361 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5362 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5363 const PaintPoint *prevPoint = static_cast<const PaintPoint *>(data->prevPoint);
5364 const PaintPoint *pPoint_prev = &prevPoint[index];
5365 const float *force = data->force;
5366 const float eff_scale = data->eff_scale;
5367
5368 const int *n_target = sData->adj_data->n_target;
5369
5370 uint8_t *point_locks = data->point_locks;
5371
5372 int closest_id[2];
5373 float closest_d[2];
5374
5375 /* adjust drip speed depending on wetness */
5376 float w_factor = pPoint_prev->wetness - 0.025f;
5377 if (w_factor <= 0) {
5378 return;
5379 }
5380 CLAMP(w_factor, 0.0f, 1.0f);
5381
5382 float ppoint_wetness_diff = 0.0f;
5383
5384 /* get force affect points */
5385 surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
5386
5387 /* Apply movement towards those two points */
5388 for (int i = 0; i < 2; i++) {
5389 const int n_idx = closest_id[i];
5390 if (n_idx != -1 && closest_d[i] > 0.0f) {
5391 const float dir_dot = closest_d[i];
5392
5393 /* just skip if angle is too extreme */
5394 if (dir_dot <= 0.0f) {
5395 continue;
5396 }
5397
5398 float dir_factor, a_factor;
5399 const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
5400
5401 const uint n_trgt = uint(n_target[n_idx]);
5402
5403 /* Sort of spin-lock, but only for given ePoint.
5404 * Since the odds a same ePoint is modified at the same time by several threads is very low,
5405 * this is much more efficient than a global spin lock. */
5406 const uint epointlock_idx = n_trgt / 8;
5407 const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
5408 while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) &
5409 epointlock_bitmask)
5410 {
5411 /* pass */
5412 }
5413
5414 PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
5415 const float e_wet = ePoint->wetness;
5416
5417 dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
5418
5419 /* mix new wetness */
5420 ePoint->wetness += dir_factor;
5421 CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
5422
5423 /* mix new color */
5424 a_factor = dir_factor / pPoint_prev->wetness;
5425 CLAMP(a_factor, 0.0f, 1.0f);
5426 mixColors(ePoint->e_color,
5427 ePoint->e_color[3],
5428 pPoint_prev->e_color,
5429 pPoint_prev->e_color[3],
5430 a_factor);
5431 /* dripping is supposed to preserve alpha level */
5432 if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
5433 ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
5434 CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
5435 }
5436
5437 /* Decrease paint wetness on current point (just store diff here,
5438 * that way we can only lock current point once at the end to apply it). */
5439 ppoint_wetness_diff += (ePoint->wetness - e_wet);
5440
5441#ifndef NDEBUG
5442 {
5443 uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx],
5444 ~epointlock_bitmask);
5445 BLI_assert(ret & epointlock_bitmask);
5446 }
5447#else
5448 atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
5449#endif
5450 }
5451 }
5452
5453 {
5454 const uint ppointlock_idx = index / 8;
5455 const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
5456 while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) &
5457 ppointlock_bitmask)
5458 {
5459 /* pass */
5460 }
5461
5462 pPoint->wetness -= ppoint_wetness_diff;
5463 CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
5464
5465#ifndef NDEBUG
5466 {
5467 uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
5468 BLI_assert(ret & ppointlock_bitmask);
5469 }
5470#else
5471 atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
5472#endif
5473 }
5474}
5475
5477 DynamicPaintSurface *surface,
5478 /* Cannot be const, because it is assigned to non-const variable.
5479 * NOLINTNEXTLINE: readability-non-const-parameter. */
5480 float *force,
5481 PaintPoint *prevPoint,
5482 float timescale,
5483 float steps)
5484{
5485 PaintSurfaceData *sData = surface->data;
5486
5487 const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
5488 timescale /= steps;
5489
5490 if (!sData->adj_data) {
5491 return;
5492 }
5493
5494 /*
5495 * Spread Effect
5496 */
5497 if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
5498 const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed *
5499 timescale;
5500
5501 /* Copy current surface to the previous points array to read unmodified values */
5502 memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintPoint));
5503
5505 data.surface = surface;
5506 data.prevPoint = prevPoint;
5507 data.eff_scale = eff_scale;
5508
5509 TaskParallelSettings settings;
5511 settings.use_threading = (sData->total_points > 1000);
5513 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, &settings);
5514 }
5515
5516 /*
5517 * Shrink Effect
5518 */
5519 if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
5520 const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed *
5521 timescale;
5522
5523 /* Copy current surface to the previous points array to read unmodified values */
5524 memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintPoint));
5525
5527 data.surface = surface;
5528 data.prevPoint = prevPoint;
5529 data.eff_scale = eff_scale;
5530
5531 TaskParallelSettings settings;
5533 settings.use_threading = (sData->total_points > 1000);
5535 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, &settings);
5536 }
5537
5538 /*
5539 * Drip Effect
5540 */
5541 if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
5542 const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
5543
5544 /* Same as #BLI_bitmask, but handled atomically as 'ePoint' locks. */
5545 const size_t point_locks_size = (sData->total_points / 8) + 1;
5546 uint8_t *point_locks = static_cast<uint8_t *>(
5547 MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__));
5548
5549 /* Copy current surface to the previous points array to read unmodified values */
5550 memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintPoint));
5551
5553 data.surface = surface;
5554 data.prevPoint = prevPoint;
5555 data.eff_scale = eff_scale;
5556 data.force = force;
5557 data.point_locks = point_locks;
5558
5559 TaskParallelSettings settings;
5561 settings.use_threading = (sData->total_points > 1000);
5563 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, &settings);
5564
5565 MEM_freeN(point_locks);
5566 }
5567}
5568
5569static void dynamic_paint_border_cb(void *__restrict userdata,
5570 const int b_index,
5571 const TaskParallelTLS *__restrict /*tls*/)
5572{
5573 const DynamicPaintEffectData *data = static_cast<const DynamicPaintEffectData *>(userdata);
5574
5575 const DynamicPaintSurface *surface = data->surface;
5576 const PaintSurfaceData *sData = surface->data;
5577
5578 const int index = sData->adj_data->border[b_index];
5579
5580 const int numOfNeighs = sData->adj_data->n_num[index];
5581 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5582
5583 const int *n_index = sData->adj_data->n_index;
5584 const int *n_target = sData->adj_data->n_target;
5585
5586 /* Average neighboring points. Intermediaries use premultiplied alpha. */
5587 float mix_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
5588 float mix_e_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
5589 float mix_wetness = 0.0f;
5590
5591 for (int i = 0; i < numOfNeighs; i++) {
5592 const int n_idx = n_index[index] + i;
5593 const int target = n_target[n_idx];
5594
5595 PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
5596
5597 BLI_assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
5598
5599 madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
5600 mix_color[3] += pPoint2->color[3];
5601
5602 madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
5603 mix_e_color[3] += pPoint2->e_color[3];
5604
5605 mix_wetness += pPoint2->wetness;
5606 }
5607
5608 const float divisor = 1.0f / numOfNeighs;
5609
5610 if (mix_color[3]) {
5611 pPoint->color[3] = mix_color[3] * divisor;
5612 mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
5613 }
5614 else {
5615 pPoint->color[3] = 0.0f;
5616 }
5617
5618 if (mix_e_color[3]) {
5619 pPoint->e_color[3] = mix_e_color[3] * divisor;
5620 mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
5621 }
5622 else {
5623 pPoint->e_color[3] = 0.0f;
5624 }
5625
5626 pPoint->wetness = mix_wetness / numOfNeighs;
5627}
5628
5630{
5631 PaintSurfaceData *sData = surface->data;
5632
5633 if (!sData->adj_data || !sData->adj_data->border) {
5634 return;
5635 }
5636
5637 /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
5639 data.surface = surface;
5640
5641 TaskParallelSettings settings;
5643 settings.use_threading = (sData->adj_data->total_border > 1000);
5645 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, &settings);
5646}
5647
5648static void dynamic_paint_wave_step_cb(void *__restrict userdata,
5649 const int index,
5650 const TaskParallelTLS *__restrict /*tls*/)
5651{
5652 const DynamicPaintEffectData *data = static_cast<const DynamicPaintEffectData *>(userdata);
5653
5654 const DynamicPaintSurface *surface = data->surface;
5655 const PaintSurfaceData *sData = surface->data;
5656 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5657 const PaintWavePoint *prevPoint = static_cast<const PaintWavePoint *>(data->prevPoint);
5658
5659 const float wave_speed = data->wave_speed;
5660 const float wave_scale = data->wave_scale;
5661 const float wave_max_slope = data->wave_max_slope;
5662
5663 const float dt = data->dt;
5664 const float min_dist = data->min_dist;
5665 const float damp_factor = data->damp_factor;
5666
5667 PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
5668 const int numOfNeighs = sData->adj_data->n_num[index];
5669 float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
5670 int numOfN = 0, numOfRN = 0;
5671
5672 if (wPoint->state > 0) {
5673 return;
5674 }
5675
5676 const int *n_index = sData->adj_data->n_index;
5677 const int *n_target = sData->adj_data->n_target;
5678 const int *adj_flags = sData->adj_data->flags;
5679
5680 /* calculate force from surrounding points */
5681 for (int i = 0; i < numOfNeighs; i++) {
5682 const int n_idx = n_index[index] + i;
5683 float dist = bNeighs[n_idx].dist * wave_scale;
5684 const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
5685
5686 if (!dist || tPoint->state > 0) {
5687 continue;
5688 }
5689
5690 CLAMP_MIN(dist, min_dist);
5691 avg_dist += dist;
5692 numOfN++;
5693
5694 /* count average height for edge points for open borders */
5695 if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
5696 avg_n_height += tPoint->height;
5697 numOfRN++;
5698 }
5699
5700 force += (tPoint->height - wPoint->height) / (dist * dist);
5701 avg_height += tPoint->height;
5702 }
5703 avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
5704
5705 if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
5706 /* if open borders, apply a fake height to keep waves going on */
5707 avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
5708 wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
5709 (avg_dist + dt * wave_speed);
5710 }
5711 /* Else do wave equation. */
5712 else {
5713 /* add force towards zero height based on average dist */
5714 if (avg_dist) {
5715 force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
5716 }
5717
5718 /* change point velocity */
5719 wPoint->velocity += force * dt * wave_speed * wave_speed;
5720 /* damping */
5721 wPoint->velocity *= damp_factor;
5722 /* and new height */
5723 wPoint->height += wPoint->velocity * dt;
5724
5725 /* limit wave slope steepness */
5726 if (wave_max_slope && avg_dist) {
5727 const float max_offset = wave_max_slope * avg_dist;
5728 const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
5729 if (offset > max_offset) {
5730 wPoint->height += offset - max_offset;
5731 }
5732 else if (offset < -max_offset) {
5733 wPoint->height += offset + max_offset;
5734 }
5735 }
5736 }
5737
5738 if (data->reset_wave) {
5739 /* if there wasn't any brush intersection, clear isect height */
5740 if (wPoint->state == DPAINT_WAVE_NONE) {
5741 wPoint->brush_isect = 0.0f;
5742 }
5743 wPoint->state = DPAINT_WAVE_NONE;
5744 }
5745}
5746
5747static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
5748{
5749 PaintSurfaceData *sData = surface->data;
5750 BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5751 int index;
5752 int steps, ss;
5753 float dt, min_dist, damp_factor;
5754 const float wave_speed = surface->wave_speed;
5755 const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ?
5756 (0.5f / surface->wave_smoothness) :
5757 0.0f;
5758 double average_dist = 0.0f;
5759 const float canvas_size = getSurfaceDimension(sData);
5760 const float wave_scale = CANVAS_REL_SIZE / canvas_size;
5761
5762 /* allocate memory */
5763 PaintWavePoint *prevPoint = static_cast<PaintWavePoint *>(
5764 MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), __func__));
5765 if (!prevPoint) {
5766 return;
5767 }
5768
5769 /* calculate average neigh distance (single thread) */
5770 for (index = 0; index < sData->total_points; index++) {
5771 int numOfNeighs = sData->adj_data->n_num[index];
5772
5773 for (int i = 0; i < numOfNeighs; i++) {
5774 average_dist += double(bNeighs[sData->adj_data->n_index[index] + i].dist);
5775 }
5776 }
5777 average_dist *= double(wave_scale) / sData->adj_data->total_targets;
5778
5779 /* determine number of required steps */
5780 steps = int(ceil(double(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
5781 (average_dist / double(wave_speed) / 3)));
5782 CLAMP(steps, 1, 20);
5783 timescale /= steps;
5784
5785 /* apply simulation values for final timescale */
5786 dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
5787 min_dist = wave_speed * dt * 1.5f;
5788 damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
5789
5790 for (ss = 0; ss < steps; ss++) {
5791 /* copy previous frame data */
5792 memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
5793
5795 data.surface = surface;
5796 data.prevPoint = prevPoint;
5797 data.wave_speed = wave_speed;
5798 data.wave_scale = wave_scale;
5799 data.wave_max_slope = wave_max_slope;
5800 data.dt = dt;
5801 data.min_dist = min_dist;
5802 data.damp_factor = damp_factor;
5803 data.reset_wave = (ss == steps - 1);
5804
5805 TaskParallelSettings settings;
5807 settings.use_threading = (sData->total_points > 1000);
5809 }
5810
5811 MEM_freeN(prevPoint);
5812}
5813
5814/* Do dissolve and fading effects */
5822
5827
5828static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata,
5829 const int index,
5830 const TaskParallelTLS *__restrict /*tls*/)
5831{
5832 const DynamicPaintDissolveDryData *data = static_cast<const DynamicPaintDissolveDryData *>(
5833 userdata);
5834
5835 const DynamicPaintSurface *surface = data->surface;
5836 const PaintSurfaceData *sData = surface->data;
5837 const float timescale = data->timescale;
5838
5839 /* Do drying dissolve effects */
5840 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
5841 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5842 /* drying */
5843 if (surface->flags & MOD_DPAINT_USE_DRYING) {
5844 if (pPoint->wetness >= MIN_WETNESS) {
5845 float f_color[4];
5846 float p_wetness = pPoint->wetness;
5847
5848 value_dissolve(&pPoint->wetness,
5849 surface->dry_speed,
5850 timescale,
5851 (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
5852 CLAMP_MIN(pPoint->wetness, 0.0f);
5853
5854 if (pPoint->wetness < surface->color_dry_threshold) {
5855 float dry_ratio = pPoint->wetness / p_wetness;
5856
5857 /*
5858 * Slowly "shift" paint from wet layer to dry layer as it drys:
5859 */
5860 /* make sure alpha values are within proper range */
5861 CLAMP(pPoint->color[3], 0.0f, 1.0f);
5862 CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
5863
5864 /* get current final blended color of these layers */
5866 pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
5867 /* reduce wet layer alpha by dry factor */
5868 pPoint->e_color[3] *= dry_ratio;
5869
5870 /* Now calculate new alpha for dry layer that keeps final blended color unchanged. */
5871 pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
5872 /* For each rgb component, calculate a new dry layer color that keeps the final blend
5873 * color with these new alpha values. (wet layer color doesn't change). */
5874 if (pPoint->color[3]) {
5875 for (int i = 0; i < 3; i++) {
5876 pPoint->color[i] = (f_color[i] * f_color[3] -
5877 pPoint->e_color[i] * pPoint->e_color[3]) /
5878 (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
5879 }
5880 }
5881 }
5882
5883 pPoint->state = DPAINT_PAINT_WET;
5884 }
5885 /* In case of just dried paint, just mix it to the dry layer and mark it empty. */
5886 else if (pPoint->state > 0) {
5887 float f_color[4];
5888 blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
5889 copy_v4_v4(pPoint->color, f_color);
5890 /* clear wet layer */
5891 pPoint->wetness = 0.0f;
5892 pPoint->e_color[3] = 0.0f;
5893 pPoint->state = DPAINT_PAINT_DRY;
5894 }
5895 }
5896
5897 if (surface->flags & MOD_DPAINT_DISSOLVE) {
5898 value_dissolve(&pPoint->color[3],
5899 surface->diss_speed,
5900 timescale,
5901 (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
5902 CLAMP_MIN(pPoint->color[3], 0.0f);
5903
5904 value_dissolve(&pPoint->e_color[3],
5905 surface->diss_speed,
5906 timescale,
5907 (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
5908 CLAMP_MIN(pPoint->e_color[3], 0.0f);
5909 }
5910 }
5911 /* dissolve for float types */
5912 else if (surface->flags & MOD_DPAINT_DISSOLVE &&
5914 {
5915 float *point = &((float *)sData->type_data)[index];
5916 /* log or linear */
5918 point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
5919 CLAMP_MIN(*point, 0.0f);
5920 }
5921}
5922
5924{
5925 PaintSurfaceData *sData = surface->data;
5926 PaintBakeData *bData = sData->bData;
5927 Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
5928 const blender::Span<blender::float3> positions = mesh->vert_positions();
5929
5930 int numOfVerts = mesh->verts_num;
5931
5932 if (!bData->prev_positions) {
5933 return true;
5934 }
5935
5936 /* matrix comparison */
5937 if (!equals_m4m4(bData->prev_obmat, ob->object_to_world().ptr())) {
5938 return true;
5939 }
5940
5941 /* vertices */
5942 for (int i = 0; i < numOfVerts; i++) {
5943 if (!equals_v3v3(bData->prev_positions[i], positions[i])) {
5944 return true;
5945 }
5946 }
5947
5948 return false;
5949}
5950
5951/* Prepare for surface step by creating PaintBakeNormal data */
5963
5964static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
5965 const int index,
5966 const TaskParallelTLS *__restrict /*tls*/)
5967{
5969 userdata);
5970
5971 const DynamicPaintSurface *surface = data->surface;
5972 const PaintSurfaceData *sData = surface->data;
5973 const PaintAdjData *adj_data = sData->adj_data;
5974 const PaintBakeData *bData = sData->bData;
5975
5976 Object *ob = data->ob;
5977
5978 const Vec3f *canvas_verts = data->canvas_verts;
5979
5980 const bool do_velocity_data = data->do_velocity_data;
5981 const bool new_bdata = data->new_bdata;
5982
5983 float prev_point[3] = {0.0f, 0.0f, 0.0f};
5984 float temp_nor[3];
5985
5986 if (do_velocity_data && !new_bdata) {
5987 copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
5988 }
5989
5990 /*
5991 * Calculate current 3D-position and normal of each surface point
5992 */
5993 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
5994 float n1[3], n2[3], n3[3];
5995 const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
5996 const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
5997
5998 bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
5999 bData->s_pos[index] = index * bData->s_num[index];
6000
6001 /* per sample coordinates */
6002 for (int ss = 0; ss < bData->s_num[index]; ss++) {
6003 interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
6004 canvas_verts[tPoint->v1].v,
6005 canvas_verts[tPoint->v2].v,
6006 canvas_verts[tPoint->v3].v,
6007 f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
6008 }
6009
6010 /* Calculate current pixel surface normal */
6011 copy_v3_v3(n1, data->vert_normals[tPoint->v1]);
6012 copy_v3_v3(n2, data->vert_normals[tPoint->v2]);
6013 copy_v3_v3(n3, data->vert_normals[tPoint->v3]);
6014
6016 temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
6017 normalize_v3(temp_nor);
6019 /* Prepare surface normal directional scale to easily convert
6020 * brush intersection amount between global and local space */
6021 float scaled_nor[3];
6022 mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
6023 bData->bNormal[index].normal_scale = len_v3(scaled_nor);
6024 }
6025 mul_mat3_m4_v3(ob->object_to_world().ptr(), temp_nor);
6026 normalize_v3(temp_nor);
6027 negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
6028 }
6029 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
6030 int ss;
6031 if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
6032 bData->s_num[index] = adj_data->n_num[index] + 1;
6033 bData->s_pos[index] = adj_data->n_index[index] + index;
6034 }
6035 else {
6036 bData->s_num[index] = 1;
6037 bData->s_pos[index] = index;
6038 }
6039
6040 /* calculate position for each sample */
6041 for (ss = 0; ss < bData->s_num[index]; ss++) {
6042 /* first sample is always point center */
6043 copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
6044 if (ss > 0) {
6045 int t_index = adj_data->n_index[index] + (ss - 1);
6046 /* get vertex position at 1/3 of each neigh edge */
6047 mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
6048 madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
6049 canvas_verts[adj_data->n_target[t_index]].v,
6050 1.0f / 3.0f);
6051 }
6052 }
6053
6054 /* normal */
6055 copy_v3_v3(temp_nor, data->vert_normals[index]);
6057 /* Prepare surface normal directional scale to easily convert
6058 * brush intersection amount between global and local space */
6059 float scaled_nor[3];
6060 mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
6061 bData->bNormal[index].normal_scale = len_v3(scaled_nor);
6062 }
6063 mul_mat3_m4_v3(ob->object_to_world().ptr(), temp_nor);
6064 normalize_v3(temp_nor);
6065 negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
6066 }
6067
6068 /* calculate speed vector */
6069 if (do_velocity_data && !new_bdata && !bData->clear) {
6070 sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
6071 }
6072}
6073
6075 Depsgraph *depsgraph,
6076 Object *ob)
6077{
6078 PaintSurfaceData *sData = surface->data;
6079 PaintBakeData *bData = sData->bData;
6080 Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
6081 int index;
6082 bool new_bdata = false;
6083 const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
6084 (surface_getBrushFlags(surface, depsgraph) &
6086 const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
6087
6088 int canvasNumOfVerts = mesh->verts_num;
6089 const blender::Span<blender::float3> positions = mesh->vert_positions();
6090 Vec3f *canvas_verts;
6091
6092 if (bData) {
6093 const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
6094
6095 /* Get previous speed for acceleration. */
6096 if (do_accel_data && bData->prev_velocity && bData->velocity) {
6097 memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
6098 }
6099
6100 /* reset speed vectors */
6101 if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved)) {
6102 memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
6103 }
6104
6105 /* if previous data exists and mesh hasn't moved, no need to recalc */
6106 if (!surface_moved) {
6107 return true;
6108 }
6109 }
6110
6111 canvas_verts = (Vec3f *)MEM_mallocN(canvasNumOfVerts * sizeof(Vec3f),
6112 "Dynamic Paint transformed canvas verts");
6113 if (!canvas_verts) {
6114 return false;
6115 }
6116
6117 /* allocate memory if required */
6118 if (!bData) {
6119 sData->bData = bData = (PaintBakeData *)MEM_callocN(sizeof(PaintBakeData),
6120 "Dynamic Paint bake data");
6121 if (!bData) {
6122 if (canvas_verts) {
6123 MEM_freeN(canvas_verts);
6124 }
6125 return false;
6126 }
6127
6128 /* Init bdata */
6129 bData->bNormal = (PaintBakeNormal *)MEM_mallocN(sData->total_points * sizeof(PaintBakeNormal),
6130 "Dynamic Paint step data");
6131 bData->s_pos = static_cast<int *>(
6132 MEM_mallocN(sData->total_points * sizeof(uint), "Dynamic Paint bData s_pos"));
6133 bData->s_num = static_cast<int *>(
6134 MEM_mallocN(sData->total_points * sizeof(uint), "Dynamic Paint bData s_num"));
6135 bData->realCoord = (Vec3f *)MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f),
6136 "Dynamic Paint point coords");
6137 bData->prev_positions = static_cast<float(*)[3]>(
6138 MEM_mallocN(canvasNumOfVerts * sizeof(float[3]), "Dynamic Paint bData prev_positions"));
6139
6140 /* if any allocation failed, free everything */
6141 if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
6142 if (bData->bNormal) {
6143 MEM_freeN(bData->bNormal);
6144 }
6145 if (bData->s_pos) {
6146 MEM_freeN(bData->s_pos);
6147 }
6148 if (bData->s_num) {
6149 MEM_freeN(bData->s_num);
6150 }
6151 if (bData->realCoord) {
6152 MEM_freeN(bData->realCoord);
6153 }
6154 if (canvas_verts) {
6155 MEM_freeN(canvas_verts);
6156 }
6157
6158 return setError(surface->canvas, N_("Not enough free memory"));
6159 }
6160
6161 new_bdata = true;
6162 }
6163
6164 if (do_velocity_data && !bData->velocity) {
6165 bData->velocity = (Vec3f *)MEM_callocN(sData->total_points * sizeof(Vec3f),
6166 "Dynamic Paint velocity");
6167 }
6168 if (do_accel_data && !bData->prev_velocity) {
6169 bData->prev_velocity = (Vec3f *)MEM_mallocN(sData->total_points * sizeof(Vec3f),
6170 "Dynamic Paint prev velocity");
6171 /* copy previous vel */
6172 if (bData->prev_velocity && bData->velocity) {
6173 memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
6174 }
6175 }
6176
6177 /*
6178 * Make a transformed copy of canvas evaluated-mesh vertices to avoid recalculation.
6179 */
6180 bData->mesh_bounds.valid = false;
6181 for (index = 0; index < canvasNumOfVerts; index++) {
6182 copy_v3_v3(canvas_verts[index].v, positions[index]);
6183 mul_m4_v3(ob->object_to_world().ptr(), canvas_verts[index].v);
6184 boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
6185 }
6186
6187 /*
6188 * Prepare each surface point for a new step
6189 */
6191 data.surface = surface;
6192 data.ob = ob;
6193 data.positions = positions;
6194 data.vert_normals = mesh->vert_normals();
6195 data.canvas_verts = canvas_verts;
6196 data.do_velocity_data = do_velocity_data;
6197 data.new_bdata = new_bdata;
6198
6199 TaskParallelSettings settings;
6201 settings.use_threading = (sData->total_points > 1000);
6203 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, &settings);
6204
6205 MEM_freeN(canvas_verts);
6206
6207 /* generate surface space partitioning grid */
6208 surfaceGenerateGrid(surface);
6209 /* Calculate current frame adjacency point distances and global directions. */
6210 dynamicPaint_prepareAdjacencyData(surface, false);
6211
6212 /* Copy current frame vertices to check against in next frame */
6213 copy_m4_m4(bData->prev_obmat, ob->object_to_world().ptr());
6214 memcpy(bData->prev_positions, positions.data(), canvasNumOfVerts * sizeof(float[3]));
6215
6216 bData->clear = 0;
6217
6218 return true;
6219}
6220
6221/*
6222 * Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
6223 */
6224static int dynamicPaint_doStep(Depsgraph *depsgraph,
6225 Scene *scene,
6226 Object *ob,
6227 DynamicPaintSurface *surface,
6228 float timescale,
6229 float subframe)
6230{
6231 PaintSurfaceData *sData = surface->data;
6232 PaintBakeData *bData = sData->bData;
6233 DynamicPaintCanvasSettings *canvas = surface->canvas;
6234 const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
6235 int ret = 1;
6236
6237 if (sData->total_points < 1) {
6238 return 0;
6239 }
6240
6243 data.surface = surface;
6244 data.timescale = timescale;
6245
6246 TaskParallelSettings settings;
6248 settings.use_threading = (sData->total_points > 1000);
6250 0, sData->total_points, &data, dynamic_paint_surface_pre_step_cb, &settings);
6251 }
6252
6253 /*
6254 * Loop through surface's target paint objects and do painting
6255 */
6256 {
6257 uint numobjects;
6259 depsgraph, nullptr, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
6260
6261 /* backup current scene frame */
6262 int scene_frame = scene->r.cfra;
6263 float scene_subframe = scene->r.subframe;
6264
6265 for (int i = 0; i < numobjects; i++) {
6266 Object *brushObj = objects[i];
6267
6268 /* check if target has an active dp modifier */
6270 if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
6272 /* make sure we're dealing with a brush */
6273 if (pmd2->brush && pmd2->type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
6274 DynamicPaintBrushSettings *brush = pmd2->brush;
6275
6276 /* calculate brush speed vectors if required */
6277 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
6278 bData->brush_velocity = static_cast<float *>(MEM_callocN(
6279 sizeof(float[4]) * sData->total_points, "Dynamic Paint brush velocity"));
6280 /* init adjacency data if not already */
6281 if (!sData->adj_data) {
6282 dynamicPaint_initAdjacencyData(surface, true);
6283 }
6284 if (!bData->bNeighs) {
6285 dynamicPaint_prepareAdjacencyData(surface, true);
6286 }
6287 }
6288
6289 /* update object data on this subframe */
6290 if (subframe) {
6291 scene_setSubframe(scene, subframe);
6293 scene,
6294 brushObj,
6295 true,
6297 BKE_scene_ctime_get(scene),
6299 }
6300
6301 /* Apply brush on the surface depending on its collision type */
6302 if (brush->psys && brush->psys->part &&
6303 ELEM(brush->psys->part->type,
6305 PART_FLUID,
6315 psys_check_enabled(brushObj, brush->psys, for_render))
6316 {
6317 /* Paint a particle system */
6318 dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
6319 }
6320 /* Object center distance: */
6321 if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
6323 depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
6324 }
6325 /* Mesh volume/proximity: */
6326 else if (brushObj != ob) {
6327 dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
6328 }
6329
6330 /* reset object to its original state */
6331 if (subframe) {
6332 scene->r.cfra = scene_frame;
6333 scene->r.subframe = scene_subframe;
6335 scene,
6336 brushObj,
6337 true,
6339 BKE_scene_ctime_get(scene),
6341 }
6342
6343 /* process special brush effects, like smudge */
6344 if (bData->brush_velocity) {
6345 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE)
6346 {
6347 dynamicPaint_doSmudge(surface, brush, timescale);
6348 }
6349 MEM_freeN(bData->brush_velocity);
6350 bData->brush_velocity = nullptr;
6351 }
6352 }
6353 }
6354 }
6355
6357 }
6358
6359 /* surfaces operations that use adjacency data */
6360 if (sData->adj_data && bData->bNeighs) {
6361 /* wave type surface simulation step */
6362 if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
6363 dynamicPaint_doWaveStep(surface, timescale);
6364 }
6365
6366 /* paint surface effects */
6367 if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
6368 int steps = 1, s;
6369 PaintPoint *prevPoint;
6370 float *force = nullptr;
6371
6372 /* Allocate memory for surface previous points to read unchanged values from */
6373 prevPoint = static_cast<PaintPoint *>(
6374 MEM_mallocN(sData->total_points * sizeof(PaintPoint), "PaintSurfaceDataCopy"));
6375 if (!prevPoint) {
6376 return setError(canvas, N_("Not enough free memory"));
6377 }
6378
6379 /* Prepare effects and get number of required steps */
6380 steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
6381 for (s = 0; s < steps; s++) {
6382 dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, float(steps));
6383 }
6384
6385 /* Free temporary effect data */
6386 if (prevPoint) {
6387 MEM_freeN(prevPoint);
6388 }
6389 if (force) {
6390 MEM_freeN(force);
6391 }
6392 }
6393
6394 /* paint island border pixels */
6395 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
6397 }
6398 }
6399
6400 return ret;
6401}
6402
6404 DynamicPaintSurface *surface, Depsgraph *depsgraph, Scene *scene, Object *cObject, int frame)
6405{
6406 float timescale = 1.0f;
6407
6408 /* Apply previous displace on evaluated-mesh if incremental surface. */
6409 if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
6411 }
6412
6413 /* update bake data */
6414 dynamicPaint_generateBakeData(surface, depsgraph, cObject);
6415
6416 /* don't do substeps for first frame */
6417 if (surface->substeps && (frame != surface->start_frame)) {
6418 int st;
6419 timescale = 1.0f / (surface->substeps + 1);
6420
6421 for (st = 1; st <= surface->substeps; st++) {
6422 float subframe = float(st) / (surface->substeps + 1);
6423 if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe)) {
6424 return 0;
6425 }
6426 }
6427 }
6428
6429 return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
6430}
void free_bvhtree_from_mesh(BVHTreeFromMesh *data)
Definition bvhutils.cc:1160
BVHTree * BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data, const Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition bvhutils.cc:899
@ BVHTREE_FROM_CORNER_TRIS
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, float m_dist, const float v0[3], const float v1[3], const float v2[3])
Definition bvhutils.cc:173
void BKE_collision_objects_free(struct Object **objects)
struct Object ** BKE_collision_objects_create(struct Depsgraph *depsgraph, struct Object *self, struct Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
Definition colorband.cc:396
ColorBand * BKE_colorband_add(bool rangetype)
Definition colorband.cc:298
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
void CustomData_validate_layer_name(const CustomData *data, eCustomDataType type, blender::StringRef name, char *outname)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
int BKE_object_defgroup_name_index(const Object *ob, blender::StringRef name)
Definition deform.cc:585
#define DPAINT_PAINT_NEW
#define DPAINT_PAINT_DRY
#define DPAINT_WAVE_ISECT_CHANGED
#define DPAINT_WAVE_REFLECT_ONLY
#define DPAINT_PAINT_WET
#define DPAINT_WAVE_NONE
#define DPAINT_WAVE_OBSTACLE
struct EffectorWeights * BKE_effector_add_weights(struct Collection *collection)
Definition effect.cc:57
void BKE_effectors_free(struct ListBase *lb)
Definition effect.cc:364
void BKE_effectors_apply(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *wind_force, float *impulse)
Definition effect.cc:1110
struct ListBase * BKE_effectors_create(struct Depsgraph *depsgraph, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool use_rotation)
Definition effect.cc:309
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point)
Definition effect.cc:417
void BKE_image_pool_free(ImagePool *pool)
int BKE_image_path_ext_from_imtype_ensure(char *filepath, size_t filepath_maxncpy, char imtype)
void BKE_id_free(Main *bmain, void *idv)
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:837
General operations, lookup, etc. for materials.
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
void BKE_mesh_vert_corner_tri_map_create(MeshElemMap **r_map, int **r_mem, int totvert, const blender::int3 *corner_tris, int tris_num, const int *corner_verts, int corners_num)
void BKE_modifier_path_init(char *path, int path_maxncpy, const char *name)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
General operations, lookup, etc. for blender objects.
bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, Scene *scene, Object *ob, bool update_mesh, int parent_recursion, float frame, int type)
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
Definition particle.cc:706
void BKE_ptcache_id_time(PTCacheID *pid, struct Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
void BKE_ptcache_validate(struct PointCache *cache, int framenr)
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface)
struct PointCache * BKE_ptcache_add(struct ListBase *ptcaches)
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
void BKE_ptcache_free_list(struct ListBase *ptcaches)
#define PTCACHE_RESET_OUTDATED
int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *pid, int mode)
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2317
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
#define BVH_RAYCAST_DIST_MAX
Definition BLI_kdopbvh.h:92
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
A KD-tree for nearest neighbor search.
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_PI_2
MINLINE float square_f(float a)
MINLINE float min_fff(float a, float b, float c)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:289
void mul_m4_v3(const float M[4][4], float r[3])
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void interp_v4_v4v4v4(float p[4], const float v1[4], const float v2[4], const float v3[4], const float w[3])
MINLINE void negate_v3(float r[3])
MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_cmp
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define STRNCPY_UTF8(dst, src)
size_t void BLI_uniquename_cb(UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
#define CLAMP(a, b, c)
#define CLAMP_MAX(a, c)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
#define BLT_I18NCONTEXT_ID_BRUSH
#define CTX_DATA_(context, msgid)
typedef double(DMatrix)[4][4]
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLOG_STR_ERROR(clg_ref, str)
Definition CLG_log.h:188
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
@ DAG_EVAL_RENDER
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
Object groups, one object can be in many groups at once.
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_PROP_BYTE_COLOR
@ CD_MDEFORMVERT
@ CD_PROP_FLOAT2
@ MOD_DPAINT_EFFECT_DO_DRIP
@ MOD_DPAINT_EFFECT_DO_SPREAD
@ MOD_DPAINT_EFFECT_DO_SHRINK
@ MOD_DPAINT_ACTIVE
@ MOD_DPAINT_USE_DRYING
@ MOD_DPAINT_ANTIALIAS
@ MOD_DPAINT_WAVE_OPEN_BORDERS
@ MOD_DPAINT_DISP_INCREMENTAL
@ MOD_DPAINT_OUT1
@ MOD_DPAINT_DISSOLVE
@ MOD_DPAINT_MULALPHA
@ MOD_DPAINT_DISSOLVE_LOG
@ MOD_DPAINT_DRY_LOG
@ MOD_DPAINT_PROX_PROJECT
@ MOD_DPAINT_ABS_ALPHA
@ MOD_DPAINT_RAMP_ALPHA
@ MOD_DPAINT_INVERSE_PROX
@ MOD_DPAINT_USES_VELOCITY
@ MOD_DPAINT_VELOCITY_ALPHA
@ MOD_DPAINT_VELOCITY_DEPTH
@ MOD_DPAINT_VELOCITY_COLOR
@ MOD_DPAINT_DO_SMUDGE
@ MOD_DPAINT_PART_RAD
@ MOD_DPAINT_NEGATE_VOLUME
@ MOD_DPAINT_DISP_DISPLACE
@ MOD_DPAINT_SURFACE_T_WEIGHT
@ MOD_DPAINT_SURFACE_T_PAINT
@ MOD_DPAINT_SURFACE_T_DISPLACE
@ MOD_DPAINT_SURFACE_T_WAVE
@ MOD_DPAINT_BAKING
@ MOD_DPAINT_WAVEB_REFLECT
@ MOD_DPAINT_WAVEB_DEPTH
@ MOD_DPAINT_WAVEB_CHANGE
@ MOD_DPAINT_WAVEB_FORCE
@ MOD_DPAINT_RAY_BRUSH_AVG
@ MOD_DPAINT_RAY_CANVAS
@ MOD_DPAINT_COL_DIST
@ MOD_DPAINT_COL_VOLDIST
@ MOD_DPAINT_COL_POINT
@ MOD_DPAINT_COL_VOLUME
@ MOD_DPAINT_PRFALL_CONSTANT
@ MOD_DPAINT_PRFALL_SMOOTH
@ MOD_DPAINT_PRFALL_RAMP
@ MOD_DPAINT_INITIAL_NONE
@ MOD_DPAINT_INITIAL_VERTEXCOLOR
@ MOD_DPAINT_INITIAL_COLOR
@ MOD_DPAINT_INITIAL_TEXTURE
@ MOD_DPAINT_IMGFORMAT_OPENEXR
@ MOD_DPAINT_IMGFORMAT_PNG
@ MOD_DPAINT_SURFACE_F_PTEX
@ MOD_DPAINT_SURFACE_F_VERTEX
@ MOD_DPAINT_SURFACE_F_IMAGESEQ
@ eModifierFlag_SharedCaches
@ eModifierMode_Render
@ eModifierMode_Realtime
@ MOD_DYNAMICPAINT_TYPE_BRUSH
@ MOD_DYNAMICPAINT_TYPE_CANVAS
@ eModifierType_DynamicPaint
Object is a sort of wrapper for general info.
@ PART_FLUID_FLIP
@ PART_EMITTER
@ PART_FLUID_BUBBLE
@ PART_FLUID_SPRAYBUBBLE
@ PART_FLUID_TRACER
@ PART_FLUID
@ PART_FLUID_FOAM
@ PART_FLUID_SPRAYFOAMBUBBLE
@ PART_FLUID_SPRAYFOAM
@ PART_FLUID_SPRAY
@ PART_FLUID_FOAMBUBBLE
@ PARS_DEAD
@ PARS_UNBORN
@ PARS_UNEXIST
@ PART_UNBORN
@ PART_DIED
@ PTCACHE_BAKED
@ PTCACHE_DISK_CACHE
@ PTCACHE_REDO_NEEDED
@ PHYS_GLOBAL_GRAVITY
@ R_IMF_IMTYPE_OPENEXR
@ R_IMF_IMTYPE_PNG
@ IMB_FTYPE_OPENEXR
@ IMB_FTYPE_PNG
Contains defines and structs used throughout the imbuf module.
@ IB_rectfloat
#define OPENEXR_COMPRESS
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b)
ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b)
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
#define output
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
local_group_size(16, 16) .push_constant(Type b
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
#define powf(x, y)
#define ceilf(x)
#define floorf(x)
#define acosf(x)
#define fabsf(x)
#define sqrtf(x)
static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface)
static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, Object *brushOb, Scene *scene, float timescale)
static void dynamic_paint_apply_surface_vpaint_cb(void *__restrict userdata, const int p_index, const TaskParallelTLS *__restrict)
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void dynamic_paint_wave_step_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void freeGrid(PaintSurfaceData *data)
static void dynamicPaint_mixPaintColors(const DynamicPaintSurface *surface, const int index, const int paintFlags, const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
DynamicPaintSurface * dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene)
static Mesh * dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, float timescale)
static float dist_squared_to_corner_tris_uv_edges(const blender::Span< int3 > corner_tris, const float(*mloopuv)[2], int tri_index, const float point[2])
static void free_bakeData(PaintSurfaceData *data)
static void grid_cell_points_reduce(const void *__restrict userdata, void *__restrict chunk_join, void *__restrict chunk)
static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
static void scene_setSubframe(Scene *scene, float subframe)
static const float gaussianTotal
static void dynamic_paint_border_cb(void *__restrict userdata, const int b_index, const TaskParallelTLS *__restrict)
static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
#define NOT_FOUND
static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
static int neighX[8]
static void dynamic_paint_effect_drip_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintSurface *surface)
static void grid_bound_insert_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
static const float gaussianFactors[5]
static void dynamic_paint_output_surface_image_wave_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void dynamic_paint_output_surface_image_displace_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
bool dynamicPaint_createType(DynamicPaintModifierData *pmd, int type, Scene *scene)
static bool boundIntersectPoint(Bounds3D *b, const float point[3], const float radius)
static int dynamicPaint_prepareEffectStep(Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata, int tri_index, const float pixel[2], int in_edge, int depth)
static void dynamic_paint_brush_velocity_compute_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
static void surface_freeUnusedData(DynamicPaintSurface *surface)
static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata, const int id, const TaskParallelTLS *__restrict)
#define HIT_VOLUME
static int dynamic_paint_find_neighbor_pixel(const DynamicPaintCreateUVSurfaceData *data, const MeshElemMap *vert_to_tri_map, const int w, const int h, const int px, const int py, const int n_index)
static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
static void dynamic_paint_paint_particle_cell_point_cb_ex(void *__restrict userdata, const int id, const TaskParallelTLS *__restrict)
static int neighStraightX[8]
static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
#define EFF_MOVEMENT_PER_FRAME
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
static Mesh * dynamicPaint_canvas_mesh_get(DynamicPaintCanvasSettings *canvas)
static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
#define WAVE_TIME_FAC
static void dynamic_paint_output_surface_image_paint_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, const char *filepath, short output_layer)
#define CANVAS_REL_SIZE
static void dynamic_paint_effect_spread_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
static void dynamic_paint_output_surface_image_wetmap_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static bool setError(DynamicPaintCanvasSettings *canvas, const char *string)
static DynamicPaintRuntime * dynamicPaint_Modifier_runtime_ensure(DynamicPaintModifierData *pmd)
static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
#define MAX_WETNESS
#define HIT_PROXIMITY
#define JITTER_SAMPLES
static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void dynamic_paint_prepare_effect_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void surface_determineForceTargetPoints(const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Depsgraph *depsgraph, Scene *scene, Object *cObject, int frame)
static float getSurfaceDimension(PaintSurfaceData *sData)
static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
static int surface_totalSamples(DynamicPaintSurface *surface)
#define ADJ_ON_MESH_EDGE
static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob)
#define SUBFRAME_RECURSION
void dynamicPaintSurface_updateType(DynamicPaintSurface *surface)
static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
#define MIN_WETNESS
static void dynamicPaint_brushObjectCalculateVelocity(Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
void dynamicPaint_Modifier_copy(const DynamicPaintModifierData *pmd, DynamicPaintModifierData *tpmd, int flag)
static int neighY[8]
static void dynamic_paint_effect_shrink_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
DynamicPaintSurface * get_activeSurface(DynamicPaintCanvasSettings *canvas)
static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
static Mesh * dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
static void grid_cell_points_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, bool *do_update)
static void grid_bound_insert_reduce(const void *__restrict, void *__restrict chunk_join, void *__restrict chunk)
static void boundInsert(Bounds3D *b, const float point[3])
#define ADJ_BORDER_PIXEL
static void dynamic_paint_prepare_adjacency_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
static bool surface_duplicateOutputExists(void *arg, const char *name)
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph)
void dynamicPaint_freeBrush(DynamicPaintModifierData *pmd)
#define BRUSH_USES_VELOCITY
static bool dynamicPaint_paintParticles(DynamicPaintSurface *surface, ParticleSystem *psys, DynamicPaintBrushSettings *brush, float timescale)
static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata, const int ty, const TaskParallelTLS *__restrict)
static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
static void blendColors(const float t_color[3], const float t_alpha, const float s_color[3], const float s_alpha, float result[4])
static void surfaceGenerateGrid(DynamicPaintSurface *surface)
static int dynamicPaint_doStep(Depsgraph *depsgraph, Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
static bool dynamicPaint_paintSinglePoint(Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush, Object *brushOb, Scene *scene, float timescale)
static int neighStraightY[8]
Mesh * dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
#define ON_MESH_EDGE
bool dynamicPaint_outputLayerExists(DynamicPaintSurface *surface, Object *ob, int output)
static bool surface_duplicateNameExists(void *arg, const char *name)
static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
static float mixColors(float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
void dynamicPaint_Modifier_free_runtime(DynamicPaintRuntime *runtime_data)
static bool surface_usesAdjData(DynamicPaintSurface *surface)
#define OUT_OF_TEXTURE
static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdata, const int ty, const TaskParallelTLS *__restrict)
static void dynamicPaint_setInitialColor(const Scene *, DynamicPaintSurface *surface)
static void dynamicPaint_updatePointData(const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush, float paint[3], float influence, float depth, float vel_factor, const float timescale)
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
static void dynamic_paint_apply_surface_vpaint_blend_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
static void grid_cell_bounds_cb(void *__restrict userdata, const int x, const TaskParallelTLS *__restrict)
static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
KDTree_3d * tree
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
smooth(Type::VEC3, "P") .flat(Type out_color storage_buf(0, Qualifier::READ, "Surfel", "surfels_buf[]") .push_constant(Type smooth(Type::VEC4, "interp_color")
#define str(s)
uint col
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
bool IMB_saveiff(struct ImBuf *, const char *, int)
void IMB_freeImBuf(ImBuf *)
#define mix(a, b, c)
Definition hash.h:36
format
#define LOG(severity)
Definition log.h:33
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define unit_float_to_uchar_clamp(val)
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float3 ceil(const float3 a)
static ulong * next
static char faces[256]
static void error(const char *str)
void index(const bNode &, void *r_value)
VecBase< int32_t, 3 > int3
float distance(float a, float b)
Frequency::GEOMETRY nor[]
return ret
static const int steps
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
unsigned int uint32_t
Definition stdint.h:80
unsigned char uint8_t
Definition stdint.h:78
float no[3]
Definition BLI_kdopbvh.h:71
float min[2]
float max[2]
float min[3]
float max[3]
CBData data[32]
struct DynamicPaintModifierData * pmd
struct DynamicPaintModifierData * pmd
blender::Span< int3 > corner_tris
blender::Span< int > corner_verts
const DynamicPaintSurface * surface
const DynamicPaintSurface * surface
const DynamicPaintSurface * surface
const MeshElemMap * vert_to_tri_map
blender::Span< blender::float3 > positions
const DynamicPaintSurface * surface
blender::Span< blender::float3 > vert_normals
blender::Span< int > corner_verts
blender::MutableSpan< blender::float3 > vert_positions
const DynamicPaintSurface * surface
blender::Span< blender::float3 > vert_normals
blender::OffsetIndices< int > faces
struct DynamicPaintCanvasSettings * canvas
struct DynamicPaintBrushSettings * brush
const DynamicPaintSurface * surface
blender::Span< blender::float3 > positions
blender::Span< int > corner_verts
const DynamicPaintBrushSettings * brush
const float * avg_brushNor
const ParticleSystem * psys
const DynamicPaintSurface * surface
const Vec3f * brushVelocity
blender::Span< int3 > corner_tris
const DynamicPaintSurface * surface
blender::Span< int > corner_verts
blender::Span< int3 > corner_tris
struct DynamicPaintCanvasSettings * canvas
struct PaintSurfaceData * data
struct Collection * brush_group
struct DynamicPaintSurface * next
struct EffectorWeights * effector_weights
struct PointCache * pointcache
float vel_to_sec
Definition BKE_effect.h:36
ImBufFloatBuffer float_buffer
ImbFormatOptions foptions
enum eImbFileType ftype
PaintUVPoint * uv_p
Vec3f * barycentricWeights
void * first
unsigned char a
unsigned char b
unsigned char r
unsigned char g
int corners_num
int edges_num
CustomData corner_data
int faces_num
int verts_num
float loc[3]
float scale[3]
struct PointCache * cache
BakeAdjPoint * bNeighs
Vec3f * prev_velocity
float prev_obmat[4][4]
float * brush_velocity
DynamicPaintVolumeGrid * grid
float(* prev_positions)[3]
Bounds3D mesh_bounds
PaintBakeNormal * bNormal
float e_color[4]
struct PaintBakeData * bData
struct PaintAdjData * adj_data
ParticleKey state
ParticleData * particles
ParticleSettings * part
struct PhysicsSettings physics_settings
struct RenderData r
TaskParallelReduceFunc func_reduce
Definition BLI_task.h:185
size_t userdata_chunk_size
Definition BLI_task.h:173
float tin
Definition RE_texture.h:87
float trgba[4]
Definition RE_texture.h:88
float v[3]
int multitex_ext_safe(Tex *tex, const float texvec[3], TexResult *texres, ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
float max
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138