[Bf-blender-cvs] [ac45540a348] master: Curves: add brush to add curves on surface
Jacques Lucke
noreply at git.blender.org
Wed Mar 2 17:20:53 CET 2022
Commit: ac45540a348ec8662e4e27002c64176c402fe549
Author: Jacques Lucke
Date: Wed Mar 2 17:15:44 2022 +0100
Branches: master
https://developer.blender.org/rBac45540a348ec8662e4e27002c64176c402fe549
Curves: add brush to add curves on surface
This adds a prototype for the first brush that can add new curves by
painting on a surface. Note that this can only be used when the curves
object has a surface object set in the properties panel.
The brush can take minimum distance into account. This allows
distributing curves with a somewhat consistent density.
Differential Revision: https://developer.blender.org/D14207
===================================================================
M release/scripts/startup/bl_ui/space_view3d.py
M source/blender/blenlib/BLI_hash.hh
M source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
M source/blender/makesdna/DNA_brush_enums.h
M source/blender/makesdna/DNA_scene_types.h
M source/blender/makesrna/intern/rna_brush.c
M source/blender/makesrna/intern/rna_sculpt_paint.c
===================================================================
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index cd0306d31fd..d6aea8e2d89 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -473,7 +473,8 @@ class _draw_tool_settings_context_mode:
if (tool is None) or (not tool.has_datablock):
return False
- paint = context.tool_settings.curves_sculpt
+ tool_settings = context.tool_settings
+ paint = tool_settings.curves_sculpt
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
@@ -500,6 +501,10 @@ class _draw_tool_settings_context_mode:
header=True
)
+ if brush.curves_sculpt_tool == "TEST3":
+ layout.prop(tool_settings.curves_sculpt, "distance")
+
+
class VIEW3D_HT_header(Header):
bl_space_type = 'VIEW_3D'
diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index 25841180fcf..25d7cd6aaf8 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -148,6 +148,13 @@ template<> struct DefaultHash<float> {
}
};
+template<> struct DefaultHash<double> {
+ uint64_t operator()(double value) const
+ {
+ return *reinterpret_cast<uint64_t *>(&value);
+ }
+};
+
template<> struct DefaultHash<bool> {
uint64_t operator()(bool value) const
{
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 936226a03ed..12c03804981 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -2,9 +2,14 @@
#include "BLI_utildefines.h"
+#include "BKE_attribute_math.hh"
#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
#include "WM_api.h"
@@ -19,12 +24,18 @@
#include "DNA_brush_types.h"
#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_screen_types.h"
#include "RNA_access.h"
#include "BLI_index_mask_ops.hh"
+#include "BLI_kdtree.h"
#include "BLI_math_vector.hh"
+#include "BLI_rand.hh"
+
+#include "PIL_time.h"
#include "curves_sculpt_intern.h"
#include "paint_intern.h"
@@ -79,7 +90,7 @@ class DeleteOperation : public CurvesSculptStrokeOperation {
float2 last_mouse_position_;
public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
{
Scene &scene = *CTX_data_scene(C);
Object &object = *CTX_data_active_object(C);
@@ -146,7 +157,7 @@ class MoveOperation : public CurvesSculptStrokeOperation {
float2 last_mouse_position_;
public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
{
Scene &scene = *CTX_data_scene(C);
Object &object = *CTX_data_active_object(C);
@@ -201,6 +212,438 @@ class MoveOperation : public CurvesSculptStrokeOperation {
}
};
+class AddOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Contains the root points of the curves that existed before this operation started. */
+ KDTree_3d *old_kdtree_ = nullptr;
+ /** Number of points in the kdtree above. */
+ int old_kdtree_size_ = 0;
+
+ /**
+ * Indicates that the corresponding curve has already been created and can't be changed by this
+ * operation anymore.
+ */
+ static constexpr int ExistsAlreadyIndex = INT32_MAX;
+
+ struct NewPointsData {
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+ Vector<float3> positions;
+ Vector<float3> normals;
+ };
+
+ public:
+ ~AddOperation()
+ {
+ if (old_kdtree_ != nullptr) {
+ BLI_kdtree_3d_free(old_kdtree_);
+ }
+ }
+
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
+ {
+ Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
+ Scene &scene = *CTX_data_scene(C);
+ Object &object = *CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ Curves &curves_id = *static_cast<Curves *>(object.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+
+ if (curves_id.surface == nullptr || curves_id.surface->type != OB_MESH) {
+ return;
+ }
+
+ const Object &surface_ob = *curves_id.surface;
+ const Mesh &surface = *static_cast<const Mesh *>(surface_ob.data);
+ const float4x4 surface_ob_mat = surface_ob.obmat;
+ const float4x4 surface_ob_imat = surface_ob_mat.inverted();
+
+ ToolSettings &tool_settings = *scene.toolsettings;
+ CurvesSculpt &curves_sculpt = *tool_settings.curves_sculpt;
+ Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
+ const float brush_radius_screen = BKE_brush_size_get(&scene, &brush);
+ const float strength = BKE_brush_alpha_get(&scene, &brush);
+ const float minimum_distance = curves_sculpt.distance;
+
+ /* This is the main ray that is used to determine the brush position in 3D space. */
+ float3 ray_start, ray_end;
+ ED_view3d_win_to_segment_clipped(
+ &depsgraph, region, v3d, stroke_extension.mouse_position, ray_start, ray_end, true);
+ ray_start = surface_ob_imat * ray_start;
+ ray_end = surface_ob_imat * ray_end;
+ const float3 ray_direction = math::normalize(ray_end - ray_start);
+
+ /* This ray is used to determine the brush radius in 3d space. */
+ float3 offset_ray_start, offset_ray_end;
+ ED_view3d_win_to_segment_clipped(&depsgraph,
+ region,
+ v3d,
+ stroke_extension.mouse_position +
+ float2(0, brush_radius_screen),
+ offset_ray_start,
+ offset_ray_end,
+ true);
+ offset_ray_start = surface_ob_imat * offset_ray_start;
+ offset_ray_end = surface_ob_imat * offset_ray_end;
+
+ float4x4 ob_imat;
+ invert_m4_m4(ob_imat.values, object.obmat);
+
+ const float4x4 transform = ob_imat * surface_ob_mat;
+
+ BVHTreeFromMesh bvhtree;
+ BKE_bvhtree_from_mesh_get(&bvhtree, &surface, BVHTREE_FROM_LOOPTRI, 2);
+
+ /* Do a raycast against the surface object to find the brush position. */
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(bvhtree.tree,
+ ray_start,
+ ray_direction,
+ 0.0f,
+ &ray_hit,
+ bvhtree.raycast_callback,
+ &bvhtree);
+
+ if (ray_hit.index == -1) {
+ /* The ray did not hit the surface. */
+ free_bvhtree_from_mesh(&bvhtree);
+ return;
+ }
+ /* Brush position in the space of the surface object. */
+ const float3 brush_pos_3d_surface = ray_hit.co;
+ const float brush_radius_3d_surface = dist_to_line_v3(
+ brush_pos_3d_surface, offset_ray_start, offset_ray_end);
+
+ /* Brush position in the space of the curves object. */
+ const float3 brush_pos_3d_curves = transform * brush_pos_3d_surface;
+ const float brush_radius_3d_curves = dist_to_line_v3(
+ brush_pos_3d_curves, transform * offset_ray_start, transform * offset_ray_end);
+
+ Vector<int> looptri_indices = this->find_looptri_indices_to_consider(
+ bvhtree, brush_pos_3d_surface, brush_radius_3d_surface);
+
+ free_bvhtree_from_mesh(&bvhtree);
+
+ if (old_kdtree_ == nullptr && minimum_distance > 0.0f) {
+ old_kdtree_ = this->kdtree_from_curve_roots_and_positions(curves, curves.curves_range(), {});
+ old_kdtree_size_ = curves.curves_size();
+ }
+
+ float density;
+ if (minimum_distance > 0.0f) {
+ /* Estimate the sampling density based on the target minimum distance. */
+ density = strength * pow2f(1.0f / minimum_distance);
+ }
+ else {
+ /* Sample a somewhat constant amount of points based on the strength. */
+ const float brush_circle_area_3d = M_PI * pow2f(brush_radius_3d_curves);
+ density = strength * 100.0f / brush_circle_area_3d;
+ }
+
+ NewPointsData new_points = this->sample_new_points(density,
+ minimum_distance,
+ brush_radius_3d_curves,
+ brush_pos_3d_curves,
+ looptri_indices,
+ transform,
+ surface);
+ if (minimum_distance > 0.0f) {
+ this->eliminate_too_close_points(new_points, curves, minimum_distance);
+ }
+ this->insert_new_curves(new_points, curves);
+
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(region);
+ }
+
+ private:
+ Vector<int> find_looptri_indices_to_consider(BVHTreeFromMesh &bvhtree,
+ const float3 &brush_pos,
+ const float brush_radius_3d)
+ {
+ Vector<int> looptri_indices;
+
+ struct RangeQueryUserData {
+ Vector<int> &indices;
+ } range_query_user_data = {looptri_indices};
+
+ BLI_bvhtree_range_query(
+ bvhtree.tree,
+ brush_pos,
+ brush_radius_3d,
+ [](void *userdata, int index, const float co[3], float dist_sq) {
+ UNUSED_VARS(co, dist_sq);
+ RangeQueryUserData &data = *static_cast<RangeQueryUserData *>(userdata);
+ data.indices.append(index);
+ },
+ &range_query_user_data);
+
+ return looptri_indices;
+ }
+
+ KDTree_3d *kdtree_from_curve_roots_and_positions(const CurvesGeometry &cu
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list