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
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);
346 return (CustomData_get_named_layer_index(&mesh->corner_data, CD_PROP_BYTE_COLOR, name) !=
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
628static void freeGrid(PaintSurfaceData *data)
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);
764 settings.func_reduce = grid_bound_insert_reduce;
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;
830 settings.func_reduce = grid_cell_points_reduce;
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 */
986 free_bakeData(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
1000 MEM_SAFE_FREE(surface->effector_weights);
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;
1046 surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
1047 surface->type = MOD_DPAINT_SURFACE_T_PAINT;
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;
1066 surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
1067 surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
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 *>(
1251 MEM_dupallocN(surface->effector_weights));
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]>(
1647 CustomData_get_layer_named(&mesh->corner_data, CD_PROP_FLOAT2, uvname));
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
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);
1682 0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb, &settings);
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);
1848 0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb, &settings);
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{
1919 Mesh *result = BKE_mesh_copy_for_eval(*mesh);
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 *>(
1967 CustomData_get_layer_named_for_write(&result->corner_data,
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 *>(
1982 CustomData_get_layer_named_for_write(&result->corner_data,
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) {
2059 dynamicPaint_applySurfaceDisplace(surface, result);
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/* -------------------------------------------------------------------- */
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 */
2858 if (CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2)) {
2860 &mesh->corner_data, CD_PROP_FLOAT2, surface->uvlayer_name, uvname);
2861 mloopuv = static_cast<const float(*)[2]>(
2862 CustomData_get_layer_named(&mesh->corner_data, CD_PROP_FLOAT2, uvname));
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 */
3322 int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR :
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
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{
3773 const DynamicPaintBrushVelocityData *data = static_cast<const DynamicPaintBrushVelocityData *>(
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;
4035 hit.dist = BVH_RAYCAST_DIST_MAX;
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;
4067 hit.dist = BVH_RAYCAST_DIST_MAX;
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 */
4372 DynamicPaintPaintData data{};
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 */
4680 DynamicPaintPaintData data{};
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 */
4823 DynamicPaintPaintData data{};
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);
4838 0, sData->total_points, &data, dynamic_paint_paint_single_point_cb_ex, &settings);
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 */
5135 if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
5136 /* also divide by 10 to about match default gravity
5137 * with default force strength (1.0). */
5138 madd_v3_v3fl(forc,
5139 scene->physics_settings.gravity,
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 */
5816{
5817 return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
5818 (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
5820 (surface->flags & MOD_DPAINT_DISSOLVE)));
5821}
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{
5968 const DynamicPaintGenerateBakeData *data = static_cast<const DynamicPaintGenerateBakeData *>(
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
struct PaintPoint PaintPoint
struct PaintWavePoint PaintWavePoint
#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)
ImagePool * BKE_image_pool_new(void)
int BKE_image_path_ext_from_imtype_ensure(char *filepath, size_t filepath_maxncpy, char imtype)
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
void BKE_id_free(Main *bmain, void *idv)
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_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_DISP_DISPLACE
@ MOD_DPAINT_RAY_BRUSH_AVG
@ MOD_DPAINT_RAY_CANVAS
@ 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_PRFALL_CONSTANT
@ MOD_DPAINT_PRFALL_SMOOTH
@ MOD_DPAINT_PRFALL_RAMP
@ 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_SURFACE_T_WEIGHT
@ MOD_DPAINT_SURFACE_T_PAINT
@ MOD_DPAINT_SURFACE_T_DISPLACE
@ MOD_DPAINT_SURFACE_T_WAVE
@ MOD_DPAINT_BAKING
@ MOD_DPAINT_EFFECT_DO_DRIP
@ MOD_DPAINT_EFFECT_DO_SPREAD
@ MOD_DPAINT_EFFECT_DO_SHRINK
@ MOD_DPAINT_COL_DIST
@ MOD_DPAINT_COL_VOLDIST
@ MOD_DPAINT_COL_POINT
@ MOD_DPAINT_COL_VOLUME
@ MOD_DPAINT_SURFACE_F_PTEX
@ MOD_DPAINT_SURFACE_F_VERTEX
@ MOD_DPAINT_SURFACE_F_IMAGESEQ
@ MOD_DPAINT_WAVEB_REFLECT
@ MOD_DPAINT_WAVEB_DEPTH
@ MOD_DPAINT_WAVEB_CHANGE
@ MOD_DPAINT_WAVEB_FORCE
@ 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_UNBORN
@ PART_DIED
@ 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_UNEXIST
@ PARS_DEAD
@ PARS_UNBORN
@ 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)
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
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)
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
const Depsgraph * depsgraph
#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])
static CLG_LogRef LOG
#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
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)
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 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 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
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)
#define N_(msgid)
uint8_t flag
Definition wm_window.cc:138