Fix #115843: Expose curves sculpt collision distance
The hardcoded value doesn't work well with real scale human heads for example (was already adjusted once ina76b5d3a07). The result for too high values is a complete "freeze" of the whole curve (since the solution frome7606139bahas the problem that it keeps running into max iterations of the collision solver). As long as no better solver is implemented, it is better to have an adjustable value (to work on differently sizes objects) to not run into the above issue (same as the old particle hair system had) and show it in sculptmode next to the button which enables collision. This is done per `Curves` (same as the flag `CV_SCULPT_COLLISION_ENABLED`), similar to symmetry settings [alternatively, it could be part of `BrushCurvesSculptSettings` but I think it makes more sense in Curves] and then passed on to the `CurvesConstraintSolver`. Includes versioning code (to set the default for old files). Pull Request: https://projects.blender.org/blender/blender/pulls/132997
This commit is contained in:
committed by
Philipp Oeser
parent
d9d7d3b354
commit
e700e1f71c
@@ -170,7 +170,11 @@ class VIEW3D_HT_tool_header(Header):
|
||||
sub.prop(ob.data, "use_mirror_y", text="Y", toggle=True)
|
||||
sub.prop(ob.data, "use_mirror_z", text="Z", toggle=True)
|
||||
|
||||
layout.prop(ob.data, "use_sculpt_collision", icon='MOD_PHYSICS', icon_only=True, toggle=True)
|
||||
row = layout.row(align=True)
|
||||
row.prop(ob.data, "use_sculpt_collision", icon='MOD_PHYSICS', icon_only=True, toggle=True)
|
||||
sub = row.row(align=True)
|
||||
sub.active = ob.data.use_sculpt_collision
|
||||
sub.prop(ob.data, "surface_collision_distance")
|
||||
|
||||
# Expand panels from the side-bar as popovers.
|
||||
popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 22
|
||||
#define BLENDER_FILE_SUBVERSION 23
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -315,6 +315,7 @@ void curves_copy_parameters(const Curves &src, Curves &dst)
|
||||
if (src.surface_uv_map != nullptr) {
|
||||
dst.surface_uv_map = BLI_strdup(src.surface_uv_map);
|
||||
}
|
||||
dst.surface_collision_distance = src.surface_collision_distance;
|
||||
}
|
||||
|
||||
CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob)
|
||||
|
||||
@@ -5638,6 +5638,14 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 404, 23)) {
|
||||
if (!DNA_struct_member_exists(fd->filesdna, "Curves", "float", "surface_collision_distance")) {
|
||||
LISTBASE_FOREACH (Curves *, curves, &bmain->hair_curves) {
|
||||
curves->surface_collision_distance = 0.005f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Always run this versioning; meshes are written with the legacy format which always needs to
|
||||
* be converted to the new format on file load. Can be moved to a subversion check in a larger
|
||||
* breaking release. */
|
||||
|
||||
@@ -439,9 +439,11 @@ void report_invalid_uv_map(ReportList *reports)
|
||||
|
||||
void CurvesConstraintSolver::initialize(const bke::CurvesGeometry &curves,
|
||||
const IndexMask &curve_selection,
|
||||
const bool use_surface_collision)
|
||||
const bool use_surface_collision,
|
||||
const float surface_collision_distance)
|
||||
{
|
||||
use_surface_collision_ = use_surface_collision;
|
||||
surface_collision_distance_ = surface_collision_distance;
|
||||
segment_lengths_.reinitialize(curves.points_num());
|
||||
geometry::curve_constraints::compute_segment_lengths(
|
||||
curves.points_by_curve(), curves.positions(), curve_selection, segment_lengths_);
|
||||
@@ -463,7 +465,8 @@ void CurvesConstraintSolver::solve_step(bke::CurvesGeometry &curves,
|
||||
start_positions_,
|
||||
*surface,
|
||||
transforms,
|
||||
curves.positions_for_write());
|
||||
curves.positions_for_write(),
|
||||
surface_collision_distance_);
|
||||
start_positions_ = curves.positions();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -140,8 +140,10 @@ struct CombOperationExecutor {
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
|
||||
this->initialize_spherical_brush_reference_point();
|
||||
}
|
||||
self_->constraint_solver_.initialize(
|
||||
*curves_orig_, curve_selection_, curves_id_orig_->flag & CV_SCULPT_COLLISION_ENABLED);
|
||||
self_->constraint_solver_.initialize(*curves_orig_,
|
||||
curve_selection_,
|
||||
curves_id_orig_->flag & CV_SCULPT_COLLISION_ENABLED,
|
||||
curves_id_orig_->surface_collision_distance);
|
||||
|
||||
self_->curve_lengths_.reinitialize(curves_orig_->curves_num());
|
||||
const Span<float> segment_lengths = self_->constraint_solver_.segment_lengths();
|
||||
|
||||
@@ -162,13 +162,15 @@ void report_invalid_uv_map(ReportList *reports);
|
||||
struct CurvesConstraintSolver {
|
||||
private:
|
||||
bool use_surface_collision_;
|
||||
float surface_collision_distance_;
|
||||
Array<float3> start_positions_;
|
||||
Array<float> segment_lengths_;
|
||||
|
||||
public:
|
||||
void initialize(const bke::CurvesGeometry &curves,
|
||||
const IndexMask &curve_selection,
|
||||
const bool use_surface_collision);
|
||||
const bool use_surface_collision,
|
||||
const float surface_collision_distance);
|
||||
|
||||
void solve_step(bke::CurvesGeometry &curves,
|
||||
const IndexMask &curve_selection,
|
||||
|
||||
@@ -125,8 +125,10 @@ struct PinchOperationExecutor {
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
|
||||
self_->constraint_solver_.initialize(
|
||||
*curves_, curve_selection_, curves_id_->flag & CV_SCULPT_COLLISION_ENABLED);
|
||||
self_->constraint_solver_.initialize(*curves_,
|
||||
curve_selection_,
|
||||
curves_id_->flag & CV_SCULPT_COLLISION_ENABLED,
|
||||
curves_id_->surface_collision_distance);
|
||||
}
|
||||
|
||||
Array<bool> changed_curves(curves_->curves_num(), false);
|
||||
|
||||
@@ -134,8 +134,10 @@ struct PuffOperationExecutor {
|
||||
math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
|
||||
}
|
||||
|
||||
self_->constraint_solver_.initialize(
|
||||
*curves_, curve_selection_, curves_id_->flag & CV_SCULPT_COLLISION_ENABLED);
|
||||
self_->constraint_solver_.initialize(*curves_,
|
||||
curve_selection_,
|
||||
curves_id_->flag & CV_SCULPT_COLLISION_ENABLED,
|
||||
curves_id_->surface_collision_distance);
|
||||
}
|
||||
|
||||
Array<float> curve_weights(curves_->curves_num(), 0.0f);
|
||||
|
||||
@@ -24,6 +24,7 @@ void solve_length_and_collision_constraints(OffsetIndices<int> points_by_curve,
|
||||
Span<float3> start_positions,
|
||||
const Mesh &surface,
|
||||
const bke::CurvesSurfaceTransforms &transforms,
|
||||
MutableSpan<float3> positions);
|
||||
MutableSpan<float3> positions,
|
||||
const float surface_collision_distance);
|
||||
|
||||
} // namespace blender::geometry::curve_constraints
|
||||
|
||||
@@ -67,13 +67,13 @@ void solve_length_and_collision_constraints(const OffsetIndices<int> points_by_c
|
||||
const Span<float3> start_positions_cu,
|
||||
const Mesh &surface,
|
||||
const bke::CurvesSurfaceTransforms &transforms,
|
||||
MutableSpan<float3> positions_cu)
|
||||
MutableSpan<float3> positions_cu,
|
||||
const float surface_collision_distance)
|
||||
{
|
||||
solve_length_constraints(points_by_curve, curve_selection, segment_lengths_cu, positions_cu);
|
||||
|
||||
blender::bke::BVHTreeFromMesh surface_bvh = surface.bvh_corner_tris();
|
||||
|
||||
const float radius = 0.005f;
|
||||
const int max_collisions = 5;
|
||||
|
||||
curve_selection.foreach_segment(GrainSize(64), [&](const IndexMaskSegment segment) {
|
||||
@@ -108,11 +108,11 @@ void solve_length_and_collision_constraints(const OffsetIndices<int> points_by_c
|
||||
max_ray_length_su);
|
||||
BVHTreeRayHit hit;
|
||||
hit.index = -1;
|
||||
hit.dist = max_ray_length_su + radius;
|
||||
hit.dist = max_ray_length_su + surface_collision_distance;
|
||||
BLI_bvhtree_ray_cast(surface_bvh.tree,
|
||||
start_pos_su,
|
||||
ray_direction_su,
|
||||
radius,
|
||||
surface_collision_distance,
|
||||
&hit,
|
||||
surface_bvh.raycast_callback,
|
||||
&surface_bvh);
|
||||
@@ -135,7 +135,7 @@ void solve_length_and_collision_constraints(const OffsetIndices<int> points_by_c
|
||||
math::transform_direction(transforms.surface_to_curves_normal, hit_normal_su));
|
||||
|
||||
/* Slide on a plane that is slightly above the surface. */
|
||||
const float3 plane_pos_cu = hit_pos_cu + hit_normal_cu * radius;
|
||||
const float3 plane_pos_cu = hit_pos_cu + hit_normal_cu * surface_collision_distance;
|
||||
const float3 plane_normal_cu = hit_normal_cu;
|
||||
|
||||
/* Decompose the current segment into the part normal and tangent to the collision
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define _DNA_DEFAULT_Curves \
|
||||
{ \
|
||||
.flag = 0, \
|
||||
.surface_collision_distance = 0.005f, \
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -204,6 +204,10 @@ typedef struct Curves {
|
||||
*/
|
||||
char *surface_uv_map;
|
||||
|
||||
/* Distance to keep the curves away from the surface. */
|
||||
float surface_collision_distance;
|
||||
char _pad2[4];
|
||||
|
||||
/* Draw cache to store data used for viewport drawing. */
|
||||
void *batch_cache;
|
||||
} Curves;
|
||||
|
||||
@@ -552,6 +552,14 @@ static void rna_def_curves(BlenderRNA *brna)
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
|
||||
|
||||
prop = RNA_def_property(srna, "surface_collision_distance", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "surface_collision_distance");
|
||||
RNA_def_property_range(prop, FLT_EPSILON, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 10.0f, 0.001, 3);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Collision distance", "Distance to keep the curves away from the surface");
|
||||
RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
|
||||
|
||||
/* attributes */
|
||||
rna_def_attributes_common(srna, AttributeOwnerType::Curves);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user