Blender V5.0
sculpt_paint_color.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DNA_brush_types.h"
10#include "DNA_meshdata_types.h"
11
12#include "BLI_color.hh"
14#include "BLI_hash.h"
16#include "BLI_math_matrix.hh"
17#include "BLI_math_vector.hh"
18#include "BLI_vector.hh"
19
20#include "BKE_attribute.hh"
21#include "BKE_brush.hh"
22#include "BKE_colorband.hh"
23#include "BKE_colortools.hh"
24#include "BKE_customdata.hh"
25#include "BKE_mesh.hh"
26#include "BKE_paint.hh"
27#include "BKE_paint_bvh.hh"
28
30
31#include "mesh_brush_common.hh"
32#include "sculpt_automask.hh"
33#include "sculpt_color.hh"
34#include "sculpt_intern.hh"
35#include "sculpt_smooth.hh"
36
37#include "IMB_imbuf.hh"
38
39#include <cmath>
40
42
43static void calc_local_positions(const float4x4 &mat,
44 const Span<int> verts,
45 const Span<float3> positions,
46 const MutableSpan<float3> local_positions)
47{
48 for (const int i : verts.index_range()) {
49 local_positions[i] = math::transform_point(mat, positions[verts[i]]);
50 }
51}
52
53template<typename Func> inline void to_static_color_type(const CPPType &type, const Func &func)
54{
55 if (type.is<ColorGeometry4f>()) {
56 func(MPropCol());
57 }
58 else if (type.is<ColorGeometry4b>()) {
59 func(MLoopCol());
60 }
61}
62
63template<typename T> float4 to_float(const T &src);
64
65template<> float4 to_float(const MLoopCol &src)
66{
67 float4 dst;
68 rgba_uchar_to_float(dst, reinterpret_cast<const uchar *>(&src));
70 return dst;
71}
72template<> float4 to_float(const MPropCol &src)
73{
74 return src.color;
75}
76
77template<typename T> void from_float(const float4 &src, T &dst);
78
79template<> void from_float(const float4 &src, MLoopCol &dst)
80{
81 float4 temp;
82 linearrgb_to_srgb_v3_v3(temp, src);
83 temp[3] = src[3];
84 rgba_float_to_uchar(reinterpret_cast<uchar *>(&dst), temp);
85}
86template<> void from_float(const float4 &src, MPropCol &dst)
87{
88 copy_v4_v4(dst.color, src);
89}
90
91template<typename T>
93 const Span<int> corner_verts,
94 const GroupedSpan<int> vert_to_face_map,
95 const GSpan color_attribute,
96 const bke::AttrDomain color_domain,
97 const int vert)
98{
99 const T *colors_typed = static_cast<const T *>(color_attribute.data());
100 if (color_domain == bke::AttrDomain::Corner) {
101 float4 r_color(0.0f);
102 for (const int face : vert_to_face_map[vert]) {
103 const int corner = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
104 r_color += to_float(colors_typed[corner]);
105 }
106 return r_color / float(vert_to_face_map[vert].size());
107 }
108 return to_float(colors_typed[vert]);
109}
110
111template<typename T>
113 const Span<int> corner_verts,
114 const GroupedSpan<int> vert_to_face_map,
115 const GMutableSpan color_attribute,
116 const bke::AttrDomain color_domain,
117 const int vert,
118 const float4 &color)
119{
120 if (color_domain == bke::AttrDomain::Corner) {
121 for (const int i_face : vert_to_face_map[vert]) {
122 const IndexRange face = faces[i_face];
123 MutableSpan<T> colors{static_cast<T *>(color_attribute.data()) + face.start(), face.size()};
124 Span<int> face_verts = corner_verts.slice(face);
125
126 for (const int i : IndexRange(face.size())) {
127 if (face_verts[i] == vert) {
128 from_float(color, colors[i]);
129 }
130 }
131 }
132 }
133 else {
134 from_float(color, static_cast<T *>(color_attribute.data())[vert]);
135 }
136}
137
139 const Span<int> corner_verts,
140 const GroupedSpan<int> vert_to_face_map,
141 const GSpan color_attribute,
142 const bke::AttrDomain color_domain,
143 const int vert)
144{
146 to_static_color_type(color_attribute.type(), [&](auto dummy) {
147 using T = decltype(dummy);
148 color = color_vert_get<T>(
149 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, vert);
150 });
151 return color;
152}
153
155 const Span<int> corner_verts,
156 const GroupedSpan<int> vert_to_face_map,
157 const bke::AttrDomain color_domain,
158 const int vert,
159 const float4 &color,
160 const GMutableSpan color_attribute)
161{
162 to_static_color_type(color_attribute.type(), [&](auto dummy) {
163 using T = decltype(dummy);
164 color_vert_set<T>(
165 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, vert, color);
166 });
167}
168
170 GMutableSpan color_attribute,
171 MutableSpan<float4> r_colors)
172{
173 to_static_color_type(color_attribute.type(), [&](auto dummy) {
174 using T = decltype(dummy);
175 T *colors_typed = static_cast<T *>(color_attribute.data());
176 for (const int i : indices.index_range()) {
177 T temp = colors_typed[indices[i]];
178 from_float(r_colors[i], colors_typed[indices[i]]);
179 r_colors[i] = to_float(temp);
180 }
181 });
182}
183
184void gather_colors(const GSpan color_attribute,
185 const Span<int> indices,
186 MutableSpan<float4> r_colors)
187{
188 to_static_color_type(color_attribute.type(), [&](auto dummy) {
189 using T = decltype(dummy);
190 const T *colors_typed = static_cast<const T *>(color_attribute.data());
191 for (const int i : indices.index_range()) {
192 r_colors[i] = to_float(colors_typed[indices[i]]);
193 }
194 });
195}
196
198 const Span<int> corner_verts,
199 const GroupedSpan<int> vert_to_face_map,
200 const GSpan color_attribute,
201 const bke::AttrDomain color_domain,
202 const Span<int> verts,
203 const MutableSpan<float4> r_colors)
204{
205 if (color_domain == bke::AttrDomain::Point) {
206 gather_colors(color_attribute, verts, r_colors);
207 }
208 else {
209 to_static_color_type(color_attribute.type(), [&](auto dummy) {
210 using T = decltype(dummy);
211 for (const int i : verts.index_range()) {
212 r_colors[i] = color_vert_get<T>(
213 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, verts[i]);
214 }
215 });
216 }
217}
218
220{
221 const bke::AttributeAccessor attributes = mesh.attributes();
222 const StringRef name = mesh.active_color_attribute;
223 const bke::GAttributeReader colors = attributes.lookup(name);
224 if (!colors) {
225 return {};
226 }
228 if ((CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) == 0) {
229 return {};
230 }
232 return {};
233 }
234 return colors;
235}
236
238{
239 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
240 const StringRef name = mesh.active_color_attribute;
242 if (!colors) {
243 return {};
244 }
246 if ((CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) == 0) {
247 colors.finish();
248 return {};
249 }
251 colors.finish();
252 return {};
253 }
254 return colors;
255}
256
268
269static void do_color_smooth_task(const Depsgraph &depsgraph,
270 const Object &object,
271 const Span<float3> vert_positions,
272 const Span<float3> vert_normals,
274 const Span<int> corner_verts,
275 const GroupedSpan<int> vert_to_face_map,
276 const MeshAttributeData &attribute_data,
277 const Brush &brush,
278 const bke::pbvh::MeshNode &node,
280 bke::GSpanAttributeWriter &color_attribute)
281{
282 const SculptSession &ss = *object.sculpt;
283 const StrokeCache &cache = *ss.cache;
284
285 const Span<int> verts = node.verts();
286
287 tls.factors.resize(verts.size());
288 const MutableSpan<float> factors = tls.factors;
289 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
290 filter_region_clip_factors(ss, vert_positions, verts, factors);
291 if (brush.flag & BRUSH_FRONTFACE) {
292 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
293 }
294
295 tls.distances.resize(verts.size());
296 const MutableSpan<float> distances = tls.distances;
298 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
299 filter_distances_with_radius(cache.radius, distances, factors);
300 apply_hardness_to_distances(cache, distances);
301 calc_brush_strength_factors(cache, brush, distances, factors);
302
303 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
304
305 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
306 scale_factors(factors, cache.bstrength);
307
308 tls.colors.resize(verts.size());
309 MutableSpan<float4> colors = tls.colors;
310 for (const int i : verts.index_range()) {
311 colors[i] = color_vert_get(faces,
312 corner_verts,
313 vert_to_face_map,
314 color_attribute.span,
315 color_attribute.domain,
316 verts[i]);
317 }
318
320 corner_verts,
321 vert_to_face_map,
322 attribute_data.hide_poly,
323 verts,
325 tls.neighbor_data);
326
327 tls.new_colors.resize(verts.size());
328 MutableSpan<float4> new_colors = tls.new_colors;
330 corner_verts,
331 vert_to_face_map,
332 color_attribute.span,
333 color_attribute.domain,
334 neighbors,
335 new_colors);
336
337 for (const int i : colors.index_range()) {
338 blend_color_interpolate_float(new_colors[i], colors[i], new_colors[i], factors[i]);
339 }
340
341 for (const int i : verts.index_range()) {
343 corner_verts,
344 vert_to_face_map,
345 color_attribute.domain,
346 verts[i],
347 new_colors[i],
348 color_attribute.span);
349 }
350}
351
352static void do_paint_brush_task(const Depsgraph &depsgraph,
353 Object &object,
354 const Span<float3> vert_positions,
355 const Span<float3> vert_normals,
357 const Span<int> corner_verts,
358 const GroupedSpan<int> vert_to_face_map,
359 const MeshAttributeData &attribute_data,
360 const Paint &paint,
361 const Brush &brush,
362 const float4x4 &mat,
363 const float4 wet_mix_sampled_color,
366 const MutableSpan<float4> mix_colors,
367 bke::GSpanAttributeWriter &color_attribute)
368{
369 const SculptSession &ss = *object.sculpt;
370 const StrokeCache &cache = *ss.cache;
371
372 const float bstrength = fabsf(ss.cache->bstrength);
373 const float alpha = BKE_brush_alpha_get(&paint, &brush);
374
375 const Span<int> verts = node.verts();
376
377 tls.factors.resize(verts.size());
378 const MutableSpan<float> factors = tls.factors;
379 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
380 filter_region_clip_factors(ss, vert_positions, verts, factors);
381 if (brush.flag & BRUSH_FRONTFACE) {
382 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
383 }
384
385 float radius;
386
387 tls.distances.resize(verts.size());
388 const MutableSpan<float> distances = tls.distances;
389 if (brush.tip_roundness < 1.0f) {
390 tls.positions.resize(verts.size());
391 calc_local_positions(mat, verts, vert_positions, tls.positions);
392 calc_brush_cube_distances<float3>(brush, tls.positions, distances);
393 radius = 1.0f;
394 }
395 else {
397 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
398 radius = cache.radius;
399 }
400 filter_distances_with_radius(radius, distances, factors);
401 apply_hardness_to_distances(radius, cache.hardness, distances);
404 distances,
405 radius,
406 factors);
407
409 if (cache.automasking) {
410 tls.auto_mask.resize(verts.size());
411 auto_mask = tls.auto_mask;
412 auto_mask.fill(1.0f);
414 scale_factors(factors, auto_mask);
415 }
416
417 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
418 scale_factors(factors, bstrength);
419
420 const float density = ss.cache->paint_brush.density;
421 if (density < 1.0f) {
423 const float seed = ss.cache->paint_brush.density_seed.value_or(0.0f);
424 for (const int i : verts.index_range()) {
425 const float hash_noise = BLI_hash_int_01(seed * 1000 * verts[i]);
426 if (hash_noise > density) {
427 const float noise = density * hash_noise;
428 factors[i] *= noise;
429 }
430 }
431 }
432
433 float3 brush_color_rgb = ss.cache->invert ? BKE_brush_secondary_color_get(&paint, &brush) :
434 BKE_brush_color_get(&paint, &brush);
435
436 const std::optional<BrushColorJitterSettings> color_jitter_settings =
438 if (color_jitter_settings) {
439 brush_color_rgb = BKE_paint_randomize_color(*color_jitter_settings,
442 ss.cache->pressure,
443 brush_color_rgb);
444 }
445
446 float4 brush_color(brush_color_rgb, 1.0f);
447
448 const Span<float4> orig_colors = orig_color_data_get_mesh(object, node);
449
450 MutableSpan<float4> color_buffer = gather_data_mesh(mix_colors.as_span(), verts, tls.mix_colors);
451
452 if (brush.flag & BRUSH_USE_GRADIENT) {
453 switch (brush.gradient_stroke_mode) {
455 BKE_colorband_evaluate(brush.gradient, ss.cache->pressure, brush_color);
456 break;
458 float coord = fmod(ss.cache->stroke_distance / brush.gradient_spacing, 1.0);
459 BKE_colorband_evaluate(brush.gradient, coord, brush_color);
460 break;
461 }
464 brush.gradient, ss.cache->stroke_distance / brush.gradient_spacing, brush_color);
465 break;
466 }
467 }
468 }
469
470 tls.new_colors.resize(verts.size());
471 MutableSpan<float4> new_colors = tls.new_colors;
472 for (const int i : verts.index_range()) {
473 new_colors[i] = color_vert_get(faces,
474 corner_verts,
475 vert_to_face_map,
476 color_attribute.span,
477 color_attribute.domain,
478 verts[i]);
479 }
480
481 for (const int i : verts.index_range()) {
482 /* Brush paint color, brush test falloff and flow. */
483 float4 paint_color = brush_color * factors[i] * ss.cache->paint_brush.flow;
484 float4 wet_mix_color = wet_mix_sampled_color * factors[i] * ss.cache->paint_brush.flow;
485
486 /* Interpolate with the wet_mix color for wet paint mixing. */
488 paint_color, paint_color, wet_mix_color, ss.cache->paint_brush.wet_mix);
489 blend_color_mix_float(color_buffer[i], color_buffer[i], paint_color);
490
491 /* Final mix over the original color using brush alpha. We apply auto-making again
492 * at this point to avoid washing out non-binary masking modes like cavity masking. */
493 float automasking = auto_mask.is_empty() ? 1.0f : auto_mask[i];
494 const float4 buffer_color = float4(color_buffer[i]) * alpha * automasking;
495
496 IMB_blend_color_float(new_colors[i], orig_colors[i], buffer_color, IMB_BlendMode(brush.blend));
497 new_colors[i] = math::clamp(new_colors[i], 0.0f, 1.0f);
498 }
499
500 scatter_data_mesh(color_buffer.as_span(), verts, mix_colors);
501
502 for (const int i : verts.index_range()) {
504 corner_verts,
505 vert_to_face_map,
506 color_attribute.domain,
507 verts[i],
508 new_colors[i],
509 color_attribute.span);
510 }
511}
512
517
518static void do_sample_wet_paint_task(const Object &object,
519 const Span<float3> vert_positions,
521 const Span<int> corner_verts,
522 const GroupedSpan<int> vert_to_face_map,
523 const Span<bool> hide_vert,
524 const GSpan color_attribute,
525 const bke::AttrDomain color_domain,
526 const Brush &brush,
527 const bke::pbvh::MeshNode &node,
529 SampleWetPaintData &swptd)
530{
531 const SculptSession &ss = *object.sculpt;
532 const float radius = ss.cache->radius * brush.wet_paint_radius_factor;
533
534 const Span<int> verts = node.verts();
535
536 tls.factors.resize(verts.size());
537 const MutableSpan<float> factors = tls.factors;
538 fill_factor_from_hide(hide_vert, verts, factors);
539
540 tls.distances.resize(verts.size());
541 const MutableSpan<float> distances = tls.distances;
543 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
544 filter_distances_with_radius(radius, distances, factors);
545
546 for (const int i : verts.index_range()) {
547 if (factors[i] > 0.0f) {
548 swptd.color += color_vert_get(
549 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, verts[i]);
550 swptd.tot_samples++;
551 }
552 }
553}
554
555void do_paint_brush(const Depsgraph &depsgraph,
556 PaintModeSettings &paint_mode_settings,
557 const Sculpt &sd,
558 Object &ob,
559 const IndexMask &node_mask,
560 const IndexMask &texnode_mask)
561{
562 if (SCULPT_use_image_paint_brush(paint_mode_settings, ob)) {
563 SCULPT_do_paint_brush_image(depsgraph, paint_mode_settings, sd, ob, texnode_mask);
564 return;
565 }
566
567 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
568 SculptSession &ss = *ob.sculpt;
571
572 if (!ss.cache->paint_brush.density_seed) {
574 }
575
577 return;
578 }
579
581
582 float4x4 mat;
583
584 /* If the brush is round the tip does not need to be aligned to the surface, so this saves a
585 * whole iteration over the affected nodes. */
586 if (brush.tip_roundness < 1.0f) {
587 SCULPT_cube_tip_init(sd, ob, brush, mat.ptr());
588
589 if (is_zero_m4(mat.ptr())) {
590 return;
591 }
592 }
593
594 Mesh &mesh = *static_cast<Mesh *>(ob.data);
595 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
596 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
597 const OffsetIndices<int> faces = mesh.faces();
598 const Span<int> corner_verts = mesh.corner_verts();
599 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
600 const MeshAttributeData attribute_data(mesh);
602 if (!color_attribute) {
603 return;
604 }
605
606 if (ss.cache->alt_smooth) {
608 node_mask.foreach_index(GrainSize(1), [&](const int i) {
609 ColorPaintLocalData &tls = all_tls.local();
611 ob,
612 vert_positions,
613 vert_normals,
614 faces,
615 corner_verts,
616 vert_to_face_map,
617 attribute_data,
618 brush,
619 nodes[i],
620 tls,
621 color_attribute);
622 });
623 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
624 color_attribute.finish();
625 return;
626 }
627
628 /* Regular Paint mode. */
629
630 /* Wet paint color sampling. */
631 float4 wet_color(0);
632 if (ss.cache->paint_brush.wet_mix > 0.0f) {
635 node_mask.index_range(),
636 1,
638 [&](const IndexRange range, SampleWetPaintData swptd) {
639 ColorPaintLocalData &tls = all_tls.local();
640 node_mask.slice(range).foreach_index([&](const int i) {
641 do_sample_wet_paint_task(ob,
642 vert_positions,
643 faces,
644 corner_verts,
645 vert_to_face_map,
646 attribute_data.hide_vert,
647 color_attribute.span,
648 color_attribute.domain,
649 brush,
650 nodes[i],
651 tls,
652 swptd);
653 });
654 return swptd;
655 },
656 [](const SampleWetPaintData &a, const SampleWetPaintData &b) {
657 SampleWetPaintData joined{};
658 joined.color = a.color + b.color;
659 joined.tot_samples = a.tot_samples + b.tot_samples;
660 return joined;
661 });
662
663 if (swptd.tot_samples > 0 && is_finite_v4(swptd.color)) {
664 wet_color = math::clamp(swptd.color / float(swptd.tot_samples), 0.0f, 1.0f);
665
666 if (ss.cache->first_time) {
667 ss.cache->paint_brush.wet_mix_prev_color = wet_color;
668 }
670 wet_color,
673 ss.cache->paint_brush.wet_mix_prev_color = math::clamp(wet_color, 0.0f, 1.0f);
674 }
675 }
676
677 if (ss.cache->paint_brush.mix_colors.is_empty()) {
678 ss.cache->paint_brush.mix_colors = Array<float4>(mesh.verts_num, float4(0));
679 }
680
682 node_mask.foreach_index(GrainSize(1), [&](const int i) {
683 ColorPaintLocalData &tls = all_tls.local();
684 do_paint_brush_task(depsgraph,
685 ob,
686 vert_positions,
687 vert_normals,
688 faces,
689 corner_verts,
690 vert_to_face_map,
691 attribute_data,
692 sd.paint,
693 brush,
694 mat,
695 wet_color,
696 nodes[i],
697 tls,
698 ss.cache->paint_brush.mix_colors,
699 color_attribute);
700 });
701 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
702 color_attribute.finish();
703}
704
705static void do_smear_brush_task(const Depsgraph &depsgraph,
706 Object &object,
707 const Span<float3> vert_positions,
708 const Span<float3> vert_normals,
710 const Span<int> corner_verts,
711 const GroupedSpan<int> vert_to_face_map,
712 const MeshAttributeData &attribute_data,
713 const Brush &brush,
716 bke::GSpanAttributeWriter &color_attribute)
717{
718 const SculptSession &ss = *object.sculpt;
719 const StrokeCache &cache = *ss.cache;
720 const float strength = ss.cache->bstrength;
721
722 const Span<int> verts = node.verts();
723
724 tls.factors.resize(verts.size());
725 const MutableSpan<float> factors = tls.factors;
726 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
727 filter_region_clip_factors(ss, vert_positions, verts, factors);
728 if (brush.flag & BRUSH_FRONTFACE) {
729 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
730 }
731
732 tls.distances.resize(verts.size());
733 const MutableSpan<float> distances = tls.distances;
735 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
736 filter_distances_with_radius(cache.radius, distances, factors);
737 apply_hardness_to_distances(cache, distances);
738 calc_brush_strength_factors(cache, brush, distances, factors);
739
740 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
741
742 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
743 scale_factors(factors, strength);
744
745 float3 brush_delta;
746 if (brush.flag & BRUSH_ANCHORED) {
747 brush_delta = ss.cache->grab_delta_symm;
748 }
749 else {
750 brush_delta = ss.cache->location_symm - ss.cache->last_location_symm;
751 }
752
753 Vector<int> neighbors;
754 Vector<int> neighbor_neighbors;
755
756 for (const int i : verts.index_range()) {
757 if (factors[i] == 0.0f) {
758 continue;
759 }
760 const int vert = verts[i];
761 const float3 &no = vert_normals[vert];
762
763 float3 current_disp;
764 switch (brush.smear_deform_type) {
766 current_disp = brush_delta;
767 break;
769 current_disp = ss.cache->location_symm - vert_positions[vert];
770 break;
772 current_disp = vert_positions[vert] - ss.cache->location_symm;
773 break;
774 }
775
776 /* Project into vertex plane. */
777 current_disp += no * -math::dot(current_disp, no);
778
779 const float3 current_disp_norm = math::normalize(current_disp);
780
781 current_disp = current_disp_norm * strength;
782
783 float4 accum(0);
784 float totw = 0.0f;
785
786 /*
787 * NOTE: we have to do a nested iteration here to avoid
788 * blocky artifacts on quad topologies. The runtime cost
789 * is not as bad as it seems due to neighbor iteration
790 * in the sculpt code being cache bound; once the data is in
791 * the cache iterating over it a few more times is not terribly
792 * costly.
793 */
794
795 for (const int neighbor : vert_neighbors_get_mesh(
796 faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, vert, neighbors))
797 {
798 const float3 &nco = vert_positions[neighbor];
799 for (const int neighbor_neighbor : vert_neighbors_get_mesh(faces,
800 corner_verts,
801 vert_to_face_map,
802 attribute_data.hide_poly,
803 neighbor,
804 neighbor_neighbors))
805 {
806 if (neighbor_neighbor == vert) {
807 continue;
808 }
809
810 float3 vert_disp = vert_positions[neighbor_neighbor] - vert_positions[vert];
811
812 /* Weight by how close we are to our target distance from vd.co. */
813 float w = (1.0f + fabsf(math::length(vert_disp) / strength - 1.0f));
814
815 /* TODO: use cotangents (or at least face areas) here. */
816 float len = math::distance(vert_positions[neighbor_neighbor], nco);
817 if (len > 0.0f) {
818 len = strength / len;
819 }
820 else { /* Coincident point. */
821 len = 1.0f;
822 }
823
824 /* Multiply weight with edge lengths (in the future this will be
825 * cotangent weights or face areas). */
826 w *= len;
827
828 /* Build directional weight. */
829
830 /* Project into vertex plane. */
831 vert_disp += no * -math::dot(no, vert_disp);
832 const float3 vert_disp_norm = math::normalize(vert_disp);
833
834 if (math::dot(current_disp_norm, vert_disp_norm) >= 0.0f) {
835 continue;
836 }
837
838 const float4 &neighbor_color = ss.cache->paint_brush.prev_colors[neighbor_neighbor];
839 float color_interp = -math::dot(current_disp_norm, vert_disp_norm);
840
841 /* Square directional weight to get a somewhat sharper result. */
842 w *= color_interp * color_interp;
843
844 accum += neighbor_color * w;
845 totw += w;
846 }
847 }
848
849 if (totw != 0.0f) {
850 accum /= totw;
851 }
852
854 faces, corner_verts, vert_to_face_map, color_attribute.span, color_attribute.domain, vert);
855 blend_color_interpolate_float(col, ss.cache->paint_brush.prev_colors[vert], accum, factors[i]);
857 corner_verts,
858 vert_to_face_map,
859 color_attribute.domain,
860 vert,
861 col,
862 color_attribute.span);
863 }
864}
865
866void do_smear_brush(const Depsgraph &depsgraph,
867 const Sculpt &sd,
868 Object &ob,
869 const IndexMask &node_mask)
870{
871 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
872 SculptSession &ss = *ob.sculpt;
875
876 Mesh &mesh = *static_cast<Mesh *>(ob.data);
877 if (ss.cache->bstrength == 0.0f) {
878 return;
879 }
880
881 const OffsetIndices<int> faces = mesh.faces();
882 const Span<int> corner_verts = mesh.corner_verts();
883 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
884 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
885 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
886 const MeshAttributeData attribute_data(mesh);
887
889 if (!color_attribute) {
890 return;
891 }
892
893 if (ss.cache->paint_brush.prev_colors.is_empty()) {
895 threading::parallel_for(IndexRange(mesh.verts_num), 1024, [&](const IndexRange range) {
896 for (const int vert : range) {
897 ss.cache->paint_brush.prev_colors[vert] = color_vert_get(faces,
898 corner_verts,
899 vert_to_face_map,
900 color_attribute.span,
901 color_attribute.domain,
902 vert);
903 }
904 });
905 }
906
907 BKE_curvemapping_init(brush.curve_distance_falloff);
908
909 /* Smooth colors mode. */
910 if (ss.cache->alt_smooth) {
912 node_mask.foreach_index(GrainSize(1), [&](const int i) {
913 ColorPaintLocalData &tls = all_tls.local();
914 do_color_smooth_task(depsgraph,
915 ob,
916 vert_positions,
917 vert_normals,
918 faces,
919 corner_verts,
920 vert_to_face_map,
921 attribute_data,
922 brush,
923 nodes[i],
924 tls,
925 color_attribute);
926 });
927 }
928 else {
929 /* Smear mode. */
930 node_mask.foreach_index(GrainSize(1), [&](const int i) {
931 for (const int vert : nodes[i].verts()) {
932 ss.cache->paint_brush.prev_colors[vert] = color_vert_get(faces,
933 corner_verts,
934 vert_to_face_map,
935 color_attribute.span,
936 color_attribute.domain,
937 vert);
938 }
939 });
940 threading::EnumerableThreadSpecific<ColorPaintLocalData> all_tls;
941 node_mask.foreach_index(GrainSize(1), [&](const int i) {
942 ColorPaintLocalData &tls = all_tls.local();
944 ob,
945 vert_positions,
946 vert_normals,
947 faces,
948 corner_verts,
949 vert_to_face_map,
950 attribute_data,
951 brush,
952 nodes[i],
953 tls,
954 color_attribute);
955 });
956 }
957 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
958 color_attribute.finish();
959}
960
961} // namespace blender::ed::sculpt_paint::color
#define ATTR_DOMAIN_MASK_COLOR
#define ATTR_DOMAIN_AS_MASK(domain)
float BKE_brush_alpha_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1357
const float * BKE_brush_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1161
const float * BKE_brush_secondary_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1205
std::optional< BrushColorJitterSettings > BKE_brush_color_jitter_get_settings(const Paint *paint, const Brush *brush)
Definition brush.cc:1170
void BKE_brush_calc_curve_factors(eBrushCurvePreset preset, const CurveMapping *cumap, blender::Span< float > distances, float brush_radius, blender::MutableSpan< float > factors)
Definition brush.cc:1448
bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
Definition colorband.cc:396
void BKE_curvemapping_init(CurveMapping *cumap)
CustomData interface, see also DNA_customdata_types.h.
eCustomDataMask CD_TYPE_AS_MASK(eCustomDataType type)
blender::float3 BKE_paint_randomize_color(const BrushColorJitterSettings &color_jitter, const blender::float3 &initial_hsv_jitter, const float distance, const float pressure, const blender::float3 &color)
Definition paint.cc:1964
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
A BVH for high poly meshes.
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition BLI_hash.h:92
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
MINLINE void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
bool is_zero_m4(const float mat[4][4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE bool is_finite_v4(const float v[4]) ATTR_WARN_UNUSED_RESULT
unsigned char uchar
eBrushCurvePreset
@ BRUSH_SMEAR_DEFORM_PINCH
@ BRUSH_SMEAR_DEFORM_EXPAND
@ BRUSH_SMEAR_DEFORM_DRAG
@ BRUSH_FRONTFACE
@ BRUSH_ANCHORED
@ BRUSH_USE_GRADIENT
@ BRUSH_GRADIENT_SPACING_CLAMP
@ BRUSH_GRADIENT_PRESSURE
@ BRUSH_GRADIENT_SPACING_REPEAT
eBrushFalloffShape
#define CD_MASK_COLOR_ALL
struct MLoopCol MLoopCol
struct MPropCol MPropCol
IMB_BlendMode
Definition IMB_imbuf.hh:178
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition rectop.cc:116
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static unsigned long seed
Definition btSoftBody.h:39
void resize(const int64_t new_size)
bool is() const
const CPPType & type() const
const CPPType & type() const
const void * data() const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:676
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
nullptr float
static ushort indices[]
static float verts[][3]
uint col
VecBase< float, 4 > float4
ccl_device_inline float2 fmod(const float2 a, const float b)
#define T
static char faces[256]
int face_find_corner_from_vert(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:327
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
static void do_paint_brush_task(const Depsgraph &depsgraph, Object &object, const Span< float3 > vert_positions, const Span< float3 > vert_normals, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const MeshAttributeData &attribute_data, const Paint &paint, const Brush &brush, const float4x4 &mat, const float4 wet_mix_sampled_color, bke::pbvh::MeshNode &node, ColorPaintLocalData &tls, const MutableSpan< float4 > mix_colors, bke::GSpanAttributeWriter &color_attribute)
bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
void gather_colors_vert(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, Span< int > verts, MutableSpan< float4 > r_colors)
void do_smear_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
float4 color_vert_get(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, int vert)
static void do_sample_wet_paint_task(const Object &object, const Span< float3 > vert_positions, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const Span< bool > hide_vert, const GSpan color_attribute, const bke::AttrDomain color_domain, const Brush &brush, const bke::pbvh::MeshNode &node, ColorPaintLocalData &tls, SampleWetPaintData &swptd)
void gather_colors(GSpan color_attribute, Span< int > indices, MutableSpan< float4 > r_colors)
void color_vert_set(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, bke::AttrDomain color_domain, int vert, const float4 &color, GMutableSpan color_attribute)
void swap_gathered_colors(Span< int > indices, GMutableSpan color_attribute, MutableSpan< float4 > r_colors)
void from_float(const float4 &src, T &dst)
static void do_smear_brush_task(const Depsgraph &depsgraph, Object &object, const Span< float3 > vert_positions, const Span< float3 > vert_normals, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const MeshAttributeData &attribute_data, const Brush &brush, bke::pbvh::MeshNode &node, ColorPaintLocalData &tls, bke::GSpanAttributeWriter &color_attribute)
bke::GAttributeReader active_color_attribute(const Mesh &mesh)
void to_static_color_type(const CPPType &type, const Func &func)
static void do_color_smooth_task(const Depsgraph &depsgraph, const Object &object, const Span< float3 > vert_positions, const Span< float3 > vert_normals, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const MeshAttributeData &attribute_data, const Brush &brush, const bke::pbvh::MeshNode &node, ColorPaintLocalData &tls, bke::GSpanAttributeWriter &color_attribute)
static void calc_local_positions(const float4x4 &mat, const Span< int > verts, const Span< float3 > positions, const MutableSpan< float3 > local_positions)
void do_paint_brush(const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, const Sculpt &sd, Object &ob, const IndexMask &node_mask, const IndexMask &texnode_mask)
float4 to_float(const T &src)
void neighbor_color_average(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const GSpan color_attribute, const bke::AttrDomain color_domain, const GroupedSpan< int > vert_neighbors, const MutableSpan< float4 > smooth_colors)
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6823
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7183
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7597
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6972
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6435
Span< float4 > orig_color_data_get_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7055
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7195
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6914
void calc_brush_cube_distances(const Brush &brush, const Span< T > positions, const MutableSpan< float > r_distances)
Definition sculpt.cc:7117
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:429
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6775
T clamp(const T &a, const T &min, const T &max)
T distance(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
static void to_static_color_type(const bke::AttrType type, const Func &func)
const char * name
#define fabsf
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:542
void SCULPT_cube_tip_init(const Sculpt &, const Object &ob, const Brush &brush, float mat[4][4])
Definition sculpt.cc:6328
void SCULPT_do_paint_brush_image(const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, const Sculpt &sd, Object &ob, const blender::IndexMask &node_mask)
bool SCULPT_use_image_paint_brush(PaintModeSettings &settings, Object &ob)
struct ColorBand * gradient
float wet_paint_radius_factor
char falloff_shape
struct CurveMapping * curve_distance_falloff
short blend
char gradient_stroke_mode
int gradient_spacing
int curve_distance_falloff_preset
int smear_deform_type
float tip_roundness
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
const c_style_mat & ptr() const
struct blender::ed::sculpt_paint::StrokeCache::@216032235377206062040134367360200004271263147147 paint_brush
std::unique_ptr< auto_mask::Cache > automasking
std::optional< blender::float3 > initial_hsv_jitter
i
Definition text_draw.cc:230
uint len