Merge branch 'blender-v4.5-release'

This commit is contained in:
Falk David
2025-07-04 18:05:43 +02:00

View File

@@ -29,6 +29,8 @@
#include "ED_grease_pencil.hh"
#include "ED_view3d.hh"
#include "GEO_curves_remove_and_split.hh"
#include "WM_api.hh"
#include "WM_types.hh"
@@ -1076,6 +1078,58 @@ void EraseOperation::on_stroke_extended(const bContext &C, const InputSample &ex
executor.execute(*this, C, extension_sample);
}
static void simplify_opacities(blender::bke::CurvesGeometry &curves,
const VArray<float> &opacities,
const float epsilon)
{
/* Simplify in between the ranges of inserted points. */
const VArray<bool> point_was_inserted = *curves.attributes().lookup<bool>(
"_eraser_inserted", bke::AttrDomain::Point);
BLI_assert(point_was_inserted);
IndexMaskMemory memory;
const IndexMask inserted_points = IndexMask::from_bools(point_was_inserted, memory);
/* Distance function for the simplification algorithm.
* It is computed as the difference in opacity that may result from removing the
* samples inside the range. */
const Span<float3> positions = curves.positions();
const auto opacity_distance = [&](int64_t first_index, int64_t last_index, int64_t index) {
const float3 &s0 = positions[first_index];
const float3 &s1 = positions[last_index];
const float segment_length = math::distance(s0, s1);
if (segment_length < 1e-6) {
return 0.0f;
}
const float t = math::distance(s0, positions[index]) / segment_length;
const float linear_opacity = math::interpolate(
opacities[first_index], opacities[last_index], t);
return math::abs(opacities[index] - linear_opacity);
};
Array<bool> dissolve_points(curves.points_num(), false);
inserted_points.foreach_range([&](const IndexRange &range) {
const IndexRange range_to_simplify(range.one_before_start(), range.size() + 2);
ed::greasepencil::ramer_douglas_peucker_simplify(
range_to_simplify, epsilon, opacity_distance, dissolve_points);
});
/* Remove the points. */
const IndexMask points_to_dissolve = IndexMask::from_bools(dissolve_points, memory);
curves.remove_points(points_to_dissolve, {});
}
static void remove_points_with_low_opacity(blender::bke::CurvesGeometry &curves,
const VArray<float> &opacities,
const float epsilon)
{
IndexMaskMemory memory;
const IndexMask points_to_remove_and_split = IndexMask::from_predicate(
curves.points_range(), GrainSize(4096), memory, [&](const int64_t point) {
return opacities[point] < epsilon;
});
curves = geometry::remove_points_and_split(curves, points_to_remove_and_split);
}
void EraseOperation::on_stroke_done(const bContext &C)
{
Object *object = CTX_data_active_object(&C);
@@ -1087,56 +1141,22 @@ void EraseOperation::on_stroke_done(const bContext &C)
grease_pencil.runtime->temp_eraser_size = 0.0f;
}
/* Epsilon used for simplify. */
const float epsilon = 0.01f;
for (GreasePencilDrawing *drawing_ : affected_drawings_) {
blender::bke::CurvesGeometry &curves = drawing_->geometry.wrap();
bke::greasepencil::Drawing &drawing = drawing_->wrap();
/* Simplify in between the ranges of inserted points. */
const VArray<bool> &point_was_inserted = *curves.attributes().lookup<bool>(
"_eraser_inserted", bke::AttrDomain::Point);
if (point_was_inserted.is_empty()) {
continue;
if (drawing.strokes().attributes().contains("_eraser_inserted")) {
simplify_opacities(drawing.strokes_for_write(), drawing.opacities(), 0.01f);
}
IndexMaskMemory mem_inserted;
IndexMask inserted_points = IndexMask::from_bools(point_was_inserted, mem_inserted);
remove_points_with_low_opacity(drawing.strokes_for_write(), drawing.opacities(), 0.0001f);
/* Distance function for the simplification algorithm.
* It is computed as the difference in opacity that may result from removing the
* samples inside the range. */
VArray<float> opacities = drawing_->wrap().opacities();
Span<float3> positions = curves.positions();
const auto opacity_distance = [&](int64_t first_index, int64_t last_index, int64_t index) {
const float3 &s0 = positions[first_index];
const float3 &s1 = positions[last_index];
const float segment_length = math::distance(s0, s1);
if (segment_length < 1e-6) {
return 0.0f;
}
const float t = math::distance(s0, positions[index]) / segment_length;
const float linear_opacity = math::interpolate(
opacities[first_index], opacities[last_index], t);
return math::abs(opacities[index] - linear_opacity);
};
Array<bool> remove_points(curves.points_num(), false);
inserted_points.foreach_range([&](const IndexRange &range) {
IndexRange range_to_simplify(range.one_before_start(), range.size() + 2);
ed::greasepencil::ramer_douglas_peucker_simplify(
range_to_simplify, epsilon, opacity_distance, remove_points);
});
/* Remove the points. */
IndexMaskMemory mem_remove;
IndexMask points_to_remove = IndexMask::from_bools(remove_points, mem_remove);
curves.remove_points(points_to_remove, {});
drawing_->wrap().tag_topology_changed();
curves.attributes_for_write().remove("_eraser_inserted");
drawing.strokes_for_write().attributes_for_write().remove("_eraser_inserted");
drawing.tag_topology_changed();
}
affected_drawings_.clear();
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil.id);
}
std::unique_ptr<GreasePencilStrokeOperation> new_erase_operation(const bool temp_eraser)