Curves: initial surface collision for curves sculpt mode #104469

Merged
Jacques Lucke merged 29 commits from JacquesLucke/blender:temp-curves-surface-collision into main 2023-02-11 13:46:39 +01:00
5 changed files with 75 additions and 71 deletions
Showing only changes of commit 43261bebae - Show all commits

View File

@ -22,6 +22,8 @@
#include "BLT_translation.h"
#include "GEO_curve_constraint_solver.hh"
/**
* The code below uses a prefix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
@ -424,4 +426,40 @@ void report_invalid_uv_map(ReportList *reports)
BKE_report(reports, RPT_WARNING, TIP_("Invalid UV map: UV islands must not overlap"));
}
void CurvesConstraintSolver::initialize(const bke::CurvesGeometry &curves,
const IndexMask curve_selection,
const bool use_surface_collision)
{
use_surface_collision_ = use_surface_collision;
segment_lengths_.reinitialize(curves.points_num());
geometry::curve_constraint_solver::compute_segment_lengths(
curves.points_by_curve(), curves.positions(), curve_selection, segment_lengths_);
if (use_surface_collision_) {
start_positions_ = curves.positions();
}
}
void CurvesConstraintSolver::solve_step(bke::CurvesGeometry &curves,
const IndexMask curve_selection,
const Mesh *surface,
const CurvesSurfaceTransforms &transforms)
{
if (use_surface_collision_ && surface != nullptr) {
geometry::curve_constraint_solver::solve_length_and_collision_constraints(
curves.points_by_curve(),
curve_selection,
segment_lengths_,
start_positions_,
*surface,
transforms,
curves.positions_for_write());
start_positions_ = curves.positions();
}
else {
geometry::curve_constraint_solver::solve_length_constraints(
curves.points_by_curve(), curve_selection, segment_lengths_, curves.positions_for_write());
}
curves.tag_positions_changed();
}
} // namespace blender::ed::sculpt_paint

View File

@ -38,8 +38,6 @@
#include "ED_screen.h"
#include "ED_view3d.h"
#include "GEO_curve_constraint_solver.hh"
#include "UI_interface.h"
#include "WM_api.h"
@ -57,52 +55,6 @@ namespace blender::ed::sculpt_paint {
using blender::bke::CurvesGeometry;
using threading::EnumerableThreadSpecific;
struct ConstraintSolver {
private:
bool use_surface_collision_;
Array<float3> start_positions_;
Array<float> segment_lengths_;
public:
void initialize(const bke::CurvesGeometry &curves,
const IndexMask curve_selection,
const bool use_surface_collision)
{
use_surface_collision_ = use_surface_collision;
segment_lengths_.reinitialize(curves.points_num());
geometry::curve_constraint_solver::compute_segment_lengths(
curves.points_by_curve(), curves.positions(), curve_selection, segment_lengths_);
if (use_surface_collision_) {
start_positions_ = curves.positions();
}
}
void solve(bke::CurvesGeometry &curves,
const IndexMask curve_selection,
const Mesh &surface,
const CurvesSurfaceTransforms &transforms)
{
if (use_surface_collision_) {
geometry::curve_constraint_solver::solve_length_and_collision_constraints(
curves.points_by_curve(),
curve_selection,
segment_lengths_,
start_positions_,
surface,
transforms,
curves.positions_for_write());
start_positions_ = curves.positions();
}
else {
geometry::curve_constraint_solver::solve_length_constraints(curves.points_by_curve(),
curve_selection,
segment_lengths_,
curves.positions_for_write());
}
curves.tag_positions_changed();
}
};
/**
* Moves individual points under the brush and does a length preservation step afterwards.
*/
@ -114,8 +66,8 @@ class CombOperation : public CurvesSculptStrokeOperation {
/** Only used when a 3D brush is used. */
CurvesBrush3D brush_3d_;
/** Solver for length and contact constraints. */
ConstraintSolver constraint_solver_;
/** Solver for length and collision constraints. */
CurvesConstraintSolver constraint_solver_;
friend struct CombOperationExecutor;
@ -230,8 +182,8 @@ struct CombOperationExecutor {
totcurves += curves.size();
};
self_->constraint_solver_.solve(
*curves_orig_, IndexMask(all_changed_curves), *surface, transforms_);
self_->constraint_solver_.solve_step(
*curves_orig_, IndexMask(all_changed_curves), surface, transforms_);
curves_orig_->tag_positions_changed();
DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY);

View File

@ -144,4 +144,25 @@ void report_missing_uv_map_on_original_surface(ReportList *reports);
void report_missing_uv_map_on_evaluated_surface(ReportList *reports);
void report_invalid_uv_map(ReportList *reports);
/**
* Utility class to make it easy for brushes to implement length preservation and surface
* collision.
*/
struct CurvesConstraintSolver {
private:
bool use_surface_collision_;
Array<float3> start_positions_;
Array<float> segment_lengths_;
public:
void initialize(const bke::CurvesGeometry &curves,
const IndexMask curve_selection,
const bool use_surface_collision);
void solve_step(bke::CurvesGeometry &curves,
const IndexMask curve_selection,
const Mesh *surface,
const CurvesSurfaceTransforms &transforms);
};
} // namespace blender::ed::sculpt_paint

View File

@ -40,14 +40,12 @@
namespace blender::ed::sculpt_paint {
using geometry::ConstraintSolver;
class PinchOperation : public CurvesSculptStrokeOperation {
private:
bool invert_pinch_;
/** Solver for length and contact constraints. */
ConstraintSolver constraint_solver_;
/** Solver for length and collision constraints. */
CurvesConstraintSolver constraint_solver_;
/** Only used when a 3D brush is used. */
CurvesBrush3D brush_3d_;
@ -131,9 +129,8 @@ struct PinchOperationExecutor {
brush_radius_base_re_);
}
ConstraintSolver::Params params;
params.use_collision_constraints = curves_id_->flag & CV_SCULPT_COLLISION_ENABLED;
self_->constraint_solver_.initialize(params, *curves_, curve_selection_);
self_->constraint_solver_.initialize(
*curves_, curve_selection_, curves_id_->flag & CV_SCULPT_COLLISION_ENABLED);
}
start_positions_ = curves_->positions();
@ -162,8 +159,8 @@ struct PinchOperationExecutor {
const Mesh *surface = curves_id_->surface && curves_id_->surface->type == OB_MESH ?
static_cast<Mesh *>(curves_id_->surface->data) :
nullptr;
self_->constraint_solver_.step_curves(
*curves_, surface, transforms_, start_positions_, IndexMask(changed_curves_indices));
self_->constraint_solver_.solve_step(
*curves_, IndexMask(changed_curves_indices), surface, transforms_);
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);

View File

@ -22,21 +22,18 @@
#include "BLI_length_parameterize.hh"
#include "GEO_add_curves_on_mesh.hh"
#include "GEO_constraint_solver.hh"
#include "curves_sculpt_intern.hh"
namespace blender::ed::sculpt_paint {
using geometry::ConstraintSolver;
class PuffOperation : public CurvesSculptStrokeOperation {
private:
/** Only used when a 3D brush is used. */
CurvesBrush3D brush_3d_;
/** Solver for length and contact constraints. */
ConstraintSolver constraint_solver_;
/** Solver for length and collision constraints. */
CurvesConstraintSolver constraint_solver_;
friend struct PuffOperationExecutor;
@ -142,9 +139,8 @@ struct PuffOperationExecutor {
brush_radius_base_re_);
}
ConstraintSolver::Params params;
params.use_collision_constraints = curves_id_->flag & CV_SCULPT_COLLISION_ENABLED;
self_->constraint_solver_.initialize(params, *curves_, curve_selection_);
self_->constraint_solver_.initialize(
*curves_, curve_selection_, curves_id_->flag & CV_SCULPT_COLLISION_ENABLED);
}
start_positions_ = curves_->positions();
@ -173,8 +169,8 @@ struct PuffOperationExecutor {
}
}
self_->constraint_solver_.step_curves(
*curves_, surface_, transforms_, start_positions_, IndexMask(changed_curves_indices));
self_->constraint_solver_.solve_step(
*curves_, IndexMask(changed_curves_indices), surface_, transforms_);
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);