48 #include "RNA_prototypes.h"
103 if (check_editable) {
140 namespace convert_to_particle_system {
147 if (possible_mface_indices.
size() == 1) {
148 return possible_mface_indices.
first();
152 float best_distance_sq = FLT_MAX;
153 for (
const int possible_mface_i : possible_mface_indices) {
163 if (distance_sq < best_distance_sq) {
164 best_distance_sq = distance_sq;
165 mface_i = possible_mface_i;
169 if (possible_mface.
v4) {
177 if (distance_sq < best_distance_sq) {
178 best_distance_sq = distance_sq;
179 mface_i = possible_mface_i;
195 float mface_verts_su[4][3];
208 mface_weights[3] = 0.0f;
210 return mface_weights;
216 bool *r_could_not_convert_some_curves)
223 if (curves_id.
surface ==
nullptr) {
230 Mesh &surface_me = *
static_cast<Mesh *
>(surface_ob.
data);
240 if (looptris.is_empty()) {
241 *r_could_not_convert_some_curves =
true;
244 const int hair_num =
curves.curves_num();
252 particle_system = psys;
256 if (particle_system ==
nullptr) {
259 particle_system = psmd.
psys;
282 for (
const int mface_i : mface_to_poly_map.index_range()) {
283 const int poly_i = mface_to_poly_map[mface_i];
284 poly_to_mface_map[poly_i].append(mface_i);
290 for (
const int new_hair_i :
IndexRange(hair_num)) {
291 const int curve_i = new_hair_i;
294 const float3 &root_pos_cu = positions_cu[points.
first()];
295 const float3 root_pos_su = transforms.curves_to_surface * root_pos_cu;
303 const int looptri_i = nearest.
index;
304 const MLoopTri &looptri = looptris[looptri_i];
305 const int poly_i = looptri.
poly;
308 surface_me, poly_to_mface_map[poly_i], root_pos_su);
309 const MFace &mface = surface_me.
mface[mface_i];
312 surface_me, mface, root_pos_su);
315 const int num_keys = points.
size();
319 particle.
hair = hair_keys.data();
320 particle.
totkey = hair_keys.size();
322 particle.
num = mface_i;
333 for (
const int key_i : hair_keys.index_range()) {
334 const float3 &key_pos_cu = positions_cu[points[key_i]];
335 const float3 key_pos_su = transforms.curves_to_surface * key_pos_cu;
336 const float3 key_pos_ha = surface_to_hair_mat * key_pos_su;
338 HairKey &key = hair_keys[key_i];
340 key.
time = 100.0f * key_i / (
float)(hair_keys.size() - 1);
344 particle_system->
particles = particles.data();
345 particle_system->
totpart = particles.size();
358 bool could_not_convert_some_curves =
false;
364 if (curves_ob != &active_object) {
370 if (could_not_convert_some_curves) {
373 "Some curves could not be converted because they were not attached to the surface");
385 ot->
name =
"Convert Curves to Particle System";
386 ot->
idname =
"CURVES_OT_convert_to_particle_system";
387 ot->
description =
"Add a new or update an existing hair particle system on the surface object";
395 namespace convert_from_particle_system {
413 if (transfer_parents) {
414 for (
const int parent_i : parents_cache.index_range()) {
415 const int segments = parents_cache[parent_i]->segments;
419 parents_to_transfer.
append(parent_i);
420 curve_offsets.
append(points_num);
421 points_num += segments + 1;
424 for (
const int child_i : children_cache.index_range()) {
425 const int segments = children_cache[child_i]->segments;
429 children_to_transfer.
append(child_i);
430 curve_offsets.
append(points_num);
431 points_num += segments + 1;
433 const int curves_num = parents_to_transfer.
size() + children_to_transfer.
size();
434 curve_offsets.
append(points_num);
437 curves.offsets_for_write().copy_from(curve_offsets);
439 const float4x4 object_to_world_mat =
object.obmat;
440 const float4x4 world_to_object_mat = object_to_world_mat.inverted();
444 const auto copy_hair_to_curves = [&](
const Span<ParticleCacheKey *> hair_cache,
445 const Span<int> indices_to_transfer,
446 const int curve_index_offset) {
448 for (const int i : range) {
449 const int hair_i = indices_to_transfer[i];
450 const int curve_i = i + curve_index_offset;
451 const IndexRange points = curves.points_for_curve(curve_i);
452 const Span<ParticleCacheKey> keys{hair_cache[hair_i], points.size()};
453 for (const int key_i : keys.index_range()) {
454 const float3 key_pos_wo = keys[key_i].co;
455 positions[points[key_i]] = world_to_object_mat * key_pos_wo;
461 if (transfer_parents) {
462 copy_hair_to_curves(parents_cache, parents_to_transfer, 0);
464 copy_hair_to_curves(children_cache, children_to_transfer, parents_to_transfer.
size());
466 curves.update_curve_types();
467 curves.tag_topology_changed();
479 if (psys_orig ==
nullptr) {
482 if (psys_orig ==
nullptr) {
495 psys_eval = psmd->
psys;
518 ot->
name =
"Convert Particle System to Curves";
519 ot->
idname =
"CURVES_OT_convert_from_particle_system";
520 ot->
description =
"Add a new curves object based on the current state of the particle system";
528 namespace snap_curves_to_surface {
544 Mesh &surface_mesh = *
static_cast<Mesh *
>(surface_ob.
data);
549 surface_uv_map = surface_attributes
562 switch (attach_mode) {
563 case AttachMode::Nearest: {
569 for (const int curve_i : curves_range) {
570 const IndexRange points = curves.points_for_curve(curve_i);
571 const int first_point_i = points.first();
572 const float3 old_first_point_pos_cu = positions_cu[first_point_i];
573 const float3 old_first_point_pos_su = transforms.curves_to_surface *
574 old_first_point_pos_cu;
576 BVHTreeNearest nearest;
578 nearest.dist_sq = FLT_MAX;
579 BLI_bvhtree_find_nearest(surface_bvh.tree,
580 old_first_point_pos_su,
582 surface_bvh.nearest_callback,
584 const int looptri_index = nearest.index;
585 if (looptri_index == -1) {
589 const float3 new_first_point_pos_su = nearest.co;
590 const float3 new_first_point_pos_cu = transforms.surface_to_curves *
591 new_first_point_pos_su;
592 const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
594 for (float3 &pos_cu : positions_cu.slice(points)) {
595 pos_cu += pos_diff_cu;
598 if (!surface_uv_map.is_empty()) {
599 const MLoopTri &looptri = surface_looptris[looptri_index];
600 const int corner0 = looptri.tri[0];
601 const int corner1 = looptri.tri[1];
602 const int corner2 = looptri.tri[2];
603 const float2 &uv0 = surface_uv_map[corner0];
604 const float2 &uv1 = surface_uv_map[corner1];
605 const float2 &uv2 = surface_uv_map[corner2];
606 const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
607 const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
608 const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
610 interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
611 const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
612 surface_uv_coords[curve_i] = uv;
618 case AttachMode::Deform: {
620 *r_missing_uvs =
true;
624 ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
627 for (const int curve_i : curves_range) {
628 const IndexRange points = curves.points_for_curve(curve_i);
629 const int first_point_i = points.first();
630 const float3 old_first_point_pos_cu = positions_cu[first_point_i];
632 const float2 uv = surface_uv_coords[curve_i];
633 ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
634 if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
635 *r_invalid_uvs = true;
639 const MLoopTri &looptri = *lookup_result.looptri;
640 const float3 &bary_coords = lookup_result.bary_weights;
642 const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
643 const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
644 const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
646 float3 new_first_point_pos_su;
647 interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
648 const float3 new_first_point_pos_cu = transforms.surface_to_curves *
649 new_first_point_pos_su;
651 const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
652 for (float3 &pos_cu : positions_cu.slice(points)) {
653 pos_cu += pos_diff_cu;
668 bool found_invalid_uvs =
false;
669 bool found_missing_uvs =
false;
675 Curves &curves_id = *
static_cast<Curves *
>(curves_ob->data);
676 if (curves_id.
surface ==
nullptr) {
683 *curves_ob, *curves_id.
surface, attach_mode, &found_invalid_uvs, &found_missing_uvs);
687 if (found_missing_uvs) {
690 "Curves do not have attachment information that can be used for deformation");
692 if (found_invalid_uvs) {
706 using namespace snap_curves_to_surface;
708 ot->
name =
"Snap Curves to Surface";
709 ot->
idname =
"CURVES_OT_snap_curves_to_surface";
710 ot->
description =
"Move curves so that the first point is exactly on the surface mesh";
718 {
static_cast<int>(AttachMode::Nearest),
722 "Find the closest point on the surface for the root point of every curve and move the root "
724 {
static_cast<int>(AttachMode::Deform),
728 "Re-attach curves to a deformed surface using the existing attachment information. This "
729 "only works when the topology of the surface mesh has not changed"},
730 {0,
nullptr, 0,
nullptr,
nullptr},
736 static_cast<int>(AttachMode::Nearest),
738 "How to find the point on the surface to attach to");
741 namespace set_selection_domain {
753 curves_id->selection_domain = domain;
758 if (
curves.points_num() == 0) {
766 attributes.
remove(
".selection_point_float");
772 attributes.
remove(
".selection_curve_float");
792 ot->
name =
"Set Select Mode";
794 ot->
description =
"Change the mode used for selection masking in curves sculpt mode";
806 namespace disable_selection {
828 ot->
name =
"Disable Selection";
830 ot->
description =
"Disable the drawing of influence of selection in sculpt mode";
840 bool contains_nonzero =
false;
842 for (
const int i :
data.index_range()) {
843 if (array[i] != 0.0f) {
844 contains_nonzero = true;
849 return contains_nonzero;
872 for (
const Curves *curves_id : curves_ids) {
880 namespace select_all {
885 for (const int i : range) {
886 selection[i] = 1.0f - selection[i];
901 for (
Curves *curves_id : unique_curves) {
906 attributes.
remove(
".selection_point_float");
907 attributes.
remove(
".selection_curve_float");
911 curves.selection_point_float_for_write() :
912 curves.selection_curve_float_for_write();
914 selection.
fill(0.0f);
934 ot->
name =
"(De)select All";
946 namespace surface_set {
951 if (
object ==
nullptr) {
967 Mesh &new_surface_mesh = *
static_cast<Mesh *
>(new_surface_ob.
data);
975 Object &curves_ob = *selected_ob;
979 if (new_uv_map_name !=
nullptr) {
988 snap_curves_to_surface::AttachMode::Nearest,
995 curves_id.
surface = &new_surface_ob;
1018 ot->
name =
"Set Curves Surface Object";
1021 "Use the active object as surface for selected curves objects and set it as the parent";
typedef float(TangentPoint)[2]
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
struct Scene * CTX_data_scene(const bContext *C)
#define CTX_DATA_BEGIN(C, Type, instance, member)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
struct ViewLayer * CTX_data_view_layer(const bContext *C)
struct Object * CTX_data_active_object(const bContext *C)
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
struct Main * CTX_data_main(const bContext *C)
Low-level operations for curves.
const char * CustomData_get_active_layer_name(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id)
void BKE_mesh_tessface_calc(struct Mesh *mesh)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_add(struct Main *bmain, struct ViewLayer *view_layer, int type, const char *name) ATTR_NONNULL(1
void BKE_object_apply_mat4(struct Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
void psys_free_particles(struct ParticleSystem *psys)
struct ParticleSystem * psys_get_current(struct Object *ob)
void psys_changed_type(struct Object *ob, struct ParticleSystem *psys)
struct ModifierData * object_add_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob, const char *name)
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_unreachable()
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
#define LISTBASE_FOREACH(type, var, list)
void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define BLI_SCOPED_DEFER(function_to_defer)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
struct Depsgraph Depsgraph
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_COPY_ON_WRITE
struct CurvesGeometry CurvesGeometry
@ CV_SCULPT_SELECTION_ENABLED
@ eModifierType_ParticleSystem
Object is a sort of wrapper for general info.
@ OB_MODIFIER_FLAG_ADD_REST_POSITION
struct Object * ED_object_active_context(const struct bContext *C)
bool ED_object_parent_set(struct ReportList *reports, const struct bContext *C, struct Scene *scene, struct Object *const ob, struct Object *const par, int partype, bool xmirror, bool keep_transform, const int vert_par[3])
bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
constexpr int64_t first() const
constexpr int64_t size() const
constexpr void fill(const T &value)
constexpr IndexRange index_range() const
constexpr const T & first() const
constexpr int64_t size() const
constexpr bool is_empty() const
void materialize(MutableSpan< T > r_span) const
void add_new(const Key &key)
void append(const T &value)
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
bool remove(const AttributeIDRef &attribute_id)
void ED_operatortypes_curves()
const Depsgraph * depsgraph
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
AttributeAccessor mesh_attributes(const Mesh &mesh)
static int curves_convert_from_particle_system_exec(bContext *C, wmOperator *UNUSED(op))
static bke::CurvesGeometry particles_to_curves(Object &object, ParticleSystem &psys)
static bool curves_convert_from_particle_system_poll(bContext *C)
static int curves_convert_to_particle_system_exec(bContext *C, wmOperator *op)
static int find_mface_for_root_position(const Mesh &mesh, const Span< int > possible_mface_indices, const float3 &root_pos)
static float4 compute_mface_weights_for_position(const Mesh &mesh, const MFace &mface, const float3 &position)
static void try_convert_single_object(Object &curves_ob, Main &bmain, Scene &scene, bool *r_could_not_convert_some_curves)
static int curves_disable_selection_exec(bContext *C, wmOperator *UNUSED(op))
static void invert_selection(MutableSpan< float > selection)
static int select_all_exec(bContext *C, wmOperator *op)
static int curves_set_selection_domain_exec(bContext *C, wmOperator *op)
static void snap_curves_to_surface_exec_object(Object &curves_ob, const Object &surface_ob, const AttachMode attach_mode, bool *r_invalid_uvs, bool *r_missing_uvs)
static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
static int surface_set_exec(bContext *C, wmOperator *op)
static bool surface_set_poll(bContext *C)
static void CURVES_OT_surface_set(wmOperatorType *ot)
static void CURVES_OT_convert_from_particle_system(wmOperatorType *ot)
static bool object_has_editable_curves(const Main &bmain, const Object &object)
static void CURVES_OT_convert_to_particle_system(wmOperatorType *ot)
static void SCULPT_CURVES_OT_select_all(wmOperatorType *ot)
bool editable_curves_poll(bContext *C)
static bool any_point_selected(const Span< Curves * > curves_ids)
bool has_anything_selected(const Curves &curves_id)
VectorSet< Curves * > get_unique_editable_curves(const bContext &C)
static bool varray_contains_nonzero(const VArray< float > &data)
static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot)
void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
bool curves_with_surface_poll(bContext *C)
static void CURVES_OT_disable_selection(wmOperatorType *ot)
static bool curves_poll_impl(bContext *C, const bool check_editable, const bool check_surface)
bool curves_poll(bContext *C)
static void CURVES_OT_set_selection_domain(wmOperatorType *ot)
bool editable_curves_with_surface_poll(bContext *C)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)
MutableSpan< float3 > positions
int RNA_enum_get(PointerRNA *ptr, const char *name)
const EnumPropertyItem rna_enum_attribute_curves_domain_items[]
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
BVHTree_NearestPointCallback nearest_callback
struct ParticleSystem * psys
struct ParticleCacheKey ** pathcache
AttributeReader< T > typed() const
float4x4 inverted() const
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
struct ReportList * reports
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))