Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt.cc
| Show All 10 Lines | |||||
| #include <cstring> | #include <cstring> | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_dial_2d.h" | #include "BLI_dial_2d.h" | ||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | ||||
| #include "BLI_gsqueue.h" | #include "BLI_gsqueue.h" | ||||
| #include "BLI_index_range.hh" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #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_task.hh" | ||||
| #include "BLI_timeit.hh" | #include "BLI_timeit.hh" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | ||||
| #include "DNA_brush_types.h" | #include "DNA_brush_types.h" | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
| #include "bmesh.h" | #include "bmesh.h" | ||||
| using blender::float3; | using blender::float3; | ||||
| using blender::MutableSpan; | using blender::MutableSpan; | ||||
| using blender::Set; | using blender::Set; | ||||
| using blender::Vector; | using blender::Vector; | ||||
| using blender::float2; | |||||
| using blender::float3; | |||||
| using blender::IndexRange; | |||||
| using blender::MutableSpan; | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Sculpt PBVH Abstraction API | /** \name Sculpt PBVH Abstraction API | ||||
| * | * | ||||
| * This is read-only, for writing use PBVH vertex iterators. There vd.index matches | * This is read-only, for writing use PBVH vertex iterators. There vd.index matches | ||||
| * the indices used here. | * the indices used here. | ||||
| * | * | ||||
| * For multi-resolution, the same vertex in multiple grids is counted multiple times, with | * For multi-resolution, the same vertex in multiple grids is counted multiple times, with | ||||
| * different index for each grid. | * different index for each grid. | ||||
| ▲ Show 20 Lines • Show All 2,523 Lines • ▼ Show 20 Lines | if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) { | ||||
| x += mtex->ofs[0]; | x += mtex->ofs[0]; | ||||
| y += mtex->ofs[1]; | y += mtex->ofs[1]; | ||||
| avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id); | avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id); | ||||
| avg += br->texture_sample_bias; | avg += br->texture_sample_bias; | ||||
| } | } | ||||
| else if (ss->cache && mtex->brush_map_mode == MTEX_MAP_MODE_ROLL) { | |||||
| float3 point_3d; | |||||
| point_3d[2] = 0.0f; | |||||
| float3 tan; | |||||
| float3 point_3d2; | |||||
| float2 abs_point = brush_point, abs_start = ss->cache->true_location; | |||||
| float3 tile_point = brush_point; | |||||
| /* Find position in root tile. */ | |||||
| for (int i = 0; i < 3; i++) { | |||||
| if (ss->cache->symmetry_flags & (PAINT_TILE_X << i)) { | |||||
| float offset = ss->cache->location[i] - ss->cache->true_location[i]; | |||||
| tile_point[i] -= offset; | |||||
| } | |||||
| } | |||||
| /* Rotate into base radial slice. */ | |||||
| if (ss->cache->radial_symmetry_pass > 0) { | |||||
| mul_m4_v3(ss->cache->symm_rot_mat_inv, tile_point); | |||||
| } | |||||
| /* First sample.*/ | |||||
| paint_stroke_spline_uv(ss->cache->stroke, ss->cache, tile_point, point_3d, tan); | |||||
| /* Loop through each possible symmetry combination. */ | |||||
| for (int i = 0; i < 8; i++) { | |||||
| if ((ss->cache->mirror_symmetry_pass & i) != i) { | |||||
| continue; | |||||
| } | |||||
| float symm_point[3]; | |||||
| copy_v3_v3(symm_point, tile_point); | |||||
| for (int j = 0; j < 3; j++) { | |||||
| if (i & (1 << j) && i & (ss->cache->mirror_symmetry_pass)) { | |||||
| symm_point[j] = -symm_point[j]; | |||||
| } | |||||
| } | |||||
| paint_stroke_spline_uv(ss->cache->stroke, ss->cache, symm_point, point_3d2, tan); | |||||
| if (std::abs(point_3d2[0]) < std::abs(point_3d[0])) { | |||||
| copy_v3_v3(point_3d, point_3d2); | |||||
| } | |||||
| } | |||||
| mul_v3_fl(point_3d, 1.0f / ss->cache->initial_radius); | |||||
| float angle = mtex->rot; | |||||
| float3 final; | |||||
| rotate_v2_v2fl(final, point_3d, angle); | |||||
| #if 0 /* Write texture UVs to color attribute*/ | |||||
| if (SCULPT_has_colors(ss)) { | |||||
| float color[4] = {final[0], final[1], 0.0f, 1.0f}; | |||||
| mul_v3_fl(color, 0.25f / ss->cache->initial_radius); | |||||
| color[0] -= floorf(color[0]); | |||||
| color[1] -= floorf(color[1]); | |||||
| color[2] -= floorf(color[2]); | |||||
| SCULPT_vertex_color_set(ss, vertex, color); | |||||
| } | |||||
| #endif | |||||
| avg = paint_get_tex_pixel(mtex, final[0], final[1], ss->tex_pool, thread_id); | |||||
| avg += br->texture_sample_bias; | |||||
| } | |||||
| else { | else { | ||||
| const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; | const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; | ||||
| avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, 0, ss->tex_pool); | avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, thread_id, ss->tex_pool); | ||||
| } | } | ||||
| } | } | ||||
| /* Hardness. */ | /* Hardness. */ | ||||
| float final_len = len; | float final_len = len; | ||||
| const float hardness = cache->paint_brush.hardness; | const float hardness = cache->paint_brush.hardness; | ||||
| float p = len / cache->radius; | float p = len / cache->radius; | ||||
| if (p < hardness) { | if (p < hardness) { | ||||
| ▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | static PBVHNode **sculpt_pbvh_gather_generic_intern(Object *ob, | ||||
| if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { | if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { | ||||
| SculptSearchSphereData data{}; | SculptSearchSphereData data{}; | ||||
| data.ss = ss; | data.ss = ss; | ||||
| data.sd = sd; | data.sd = sd; | ||||
| data.radius_squared = square_f(ss->cache->radius * radius_scale); | data.radius_squared = square_f(ss->cache->radius * radius_scale); | ||||
| data.original = use_original; | data.original = use_original; | ||||
| data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK; | data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK; | ||||
| data.center = nullptr; | data.center = nullptr; | ||||
| BKE_pbvh_search_gather_ex(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode, leaf_flag); | BKE_pbvh_search_gather_ex( | ||||
| ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode, leaf_flag); | |||||
| } | } | ||||
| else { | else { | ||||
| DistRayAABB_Precalc dist_ray_to_aabb_precalc; | DistRayAABB_Precalc dist_ray_to_aabb_precalc; | ||||
| dist_squared_ray_to_aabb_v3_precalc( | dist_squared_ray_to_aabb_v3_precalc( | ||||
| &dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal); | &dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal); | ||||
| SculptSearchCircleData data{}; | SculptSearchCircleData data{}; | ||||
| data.ss = ss; | data.ss = ss; | ||||
| data.sd = sd; | data.sd = sd; | ||||
| data.radius_squared = ss->cache ? square_f(ss->cache->radius * radius_scale) : | data.radius_squared = ss->cache ? square_f(ss->cache->radius * radius_scale) : | ||||
| ss->cursor_radius; | ss->cursor_radius; | ||||
| data.original = use_original; | data.original = use_original; | ||||
| data.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc; | data.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc; | ||||
| data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK; | data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK; | ||||
| BKE_pbvh_search_gather_ex(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode, leaf_flag); | BKE_pbvh_search_gather_ex( | ||||
| ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode, leaf_flag); | |||||
| } | } | ||||
| return nodes; | return nodes; | ||||
| } | } | ||||
| static PBVHNode **sculpt_pbvh_gather_generic(Object *ob, | static PBVHNode **sculpt_pbvh_gather_generic(Object *ob, | ||||
| Sculpt *sd, | Sculpt *sd, | ||||
| const Brush *brush, | const Brush *brush, | ||||
| bool use_original, | bool use_original, | ||||
| ▲ Show 20 Lines • Show All 1,270 Lines • ▼ Show 20 Lines | static void do_radial_symmetry(Sculpt *sd, | ||||
| PaintModeSettings *paint_mode_settings, | PaintModeSettings *paint_mode_settings, | ||||
| BrushActionFunc action, | BrushActionFunc action, | ||||
| const ePaintSymmetryFlags symm, | const ePaintSymmetryFlags symm, | ||||
| const int axis, | const int axis, | ||||
| const float /*feather*/) | const float /*feather*/) | ||||
| { | { | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| ss->cache->radial_symmetry_axis = axis; | |||||
| for (int i = 1; i < sd->radial_symm[axis - 'X']; i++) { | for (int i = 1; i < sd->radial_symm[axis - 'X']; i++) { | ||||
| const float angle = 2.0f * M_PI * i / sd->radial_symm[axis - 'X']; | const float angle = 2.0f * M_PI * i / sd->radial_symm[axis - 'X']; | ||||
| ss->cache->radial_symmetry_pass = i; | ss->cache->radial_symmetry_pass = i; | ||||
| SCULPT_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); | SCULPT_cache_calc_brushdata_symm(ss->cache, symm, axis, angle); | ||||
| do_tiled(sd, ob, brush, ups, paint_mode_settings, action); | do_tiled(sd, ob, brush, ups, paint_mode_settings, action); | ||||
| } | } | ||||
| ss->cache->radial_symmetry_axis = 0; | |||||
| } | } | ||||
| /** | /** | ||||
| * Noise texture gives different values for the same input coord; this | * Noise texture gives different values for the same input coord; this | ||||
| * can tear a multi-resolution mesh during sculpting so do a stitch in this case. | * can tear a multi-resolution mesh during sculpting so do a stitch in this case. | ||||
| */ | */ | ||||
| static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) | static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) | ||||
| { | { | ||||
| Show All 16 Lines | static void do_symmetrical_brush_actions(Sculpt *sd, | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const char symm = SCULPT_mesh_symmetry_xyz_get(ob); | const char symm = SCULPT_mesh_symmetry_xyz_get(ob); | ||||
| float feather = calc_symmetry_feather(sd, ss->cache); | float feather = calc_symmetry_feather(sd, ss->cache); | ||||
| cache->bstrength = brush_strength(sd, cache, feather, ups, paint_mode_settings); | cache->bstrength = brush_strength(sd, cache, feather, ups, paint_mode_settings); | ||||
| cache->symmetry = symm; | cache->symmetry = symm; | ||||
| cache->symmetry_flags = ePaintSymmetryFlags(sd->paint.symmetry_flags & | |||||
| (PAINT_TILE_X | PAINT_TILE_Y | PAINT_TILE_Z)); | |||||
| copy_v3_v3(cache->tile_offset, sd->paint.tile_offset); | |||||
| /* `symm` is a bit combination of XYZ - | /* `symm` is a bit combination of XYZ - | ||||
| * 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ | * 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ | ||||
| for (int i = 0; i <= symm; i++) { | for (int i = 0; i <= symm; i++) { | ||||
| if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { | if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i); | const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i); | ||||
| ▲ Show 20 Lines • Show All 1,475 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; | UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; | ||||
| Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| const Brush *brush = BKE_paint_brush(&sd->paint); | const Brush *brush = BKE_paint_brush(&sd->paint); | ||||
| ToolSettings *tool_settings = CTX_data_tool_settings(C); | ToolSettings *tool_settings = CTX_data_tool_settings(C); | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| cache->stroke_distance = paint_stroke_distance_get(stroke); | cache->stroke_distance = paint_stroke_distance_get(stroke); | ||||
| cache->stroke = stroke; | |||||
| SCULPT_stroke_modifiers_check(C, ob, brush); | SCULPT_stroke_modifiers_check(C, ob, brush); | ||||
| sculpt_update_cache_variants(C, sd, ob, itemptr); | sculpt_update_cache_variants(C, sd, ob, itemptr); | ||||
| sculpt_restore_mesh(sd, ob); | sculpt_restore_mesh(sd, ob); | ||||
| if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) { | if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) { | ||||
| float object_space_constant_detail = 1.0f / (sd->constant_detail * | float object_space_constant_detail = 1.0f / (sd->constant_detail * | ||||
| mat4_to_scale(ob->object_to_world)); | mat4_to_scale(ob->object_to_world)); | ||||
| ▲ Show 20 Lines • Show All 719 Lines • Show Last 20 Lines | |||||