Fix #101766: support orbit-around-selection in curves sculpt mode
How the new navigation pivot is determined depends a bit on the kind of brush: * Brushes that deform or remove curves use the 3d-brush position at the start of the brush. * Brushes that add new curves set the pivot to the bounding box center of the new curves. Finding a good pivot point is not super trivial for curves, but the existing 3d brush functionality seems to work well. This also has the benefit that almost no additional computation is needed when the user is using the spherical brush mode. However, if the projected mode is used, and orbit-around-selection is on, then we have to compute the spherical brush center now anyway. Pull Request: https://projects.blender.org/blender/blender/pulls/131907
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "curves_sculpt_intern.hh"
|
||||
|
||||
#include "BLI_bounds.hh"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
@@ -239,6 +240,14 @@ struct AddOperationExecutor {
|
||||
add_outputs.new_curves_range));
|
||||
selection.finish();
|
||||
}
|
||||
if (U.uiflag & USER_ORBIT_SELECTION) {
|
||||
if (const std::optional<Bounds<float3>> center_cu = bounds::min_max(
|
||||
curves_orig_->positions().slice(add_outputs.new_points_range)))
|
||||
{
|
||||
remember_stroke_position(
|
||||
*ctx_.scene, math::transform_point(transforms_.curves_to_world, center_cu->center()));
|
||||
}
|
||||
}
|
||||
|
||||
if (add_outputs.uv_error) {
|
||||
report_invalid_uv_map(stroke_extension.reports);
|
||||
|
||||
@@ -346,6 +346,14 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr
|
||||
return matrices;
|
||||
}
|
||||
|
||||
void remember_stroke_position(Scene &scene, const float3 &brush_position_wo)
|
||||
{
|
||||
UnifiedPaintSettings &ups = scene.toolsettings->unified_paint_settings;
|
||||
copy_v3_v3(ups.average_stroke_accum, brush_position_wo);
|
||||
ups.average_stroke_counter = 1;
|
||||
ups.last_stroke_valid = true;
|
||||
}
|
||||
|
||||
float transform_brush_radius(const float4x4 &transform,
|
||||
const float3 &brush_position,
|
||||
const float old_radius)
|
||||
|
||||
@@ -137,7 +137,7 @@ struct CombOperationExecutor {
|
||||
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
this->initialize_spherical_brush_reference_point();
|
||||
}
|
||||
self_->constraint_solver_.initialize(
|
||||
@@ -392,6 +392,9 @@ struct CombOperationExecutor {
|
||||
brush_radius_base_re_);
|
||||
if (brush_3d.has_value()) {
|
||||
self_->brush_3d_ = *brush_3d;
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -106,7 +106,7 @@ struct DeleteOperationExecutor {
|
||||
const eBrushFalloffShape falloff_shape = eBrushFalloffShape(brush_->falloff_shape);
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
this->initialize_spherical_brush_reference_point();
|
||||
}
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
@@ -261,6 +261,9 @@ struct DeleteOperationExecutor {
|
||||
brush_radius_base_re_);
|
||||
if (brush_3d.has_value()) {
|
||||
self_->brush_3d_ = *brush_3d;
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_paint.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BLI_bounds.hh"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
#include "ED_view3d.hh"
|
||||
@@ -287,6 +288,14 @@ struct DensityAddOperationExecutor {
|
||||
add_outputs.new_curves_range));
|
||||
selection.finish();
|
||||
}
|
||||
if (U.uiflag & USER_ORBIT_SELECTION) {
|
||||
if (const std::optional<Bounds<float3>> center_cu = bounds::min_max(
|
||||
curves_orig_->positions().slice(add_outputs.new_points_range)))
|
||||
{
|
||||
remember_stroke_position(
|
||||
*ctx_.scene, math::transform_point(transforms_.curves_to_world, center_cu->center()));
|
||||
}
|
||||
}
|
||||
|
||||
if (add_outputs.uv_error) {
|
||||
report_invalid_uv_map(stroke_extension.reports);
|
||||
|
||||
@@ -290,7 +290,7 @@ struct CurvesEffectOperationExecutor {
|
||||
brush_pos_end_re_ = stroke_extension.mouse_position;
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE || (U.flag & USER_ORBIT_SELECTION)) {
|
||||
if (std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
|
||||
*ctx_.depsgraph,
|
||||
*ctx_.region,
|
||||
@@ -301,6 +301,9 @@ struct CurvesEffectOperationExecutor {
|
||||
brush_radius_base_re_))
|
||||
{
|
||||
self.brush_3d_ = *brush_3d;
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,12 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
|
||||
const float2 &brush_pos_re,
|
||||
const float brush_radius_re);
|
||||
|
||||
/**
|
||||
* Updates the position of the stroke so that it can be used by the orbit-around-selection
|
||||
* navigation method.
|
||||
*/
|
||||
void remember_stroke_position(Scene &scene, const float3 &brush_position_wo);
|
||||
|
||||
Vector<float4x4> get_symmetry_brush_transforms(eCurvesSymmetryType symmetry);
|
||||
|
||||
bke::SpanAttributeWriter<float> float_selection_ensure(Curves &curves_id);
|
||||
@@ -117,7 +123,7 @@ void move_last_point_and_resample(MoveAndResampleBuffers &buffer,
|
||||
class CurvesSculptCommonContext {
|
||||
public:
|
||||
const Depsgraph *depsgraph = nullptr;
|
||||
const Scene *scene = nullptr;
|
||||
Scene *scene = nullptr;
|
||||
ARegion *region = nullptr;
|
||||
const View3D *v3d = nullptr;
|
||||
RegionView3D *rv3d = nullptr;
|
||||
|
||||
@@ -112,7 +112,7 @@ struct PinchOperationExecutor {
|
||||
const eBrushFalloffShape falloff_shape = eBrushFalloffShape(brush_->falloff_shape);
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
self_->brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
|
||||
*ctx_.region,
|
||||
*ctx_.v3d,
|
||||
@@ -120,6 +120,9 @@ struct PinchOperationExecutor {
|
||||
*object_,
|
||||
brush_pos_re_,
|
||||
brush_radius_base_re_);
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
|
||||
self_->constraint_solver_.initialize(
|
||||
|
||||
@@ -121,7 +121,7 @@ struct PuffOperationExecutor {
|
||||
surface_bvh_ = surface_->bvh_corner_tris();
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
|
||||
*ctx_.region,
|
||||
*ctx_.v3d,
|
||||
@@ -129,6 +129,9 @@ struct PuffOperationExecutor {
|
||||
*object_,
|
||||
brush_pos_re_,
|
||||
brush_radius_base_re_);
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
|
||||
self_->constraint_solver_.initialize(
|
||||
|
||||
@@ -115,7 +115,7 @@ struct SelectionPaintOperationExecutor {
|
||||
selection_goal_ = self_->use_select_ ? 1.0f : 0.0f;
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
this->initialize_spherical_brush_reference_point();
|
||||
}
|
||||
}
|
||||
@@ -377,6 +377,9 @@ struct SelectionPaintOperationExecutor {
|
||||
brush_radius_base_re_);
|
||||
if (brush_3d.has_value()) {
|
||||
self_->brush_3d_ = *brush_3d;
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -239,6 +239,9 @@ struct SlideOperationExecutor {
|
||||
if (!brush_3d.has_value()) {
|
||||
return;
|
||||
}
|
||||
remember_stroke_position(
|
||||
*ctx_.scene, math::transform_point(transforms_.curves_to_world, brush_3d->position_cu));
|
||||
|
||||
const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_,
|
||||
surface_corner_tris_orig_};
|
||||
for (const float4x4 &brush_transform : brush_transforms) {
|
||||
|
||||
@@ -87,7 +87,7 @@ struct SmoothOperationExecutor {
|
||||
|
||||
const eBrushFalloffShape falloff_shape = eBrushFalloffShape(brush_->falloff_shape);
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
|
||||
*ctx_.region,
|
||||
*ctx_.v3d,
|
||||
@@ -95,6 +95,9 @@ struct SmoothOperationExecutor {
|
||||
*object_,
|
||||
brush_pos_re_,
|
||||
brush_radius_base_re_);
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ struct SnakeHookOperatorExecutor {
|
||||
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
|
||||
|
||||
if (stroke_extension.is_first) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
|
||||
*ctx_.region,
|
||||
*ctx_.v3d,
|
||||
@@ -139,6 +139,9 @@ struct SnakeHookOperatorExecutor {
|
||||
brush_radius_base_re_);
|
||||
if (brush_3d.has_value()) {
|
||||
self_->brush_3d_ = *brush_3d;
|
||||
remember_stroke_position(
|
||||
*ctx_.scene,
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -801,6 +801,10 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
|
||||
BKE_paint_stroke_get_average(scene, ob_act_eval, lastofs);
|
||||
is_set = true;
|
||||
}
|
||||
else if (ob_act && (ob_act->mode & OB_MODE_SCULPT_CURVES)) {
|
||||
BKE_paint_stroke_get_average(scene, ob_act_eval, lastofs);
|
||||
is_set = true;
|
||||
}
|
||||
else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
|
||||
Curve *cu = static_cast<Curve *>(ob_act_eval->data);
|
||||
EditFont *ef = cu->editfont;
|
||||
|
||||
Reference in New Issue
Block a user