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