Blender V4.3
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
9#include "MEM_guardedalloc.h"
10
11#include "DNA_brush_types.h"
12#include "DNA_meshdata_types.h"
13
14#include "BLI_color.hh"
16#include "BLI_hash.h"
18#include "BLI_math_vector.hh"
19#include "BLI_task.h"
20#include "BLI_vector.hh"
21
22#include "BKE_attribute.hh"
23#include "BKE_brush.hh"
24#include "BKE_colorband.hh"
25#include "BKE_colortools.hh"
26#include "BKE_mesh.hh"
27#include "BKE_paint.hh"
28#include "BKE_pbvh_api.hh"
29
31
32#include "mesh_brush_common.hh"
33#include "sculpt_automask.hh"
34#include "sculpt_color.hh"
35#include "sculpt_intern.hh"
36#include "sculpt_smooth.hh"
37
38#include "IMB_imbuf.hh"
39
40#include "bmesh.hh"
41
42#include <cmath>
43#include <cstdlib>
44
46
47template<typename Func> inline void to_static_color_type(const CPPType &type, const Func &func)
48{
49 if (type.is<ColorGeometry4f>()) {
50 func(MPropCol());
51 }
52 else if (type.is<ColorGeometry4b>()) {
53 func(MLoopCol());
54 }
55}
56
57template<typename T> float4 to_float(const T &src);
58
59template<> float4 to_float(const MLoopCol &src)
60{
61 float4 dst;
62 rgba_uchar_to_float(dst, reinterpret_cast<const uchar *>(&src));
64 return dst;
65}
66template<> float4 to_float(const MPropCol &src)
67{
68 return src.color;
69}
70
71template<typename T> void from_float(const float4 &src, T &dst);
72
73template<> void from_float(const float4 &src, MLoopCol &dst)
74{
75 float4 temp;
76 linearrgb_to_srgb_v3_v3(temp, src);
77 temp[3] = src[3];
78 rgba_float_to_uchar(reinterpret_cast<uchar *>(&dst), temp);
79}
80template<> void from_float(const float4 &src, MPropCol &dst)
81{
82 copy_v4_v4(dst.color, src);
83}
84
85template<typename T>
87 const Span<int> corner_verts,
88 const GroupedSpan<int> vert_to_face_map,
89 const GSpan color_attribute,
90 const bke::AttrDomain color_domain,
91 const int vert)
92{
93 const T *colors_typed = static_cast<const T *>(color_attribute.data());
94 if (color_domain == bke::AttrDomain::Corner) {
95 float4 r_color(0.0f);
96 for (const int face : vert_to_face_map[vert]) {
97 const int corner = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
98 r_color += to_float(colors_typed[corner]);
99 }
100 return r_color / float(vert_to_face_map[vert].size());
101 }
102 return to_float(colors_typed[vert]);
103}
104
105template<typename T>
106static void color_vert_set(const OffsetIndices<int> faces,
107 const Span<int> corner_verts,
108 const GroupedSpan<int> vert_to_face_map,
109 const GMutableSpan color_attribute,
110 const bke::AttrDomain color_domain,
111 const int vert,
112 const float4 &color)
113{
114 if (color_domain == bke::AttrDomain::Corner) {
115 for (const int i_face : vert_to_face_map[vert]) {
116 const IndexRange face = faces[i_face];
117 MutableSpan<T> colors{static_cast<T *>(color_attribute.data()) + face.start(), face.size()};
118 Span<int> face_verts = corner_verts.slice(face);
119
120 for (const int i : IndexRange(face.size())) {
121 if (face_verts[i] == vert) {
122 from_float(color, colors[i]);
123 }
124 }
125 }
126 }
127 else {
128 from_float(color, static_cast<T *>(color_attribute.data())[vert]);
129 }
130}
131
133 const Span<int> corner_verts,
134 const GroupedSpan<int> vert_to_face_map,
135 const GSpan color_attribute,
136 const bke::AttrDomain color_domain,
137 const int vert)
138{
139 float4 color;
140 to_static_color_type(color_attribute.type(), [&](auto dummy) {
141 using T = decltype(dummy);
142 color = color_vert_get<T>(
143 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, vert);
144 });
145 return color;
146}
147
149 const Span<int> corner_verts,
150 const GroupedSpan<int> vert_to_face_map,
151 const bke::AttrDomain color_domain,
152 const int vert,
153 const float4 &color,
154 const GMutableSpan color_attribute)
155{
156 to_static_color_type(color_attribute.type(), [&](auto dummy) {
157 using T = decltype(dummy);
158 color_vert_set<T>(
159 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, vert, color);
160 });
161}
162
164 GMutableSpan color_attribute,
165 MutableSpan<float4> r_colors)
166{
167 to_static_color_type(color_attribute.type(), [&](auto dummy) {
168 using T = decltype(dummy);
169 T *colors_typed = static_cast<T *>(color_attribute.data());
170 for (const int i : indices.index_range()) {
171 T temp = colors_typed[indices[i]];
172 from_float(r_colors[i], colors_typed[indices[i]]);
173 r_colors[i] = to_float(temp);
174 }
175 });
176}
177
178void gather_colors(const GSpan color_attribute,
179 const Span<int> indices,
180 MutableSpan<float4> r_colors)
181{
182 to_static_color_type(color_attribute.type(), [&](auto dummy) {
183 using T = decltype(dummy);
184 const T *colors_typed = static_cast<const T *>(color_attribute.data());
185 for (const int i : indices.index_range()) {
186 r_colors[i] = to_float(colors_typed[indices[i]]);
187 }
188 });
189}
190
192 const Span<int> corner_verts,
193 const GroupedSpan<int> vert_to_face_map,
194 const GSpan color_attribute,
195 const bke::AttrDomain color_domain,
196 const Span<int> verts,
197 const MutableSpan<float4> r_colors)
198{
199 if (color_domain == bke::AttrDomain::Point) {
200 gather_colors(color_attribute, verts, r_colors);
201 }
202 else {
203 to_static_color_type(color_attribute.type(), [&](auto dummy) {
204 using T = decltype(dummy);
205 for (const int i : verts.index_range()) {
206 r_colors[i] = color_vert_get<T>(
207 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, verts[i]);
208 }
209 });
210 }
211}
212
214{
215 const bke::AttributeAccessor attributes = mesh.attributes();
216 const StringRef name = mesh.active_color_attribute;
217 const bke::GAttributeReader colors = attributes.lookup(name);
218 if (!colors) {
219 return {};
220 }
221 const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(colors.varray.type());
222 if ((CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) == 0) {
223 return {};
224 }
225 if ((ATTR_DOMAIN_AS_MASK(colors.domain) & ATTR_DOMAIN_MASK_COLOR) == 0) {
226 return {};
227 }
228 return colors;
229}
230
232{
233 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
234 const StringRef name = mesh.active_color_attribute;
235 bke::GSpanAttributeWriter colors = attributes.lookup_for_write_span(name);
236 if (!colors) {
237 return {};
238 }
239 const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(colors.span.type());
240 if ((CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) == 0) {
241 colors.finish();
242 return {};
243 }
244 if ((ATTR_DOMAIN_AS_MASK(colors.domain) & ATTR_DOMAIN_MASK_COLOR) == 0) {
245 colors.finish();
246 return {};
247 }
248 return colors;
249}
250
260
261static void do_color_smooth_task(const Depsgraph &depsgraph,
262 const Object &object,
263 const Span<float3> vert_positions,
264 const Span<float3> vert_normals,
265 const OffsetIndices<int> faces,
266 const Span<int> corner_verts,
267 const GroupedSpan<int> vert_to_face_map,
268 const MeshAttributeData &attribute_data,
269 const Brush &brush,
270 const bke::pbvh::MeshNode &node,
272 bke::GSpanAttributeWriter &color_attribute)
273{
274 const SculptSession &ss = *object.sculpt;
275 const StrokeCache &cache = *ss.cache;
276
277 const Span<int> verts = node.verts();
278
279 tls.factors.resize(verts.size());
280 const MutableSpan<float> factors = tls.factors;
281 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
282 filter_region_clip_factors(ss, vert_positions, verts, factors);
283 if (brush.flag & BRUSH_FRONTFACE) {
284 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
285 }
286
287 tls.distances.resize(verts.size());
288 const MutableSpan<float> distances = tls.distances;
290 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
291 filter_distances_with_radius(cache.radius, distances, factors);
292 apply_hardness_to_distances(cache, distances);
293 calc_brush_strength_factors(cache, brush, distances, factors);
294
295 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
296
297 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
298 scale_factors(factors, cache.bstrength);
299
300 tls.colors.resize(verts.size());
301 MutableSpan<float4> colors = tls.colors;
302 for (const int i : verts.index_range()) {
303 colors[i] = color_vert_get(faces,
304 corner_verts,
305 vert_to_face_map,
306 color_attribute.span,
307 color_attribute.domain,
308 verts[i]);
309 }
310
311 tls.vert_neighbors.resize(verts.size());
313 faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, verts, tls.vert_neighbors);
314 const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
315
316 tls.new_colors.resize(verts.size());
317 MutableSpan<float4> new_colors = tls.new_colors;
318 smooth::neighbor_color_average(faces,
319 corner_verts,
320 vert_to_face_map,
321 color_attribute.span,
322 color_attribute.domain,
323 vert_neighbors,
324 new_colors);
325
326 for (const int i : colors.index_range()) {
327 blend_color_interpolate_float(new_colors[i], colors[i], new_colors[i], factors[i]);
328 }
329
330 for (const int i : verts.index_range()) {
331 color_vert_set(faces,
332 corner_verts,
333 vert_to_face_map,
334 color_attribute.domain,
335 verts[i],
336 new_colors[i],
337 color_attribute.span);
338 }
339}
340
341static void do_paint_brush_task(const Scene &scene,
342 const Depsgraph &depsgraph,
343 Object &object,
344 const Span<float3> vert_positions,
345 const Span<float3> vert_normals,
346 const OffsetIndices<int> faces,
347 const Span<int> corner_verts,
348 const GroupedSpan<int> vert_to_face_map,
349 const MeshAttributeData &attribute_data,
350 const Paint &paint,
351 const Brush &brush,
352 const float4x4 &mat,
353 const float4 wet_mix_sampled_color,
356 const MutableSpan<float4> mix_colors,
357 bke::GSpanAttributeWriter &color_attribute)
358{
359 const SculptSession &ss = *object.sculpt;
360 const StrokeCache &cache = *ss.cache;
361
362 const float bstrength = fabsf(ss.cache->bstrength);
363 const float alpha = BKE_brush_alpha_get(&scene, &brush);
364
365 const Span<int> verts = node.verts();
366
367 tls.factors.resize(verts.size());
368 const MutableSpan<float> factors = tls.factors;
369 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
370 filter_region_clip_factors(ss, vert_positions, verts, factors);
371 if (brush.flag & BRUSH_FRONTFACE) {
372 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
373 }
374
375 tls.distances.resize(verts.size());
376 const MutableSpan<float> distances = tls.distances;
377 if (brush.tip_roundness < 1.0f) {
378 calc_brush_cube_distances(brush, mat, vert_positions, verts, distances, factors);
379 scale_factors(distances, cache.radius);
380 }
381 else {
383 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
384 }
385 filter_distances_with_radius(cache.radius, distances, factors);
386 apply_hardness_to_distances(cache, distances);
387 calc_brush_strength_factors(cache, brush, distances, factors);
388
389 MutableSpan<float> auto_mask;
390 if (cache.automasking) {
391 tls.auto_mask.resize(verts.size());
392 auto_mask = tls.auto_mask;
393 auto_mask.fill(1.0f);
394 auto_mask::calc_vert_factors(depsgraph, object, *cache.automasking, node, verts, auto_mask);
395 scale_factors(factors, auto_mask);
396 }
397
398 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
399 scale_factors(factors, bstrength);
400
401 const float density = ss.cache->paint_brush.density;
402 if (density < 1.0f) {
403 for (const int i : verts.index_range()) {
404 const float hash_noise = float(
406 if (hash_noise > density) {
407 const float noise = density * hash_noise;
408 factors[i] *= noise;
409 }
410 }
411 }
412
413 const float3 brush_color_rgb = ss.cache->invert ?
414 BKE_brush_secondary_color_get(&scene, &paint, &brush) :
415 BKE_brush_color_get(&scene, &paint, &brush);
416 float4 brush_color(brush_color_rgb, 1.0f);
417 IMB_colormanagement_srgb_to_scene_linear_v3(brush_color, brush_color);
418
419 const Span<float4> orig_colors = orig_color_data_get_mesh(object, node);
420
421 MutableSpan<float4> color_buffer = gather_data_mesh(mix_colors.as_span(), verts, tls.mix_colors);
422
423 if (brush.flag & BRUSH_USE_GRADIENT) {
424 switch (brush.gradient_stroke_mode) {
426 BKE_colorband_evaluate(brush.gradient, ss.cache->pressure, brush_color);
427 break;
429 float coord = fmod(ss.cache->stroke_distance / brush.gradient_spacing, 1.0);
430 BKE_colorband_evaluate(brush.gradient, coord, brush_color);
431 break;
432 }
435 brush.gradient, ss.cache->stroke_distance / brush.gradient_spacing, brush_color);
436 break;
437 }
438 }
439 }
440
441 tls.new_colors.resize(verts.size());
442 MutableSpan<float4> new_colors = tls.new_colors;
443 for (const int i : verts.index_range()) {
444 new_colors[i] = color_vert_get(faces,
445 corner_verts,
446 vert_to_face_map,
447 color_attribute.span,
448 color_attribute.domain,
449 verts[i]);
450 }
451
452 for (const int i : verts.index_range()) {
453 /* Brush paint color, brush test falloff and flow. */
454 float4 paint_color = brush_color * factors[i] * ss.cache->paint_brush.flow;
455 float4 wet_mix_color = wet_mix_sampled_color * factors[i] * ss.cache->paint_brush.flow;
456
457 /* Interpolate with the wet_mix color for wet paint mixing. */
459 paint_color, paint_color, wet_mix_color, ss.cache->paint_brush.wet_mix);
460 blend_color_mix_float(color_buffer[i], color_buffer[i], paint_color);
461
462 /* Final mix over the original color using brush alpha. We apply auto-making again
463 * at this point to avoid washing out non-binary masking modes like cavity masking. */
464 float automasking = auto_mask.is_empty() ? 1.0f : auto_mask[i];
465 const float4 buffer_color = float4(color_buffer[i]) * alpha * automasking;
466
467 IMB_blend_color_float(new_colors[i], orig_colors[i], buffer_color, IMB_BlendMode(brush.blend));
468 new_colors[i] = math::clamp(new_colors[i], 0.0f, 1.0f);
469 }
470
471 scatter_data_mesh(color_buffer.as_span(), verts, mix_colors);
472
473 for (const int i : verts.index_range()) {
474 color_vert_set(faces,
475 corner_verts,
476 vert_to_face_map,
477 color_attribute.domain,
478 verts[i],
479 new_colors[i],
480 color_attribute.span);
481 }
482}
483
488
489static void do_sample_wet_paint_task(const Object &object,
490 const Span<float3> vert_positions,
491 const OffsetIndices<int> faces,
492 const Span<int> corner_verts,
493 const GroupedSpan<int> vert_to_face_map,
494 const Span<bool> hide_vert,
495 const GSpan color_attribute,
496 const bke::AttrDomain color_domain,
497 const Brush &brush,
498 const bke::pbvh::MeshNode &node,
500 SampleWetPaintData &swptd)
501{
502 const SculptSession &ss = *object.sculpt;
503 const float radius = ss.cache->radius * brush.wet_paint_radius_factor;
504
505 const Span<int> verts = node.verts();
506
507 tls.factors.resize(verts.size());
508 const MutableSpan<float> factors = tls.factors;
509 fill_factor_from_hide(hide_vert, verts, factors);
510
511 tls.distances.resize(verts.size());
512 const MutableSpan<float> distances = tls.distances;
514 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
515 filter_distances_with_radius(radius, distances, factors);
516
517 for (const int i : verts.index_range()) {
518 if (factors[i] > 0.0f) {
519 swptd.color += color_vert_get(
520 faces, corner_verts, vert_to_face_map, color_attribute, color_domain, verts[i]);
521 swptd.tot_samples++;
522 }
523 }
524}
525
526void do_paint_brush(const Scene &scene,
527 const Depsgraph &depsgraph,
528 PaintModeSettings &paint_mode_settings,
529 const Sculpt &sd,
530 Object &ob,
531 const IndexMask &node_mask,
532 const IndexMask &texnode_mask)
533{
534 if (SCULPT_use_image_paint_brush(paint_mode_settings, ob)) {
535 SCULPT_do_paint_brush_image(scene, depsgraph, paint_mode_settings, sd, ob, texnode_mask);
536 return;
537 }
538
539 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
540 SculptSession &ss = *ob.sculpt;
541 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
543
547 BLI_hash_int_01(ss.cache->location_symm[0] * 1000));
548 }
549 return;
550 }
551
553
554 float4x4 mat;
555
556 /* If the brush is round the tip does not need to be aligned to the surface, so this saves a
557 * whole iteration over the affected nodes. */
558 if (brush.tip_roundness < 1.0f) {
559 SCULPT_cube_tip_init(sd, ob, brush, mat.ptr());
560
561 if (is_zero_m4(mat.ptr())) {
562 return;
563 }
564 }
565
566 Mesh &mesh = *static_cast<Mesh *>(ob.data);
567 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
568 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
569 const OffsetIndices<int> faces = mesh.faces();
570 const Span<int> corner_verts = mesh.corner_verts();
571 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
572 const MeshAttributeData attribute_data(mesh.attributes());
574 if (!color_attribute) {
575 return;
576 }
577
578 if (ss.cache->alt_smooth) {
580 node_mask.foreach_index(GrainSize(1), [&](const int i) {
581 ColorPaintLocalData &tls = all_tls.local();
583 ob,
584 vert_positions,
585 vert_normals,
586 faces,
587 corner_verts,
588 vert_to_face_map,
589 attribute_data,
590 brush,
591 nodes[i],
592 tls,
593 color_attribute);
594 });
595 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
596 color_attribute.finish();
597 return;
598 }
599
600 /* Regular Paint mode. */
601
602 /* Wet paint color sampling. */
603 float4 wet_color(0);
604 if (ss.cache->paint_brush.wet_mix > 0.0f) {
606 const SampleWetPaintData swptd = threading::parallel_reduce(
607 node_mask.index_range(),
608 1,
610 [&](const IndexRange range, SampleWetPaintData swptd) {
611 ColorPaintLocalData &tls = all_tls.local();
612 node_mask.slice(range).foreach_index([&](const int i) {
613 do_sample_wet_paint_task(ob,
614 vert_positions,
615 faces,
616 corner_verts,
617 vert_to_face_map,
618 attribute_data.hide_vert,
619 color_attribute.span,
620 color_attribute.domain,
621 brush,
622 nodes[i],
623 tls,
624 swptd);
625 });
626 return swptd;
627 },
628 [](const SampleWetPaintData &a, const SampleWetPaintData &b) {
629 SampleWetPaintData joined{};
630 joined.color = a.color + b.color;
631 joined.tot_samples = a.tot_samples + b.tot_samples;
632 return joined;
633 });
634
635 if (swptd.tot_samples > 0 && is_finite_v4(swptd.color)) {
636 wet_color = math::clamp(swptd.color / float(swptd.tot_samples), 0.0f, 1.0f);
637
638 if (ss.cache->first_time) {
639 ss.cache->paint_brush.wet_mix_prev_color = wet_color;
640 }
642 wet_color,
645 ss.cache->paint_brush.wet_mix_prev_color = math::clamp(wet_color, 0.0f, 1.0f);
646 }
647 }
648
649 if (ss.cache->paint_brush.mix_colors.is_empty()) {
650 ss.cache->paint_brush.mix_colors = Array<float4>(mesh.verts_num, float4(0));
651 }
652
654 node_mask.foreach_index(GrainSize(1), [&](const int i) {
655 ColorPaintLocalData &tls = all_tls.local();
656 do_paint_brush_task(scene,
657 depsgraph,
658 ob,
659 vert_positions,
660 vert_normals,
661 faces,
662 corner_verts,
663 vert_to_face_map,
664 attribute_data,
665 sd.paint,
666 brush,
667 mat,
668 wet_color,
669 nodes[i],
670 tls,
671 ss.cache->paint_brush.mix_colors,
672 color_attribute);
673 });
674 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
675 color_attribute.finish();
676}
677
678static void do_smear_brush_task(const Depsgraph &depsgraph,
679 Object &object,
680 const Span<float3> vert_positions,
681 const Span<float3> vert_normals,
682 const OffsetIndices<int> faces,
683 const Span<int> corner_verts,
684 const GroupedSpan<int> vert_to_face_map,
685 const MeshAttributeData &attribute_data,
686 const Brush &brush,
689 bke::GSpanAttributeWriter &color_attribute)
690{
691 const SculptSession &ss = *object.sculpt;
692 const StrokeCache &cache = *ss.cache;
693 const float strength = ss.cache->bstrength;
694
695 const Span<int> verts = node.verts();
696
697 tls.factors.resize(verts.size());
698 const MutableSpan<float> factors = tls.factors;
699 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
700 filter_region_clip_factors(ss, vert_positions, verts, factors);
701 if (brush.flag & BRUSH_FRONTFACE) {
702 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
703 }
704
705 tls.distances.resize(verts.size());
706 const MutableSpan<float> distances = tls.distances;
708 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
709 filter_distances_with_radius(cache.radius, distances, factors);
710 apply_hardness_to_distances(cache, distances);
711 calc_brush_strength_factors(cache, brush, distances, factors);
712
713 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
714
715 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
716 scale_factors(factors, strength);
717
718 float3 brush_delta;
719 if (brush.flag & BRUSH_ANCHORED) {
720 brush_delta = ss.cache->grab_delta_symm;
721 }
722 else {
723 brush_delta = ss.cache->location_symm - ss.cache->last_location_symm;
724 }
725
726 Vector<int> neighbors;
727 Vector<int> neighbor_neighbors;
728
729 for (const int i : verts.index_range()) {
730 if (factors[i] == 0.0f) {
731 continue;
732 }
733 const int vert = verts[i];
734 const float3 &no = vert_normals[vert];
735
736 float3 current_disp;
737 switch (brush.smear_deform_type) {
739 current_disp = brush_delta;
740 break;
742 current_disp = ss.cache->location_symm - vert_positions[vert];
743 break;
745 current_disp = vert_positions[vert] - ss.cache->location_symm;
746 break;
747 }
748
749 /* Project into vertex plane. */
750 current_disp += no * -math::dot(current_disp, no);
751
752 const float3 current_disp_norm = math::normalize(current_disp);
753
754 current_disp = current_disp_norm * strength;
755
756 float4 accum(0);
757 float totw = 0.0f;
758
759 /*
760 * NOTE: we have to do a nested iteration here to avoid
761 * blocky artifacts on quad topologies. The runtime cost
762 * is not as bad as it seems due to neighbor iteration
763 * in the sculpt code being cache bound; once the data is in
764 * the cache iterating over it a few more times is not terribly
765 * costly.
766 */
767
768 for (const int neighbor : vert_neighbors_get_mesh(
769 faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, vert, neighbors))
770 {
771 const float3 &nco = vert_positions[neighbor];
772 for (const int neighbor_neighbor : vert_neighbors_get_mesh(faces,
773 corner_verts,
774 vert_to_face_map,
775 attribute_data.hide_poly,
776 neighbor,
777 neighbor_neighbors))
778 {
779 if (neighbor_neighbor == vert) {
780 continue;
781 }
782
783 float3 vert_disp = vert_positions[neighbor_neighbor] - vert_positions[vert];
784
785 /* Weight by how close we are to our target distance from vd.co. */
786 float w = (1.0f + fabsf(math::length(vert_disp) / strength - 1.0f));
787
788 /* TODO: use cotangents (or at least face areas) here. */
789 float len = math::distance(vert_positions[neighbor_neighbor], nco);
790 if (len > 0.0f) {
791 len = strength / len;
792 }
793 else { /* Coincident point. */
794 len = 1.0f;
795 }
796
797 /* Multiply weight with edge lengths (in the future this will be
798 * cotangent weights or face areas). */
799 w *= len;
800
801 /* Build directional weight. */
802
803 /* Project into vertex plane. */
804 vert_disp += no * -math::dot(no, vert_disp);
805 const float3 vert_disp_norm = math::normalize(vert_disp);
806
807 if (math::dot(current_disp_norm, vert_disp_norm) >= 0.0f) {
808 continue;
809 }
810
811 const float4 &neighbor_color = ss.cache->paint_brush.prev_colors[neighbor_neighbor];
812 float color_interp = -math::dot(current_disp_norm, vert_disp_norm);
813
814 /* Square directional weight to get a somewhat sharper result. */
815 w *= color_interp * color_interp;
816
817 accum += neighbor_color * w;
818 totw += w;
819 }
820 }
821
822 if (totw != 0.0f) {
823 accum /= totw;
824 }
825
827 faces, corner_verts, vert_to_face_map, color_attribute.span, color_attribute.domain, vert);
828 blend_color_interpolate_float(col, ss.cache->paint_brush.prev_colors[vert], accum, factors[i]);
829 color_vert_set(faces,
830 corner_verts,
831 vert_to_face_map,
832 color_attribute.domain,
833 vert,
834 col,
835 color_attribute.span);
836 }
837}
838
839void do_smear_brush(const Depsgraph &depsgraph,
840 const Sculpt &sd,
841 Object &ob,
842 const IndexMask &node_mask)
843{
844 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
845 SculptSession &ss = *ob.sculpt;
846 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
848
849 Mesh &mesh = *static_cast<Mesh *>(ob.data);
850 if (ss.cache->bstrength == 0.0f) {
851 return;
852 }
853
854 const OffsetIndices<int> faces = mesh.faces();
855 const Span<int> corner_verts = mesh.corner_verts();
856 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
857 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
858 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
859 const MeshAttributeData attribute_data(mesh.attributes());
860
862 if (!color_attribute) {
863 return;
864 }
865
866 if (ss.cache->paint_brush.prev_colors.is_empty()) {
867 ss.cache->paint_brush.prev_colors = Array<float4>(mesh.verts_num);
868 threading::parallel_for(IndexRange(mesh.verts_num), 1024, [&](const IndexRange range) {
869 for (const int vert : range) {
870 ss.cache->paint_brush.prev_colors[vert] = color_vert_get(faces,
871 corner_verts,
872 vert_to_face_map,
873 color_attribute.span,
874 color_attribute.domain,
875 vert);
876 }
877 });
878 }
879
880 BKE_curvemapping_init(brush.curve);
881
882 /* Smooth colors mode. */
883 if (ss.cache->alt_smooth) {
885 node_mask.foreach_index(GrainSize(1), [&](const int i) {
886 ColorPaintLocalData &tls = all_tls.local();
887 do_color_smooth_task(depsgraph,
888 ob,
889 vert_positions,
890 vert_normals,
891 faces,
892 corner_verts,
893 vert_to_face_map,
894 attribute_data,
895 brush,
896 nodes[i],
897 tls,
898 color_attribute);
899 });
900 }
901 else {
902 /* Smear mode. */
903 node_mask.foreach_index(GrainSize(1), [&](const int i) {
904 for (const int vert : nodes[i].verts()) {
905 ss.cache->paint_brush.prev_colors[vert] = color_vert_get(faces,
906 corner_verts,
907 vert_to_face_map,
908 color_attribute.span,
909 color_attribute.domain,
910 vert);
911 }
912 });
913 threading::EnumerableThreadSpecific<ColorPaintLocalData> all_tls;
914 node_mask.foreach_index(GrainSize(1), [&](const int i) {
915 ColorPaintLocalData &tls = all_tls.local();
917 ob,
918 vert_positions,
919 vert_normals,
920 faces,
921 corner_verts,
922 vert_to_face_map,
923 attribute_data,
924 brush,
925 nodes[i],
926 tls,
927 color_attribute);
928 });
929 }
930 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
931 color_attribute.finish();
932}
933
934} // namespace blender::ed::sculpt_paint::color
#define ATTR_DOMAIN_MASK_COLOR
#define ATTR_DOMAIN_AS_MASK(domain)
const float * BKE_brush_secondary_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1037
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1153
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1029
bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
Definition colorband.cc:396
void BKE_curvemapping_init(CurveMapping *cumap)
#define CD_TYPE_AS_MASK(_type)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
A BVH for high poly meshes.
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition BLI_hash.h:96
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void 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])
bool is_finite_v4(const float v[4]) ATTR_WARN_UNUSED_RESULT
unsigned char uchar
@ 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
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
IMB_BlendMode
Definition IMB_imbuf.hh:186
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition rectop.cc:115
Read Guarded memory(de)allocation.
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
const CPPType & type() const
const CPPType & type() const
const void * data() const
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr bool is_empty() const
Definition BLI_span.hh:510
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
void resize(const int64_t new_size)
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:593
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
#define fabsf(x)
int len
draw_view in_light_buf[] float
static float verts[][3]
uint col
ccl_device_inline float2 fmod(const float2 a, const float b)
int face_find_corner_from_vert(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:264
bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
static void do_paint_brush_task(const Scene &scene, 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)
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 do_paint_brush(const Scene &scene, const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, const Sculpt &sd, Object &ob, const IndexMask &node_mask, const IndexMask &texnode_mask)
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)
float4 to_float(const T &src)
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6490
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:6862
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6772
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6639
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6122
Span< float4 > orig_color_data_get_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
void calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, MutableSpan< Vector< int > > result)
Definition sculpt.cc:7330
void calc_brush_cube_distances(const Brush &brush, const float4x4 &mat, Span< float3 > positions, Span< int > verts, MutableSpan< float > r_distances, MutableSpan< float > factors)
Definition sculpt.cc:6783
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6581
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:431
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert_indices, MutableSpan< float > factors)
Definition sculpt.cc:6898
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6442
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)
static void to_static_color_type(const eCustomDataType type, const Func &func)
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:513
void SCULPT_cube_tip_init(const Sculpt &, const Object &ob, const Brush &brush, float mat[4][4])
Definition sculpt.cc:6024
bool SCULPT_stroke_is_first_brush_step(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:507
void SCULPT_do_paint_brush_image(const Scene &scene, 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
struct CurveMapping * curve
char falloff_shape
short blend
char gradient_stroke_mode
int gradient_spacing
int smear_deform_type
float tip_roundness
struct SculptSession * sculpt
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
const c_style_mat & ptr() const
struct blender::ed::sculpt_paint::StrokeCache::@480 paint_brush
std::unique_ptr< auto_mask::Cache > automasking