Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt_automasking.cc
| Show All 9 Lines | |||||
| #include "BLI_array.hh" | #include "BLI_array.hh" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_hash.h" | #include "BLI_hash.h" | ||||
| #include "BLI_index_range.hh" | #include "BLI_index_range.hh" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_math_vector_types.hh" | #include "BLI_math_vector_types.hh" | ||||
| #include "BLI_set.hh" | #include "BLI_set.hh" | ||||
| #include "BLI_task.h" | #include "BLI_task.h" | ||||
| #include "BLI_task.hh" | |||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | ||||
| #include "DNA_brush_types.h" | #include "DNA_brush_types.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "BKE_brush.h" | #include "BKE_brush.h" | ||||
| #include "BKE_colortools.h" | #include "BKE_colortools.h" | ||||
| ▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | return sculpt_automasking_normal_calc(ss, | ||||
| automasking->settings.view_normal_limit + falloff, | automasking->settings.view_normal_limit + falloff, | ||||
| automask_data); | automask_data); | ||||
| } | } | ||||
| static float automasking_view_occlusion_factor(AutomaskingCache *automasking, | static float automasking_view_occlusion_factor(AutomaskingCache *automasking, | ||||
| SculptSession *ss, | SculptSession *ss, | ||||
| PBVHVertRef vertex, | PBVHVertRef vertex, | ||||
| uchar stroke_id, | uchar stroke_id, | ||||
| AutomaskingNodeData * /*automask_data*/) | AutomaskingNodeData *automask_data) | ||||
| { | { | ||||
| char f = *(char *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_occlusion); | char f = *(char *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_occlusion); | ||||
| if (stroke_id != automasking->current_stroke_id) { | if (stroke_id != automasking->current_stroke_id) { | ||||
| f = *(char *)SCULPT_vertex_attr_get( | f = *(char *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_occlusion) = | ||||
| vertex, | SCULPT_vertex_is_occluded(ss, vertex, automask_data->have_orig_data) ? 2 : 1; | ||||
| ss->attrs.automasking_occlusion) = SCULPT_vertex_is_occluded(ss, vertex, true) ? 2 : 1; | |||||
| } | } | ||||
| return f == 2; | return f == 2; | ||||
| } | } | ||||
| /* Updates vertex stroke id. */ | /* Updates vertex stroke id. */ | ||||
| static float automasking_factor_end(SculptSession *ss, | static float automasking_factor_end(SculptSession *ss, | ||||
| AutomaskingCache *automasking, | AutomaskingCache *automasking, | ||||
| ▲ Show 20 Lines • Show All 230 Lines • ▼ Show 20 Lines | if ((automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) && | ||||
| factor = inverted ? 1.0f - factor : factor; | factor = inverted ? 1.0f - factor : factor; | ||||
| factor = BKE_curvemapping_evaluateF(automasking->settings.cavity_curve, 0, factor); | factor = BKE_curvemapping_evaluateF(automasking->settings.cavity_curve, 0, factor); | ||||
| factor = inverted ? 1.0f - factor : factor; | factor = inverted ? 1.0f - factor : factor; | ||||
| } | } | ||||
| return factor; | return factor; | ||||
| } | } | ||||
| float SCULPT_automasking_factor_get(AutomaskingCache *automasking, | static float sculpt_automasking_factor_calc(AutomaskingCache *automasking, | ||||
| SculptSession *ss, | SculptSession *ss, | ||||
| PBVHVertRef vert, | PBVHVertRef vert, | ||||
| AutomaskingNodeData *automask_data) | AutomaskingNodeData *automask_data) | ||||
| { | { | ||||
| if (!automasking || vert.i == PBVH_REF_NONE) { | if (!automasking || vert.i == PBVH_REF_NONE) { | ||||
| return 1.0f; | return 1.0f; | ||||
| } | } | ||||
| float mask = 1.0f; | float mask = 1.0f; | ||||
| /* Since brush normal mode depends on the current mirror symmetry pass | /* Since brush normal mode depends on the current mirror symmetry pass | ||||
| * it is not folded into the factor cache (when it exists). */ | * it is not folded into the factor cache (when it exists). */ | ||||
| if ((ss->cache || ss->filter_cache) && | if ((ss->cache || ss->filter_cache) && | ||||
| (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) { | (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) { | ||||
| mask *= automasking_brush_normal_factor(automasking, ss, vert, automask_data); | mask *= automasking_brush_normal_factor(automasking, ss, vert, automask_data); | ||||
| } | } | ||||
| /* If the cache is initialized with valid info, use the cache. This is used when the | /* If the cache is initialized with valid info, use the cache. This is used when the | ||||
| * automasking information can't be computed in real time per vertex and needs to be | * automasking information can't be computed in real time per vertex and needs to be | ||||
| * initialized for the whole mesh when the stroke starts. */ | * initialized for the whole mesh when the stroke starts. */ | ||||
| if (ss->attrs.automasking_factor) { | if (ss->attrs.automasking_factor && !(automask_data && automask_data->initializing)) { | ||||
| float factor = *(float *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_factor); | float factor = *(float *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_factor); | ||||
| if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { | if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { | ||||
| factor *= sculpt_automasking_cavity_factor(automasking, ss, vert); | factor *= sculpt_automasking_cavity_factor(automasking, ss, vert); | ||||
| } | } | ||||
| return automasking_factor_end(ss, automasking, vert, factor * mask); | return automasking_factor_end(ss, automasking, vert, factor * mask); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | static float sculpt_automasking_factor_calc(AutomaskingCache *automasking, | ||||
| if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { | if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { | ||||
| mask *= sculpt_automasking_cavity_factor(automasking, ss, vert); | mask *= sculpt_automasking_cavity_factor(automasking, ss, vert); | ||||
| } | } | ||||
| return automasking_factor_end(ss, automasking, vert, mask); | return automasking_factor_end(ss, automasking, vert, mask); | ||||
| } | } | ||||
| float SCULPT_automasking_factor_get(AutomaskingCache *automasking, | |||||
| SculptSession *ss, | |||||
| PBVHVertRef vert, | |||||
| AutomaskingNodeData *automask_data) | |||||
| { | |||||
| if (!automasking || vert.i == PBVH_REF_NONE) { | |||||
| return 1.0f; | |||||
| } | |||||
| /* If the cache is initialized with valid info, use the cache. This is used when the | |||||
| * automasking information can't be computed in real time per vertex and needs to be | |||||
| * initialized for the whole mesh when the stroke starts. */ | |||||
| if (automasking->has_full_factor_cache) { | |||||
| float factor = *(float *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_factor); | |||||
| if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { | |||||
| factor *= sculpt_automasking_cavity_factor(automasking, ss, vert); | |||||
| } | |||||
| return factor; | |||||
| } | |||||
| uchar stroke_id = ss->attrs.automasking_stroke_id ? | |||||
| *(uchar *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_stroke_id) : | |||||
| -1; | |||||
| bool do_occlusion = (automasking->settings.flags & | |||||
| (BRUSH_AUTOMASKING_VIEW_OCCLUSION | BRUSH_AUTOMASKING_VIEW_NORMAL)) == | |||||
| (BRUSH_AUTOMASKING_VIEW_OCCLUSION | BRUSH_AUTOMASKING_VIEW_NORMAL); | |||||
| if (do_occlusion && | |||||
| automasking_view_occlusion_factor(automasking, ss, vert, stroke_id, automask_data)) { | |||||
| return automasking_factor_end(ss, automasking, vert, 0.0f); | |||||
| } | |||||
| return sculpt_automasking_factor_calc(automasking, ss, vert, automask_data); | |||||
| } | |||||
| void SCULPT_automasking_cache_free(AutomaskingCache *automasking) | void SCULPT_automasking_cache_free(AutomaskingCache *automasking) | ||||
| { | { | ||||
| if (!automasking) { | if (!automasking) { | ||||
| return; | return; | ||||
| } | } | ||||
| MEM_SAFE_FREE(automasking); | MEM_SAFE_FREE(automasking); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | if (brush && SCULPT_tool_can_reuse_automask(brush->sculpt_tool) && !have_occlusion) { | ||||
| } | } | ||||
| } | } | ||||
| if (!automasking->can_reuse_mask) { | if (!automasking->can_reuse_mask) { | ||||
| ss->last_automask_stroke_id = ss->stroke_id; | ss->last_automask_stroke_id = ss->stroke_id; | ||||
| } | } | ||||
| } | } | ||||
| if (!SCULPT_automasking_needs_factors_cache(sd, brush) && ss->cache && ss->cache->use_pixels) { | |||||
| SculptAttributeParams params = {0}; | |||||
| params.stroke_only = true; | |||||
| /* | |||||
| * Allocate factor cache but don't initialize it. | |||||
| * Will be filled in by SCULPT_automasking_cache_check. | |||||
| */ | |||||
| ss->attrs.automasking_factor = BKE_sculpt_attribute_ensure( | |||||
| ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(automasking_factor), ¶ms); | |||||
| return automasking; | |||||
| } | |||||
| if (!SCULPT_automasking_needs_factors_cache(sd, brush)) { | if (!SCULPT_automasking_needs_factors_cache(sd, brush)) { | ||||
| return automasking; | return automasking; | ||||
| } | } | ||||
| automasking->has_full_factor_cache = true; | |||||
| SculptAttributeParams params = {0}; | SculptAttributeParams params = {0}; | ||||
| params.stroke_only = true; | params.stroke_only = true; | ||||
| ss->attrs.automasking_factor = BKE_sculpt_attribute_ensure( | ss->attrs.automasking_factor = BKE_sculpt_attribute_ensure( | ||||
| ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(automasking_factor), ¶ms); | ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(automasking_factor), ¶ms); | ||||
| float initial_value; | float initial_value; | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob) | ||||
| if (normal_bits) { | if (normal_bits) { | ||||
| sculpt_normal_occlusion_automasking_fill(automasking, ob, (eAutomasking_flag)normal_bits); | sculpt_normal_occlusion_automasking_fill(automasking, ob, (eAutomasking_flag)normal_bits); | ||||
| } | } | ||||
| return automasking; | return automasking; | ||||
| } | } | ||||
| void SCULPT_automasking_cache_check( | |||||
| Object *ob, SculptSession *ss, AutomaskingCache *automasking, PBVHNode **nodes, int totnode) | |||||
| { | |||||
| if (!automasking || automasking->has_full_factor_cache) { | |||||
| return; | |||||
| } | |||||
| Vector<Vector<PBVHVertRef>> node_other_verts; | |||||
| node_other_verts.resize(totnode); | |||||
| blender::threading::parallel_for(IndexRange(totnode), 2, [&](IndexRange range) { | |||||
| for (int i : range) { | |||||
| PBVHNode *node = nodes[i]; | |||||
| if (!BKE_pbvh_node_needs_automasking(ss->pbvh, node)) { | |||||
| return; | |||||
| } | |||||
| BKE_pbvh_node_automasking_unmark(ss->pbvh, node); | |||||
| PBVHVertexIter vd; | |||||
| AutomaskingNodeData automask_data; | |||||
| SCULPT_automasking_node_begin(ob, ss, automasking, &automask_data, nodes[i]); | |||||
| automask_data.initializing = true; | |||||
| BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { | |||||
| SCULPT_automasking_node_update(ss, &automask_data, &vd); | |||||
| if (vd.i >= vd.unique_vert_len) { | |||||
| node_other_verts[i].append(vd.vertex); | |||||
| } | |||||
| else { | |||||
| float value = SCULPT_automasking_factor_get(automasking, ss, vd.vertex, &automask_data); | |||||
| *(float *)SCULPT_vertex_attr_get(vd.vertex, ss->attrs.automasking_factor) = value; | |||||
| } | |||||
| } | |||||
| BKE_pbvh_vertex_iter_end; | |||||
| } | |||||
| }); | |||||
| Set<PBVHVertRef> done_set; | |||||
| for (int i : IndexRange(totnode)) { | |||||
| PBVHNode *node = nodes[i]; | |||||
| AutomaskingNodeData automask_data; | |||||
| SCULPT_automasking_node_begin(ob, ss, automasking, &automask_data, node); | |||||
| automask_data.initializing = true; | |||||
| PBVHVertexIter vd = {0}; | |||||
| for (PBVHVertRef vertex : node_other_verts[i]) { | |||||
| float co[3], no[3], mask = 1.0f; | |||||
| copy_v3_v3(co, SCULPT_vertex_co_get(ss, vertex)); | |||||
| SCULPT_vertex_normal_get(ss, vertex, no); | |||||
| mask = SCULPT_vertex_mask_get(ss, vertex); | |||||
| vd.co = co; | |||||
| vd.no = vd.fno = no; | |||||
| vd.mask = &mask; | |||||
| vd.i = 0; | |||||
| vd.vertex = vertex; | |||||
| vd.index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); | |||||
| SCULPT_automasking_node_update(ss, &automask_data, &vd); | |||||
| if (!done_set.contains(vertex)) { | |||||
| done_set.add(vertex); | |||||
| float value = SCULPT_automasking_factor_get(automasking, ss, vd.vertex, &automask_data); | |||||
| *(float *)SCULPT_vertex_attr_get(vd.vertex, ss->attrs.automasking_factor) = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| bool SCULPT_automasking_needs_original(const Sculpt *sd, const Brush *brush) | bool SCULPT_automasking_needs_original(const Sculpt *sd, const Brush *brush) | ||||
| { | { | ||||
| return sculpt_automasking_mode_effective_bits(sd, brush) & | return sculpt_automasking_mode_effective_bits(sd, brush) & | ||||
| (BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_BRUSH_NORMAL | | (BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_BRUSH_NORMAL | | ||||
| BRUSH_AUTOMASKING_VIEW_NORMAL); | BRUSH_AUTOMASKING_VIEW_NORMAL); | ||||
| } | } | ||||