Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/curves/intern/curves_ops.cc
| Show First 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | interp_weights_tri_v3(mface_weights, | ||||
| mesh.mvert[mface.v2].co, | mesh.mvert[mface.v2].co, | ||||
| mesh.mvert[mface.v3].co, | mesh.mvert[mface.v3].co, | ||||
| position); | position); | ||||
| mface_weights[3] = 0.0f; | mface_weights[3] = 0.0f; | ||||
| } | } | ||||
| return mface_weights; | return mface_weights; | ||||
| } | } | ||||
| static int curves_convert_to_particle_system_exec(bContext *C, wmOperator *UNUSED(op)) | static void try_convert_single_object(Object &curves_ob, | ||||
| Main &bmain, | |||||
| Scene &scene, | |||||
| bool *r_could_not_convert_some_curves) | |||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | if (curves_ob.type != OB_CURVES) { | ||||
| Scene *scene = CTX_data_scene(C); | return; | ||||
| CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) { | |||||
| if (curves_ob->type != OB_CURVES) { | |||||
| continue; | |||||
| } | } | ||||
| Curves &curves_id = *static_cast<Curves *>(curves_ob->data); | Curves &curves_id = *static_cast<Curves *>(curves_ob.data); | ||||
| CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); | CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); | ||||
| if (curves_id.surface == nullptr) { | if (curves_id.surface == nullptr) { | ||||
| continue; | return; | ||||
| } | } | ||||
| Object &surface_ob = *curves_id.surface; | Object &surface_ob = *curves_id.surface; | ||||
| if (surface_ob.type != OB_MESH) { | if (surface_ob.type != OB_MESH) { | ||||
| continue; | return; | ||||
| } | } | ||||
| Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data); | Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data); | ||||
| const Span<float3> positions_cu = curves.positions(); | const Span<float3> positions_cu = curves.positions(); | ||||
| const VArray<int> looptri_indices = curves.surface_triangle_indices(); | const VArray<int> looptri_indices = curves.surface_triangle_indices(); | ||||
| const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&surface_me), | const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&surface_me), | ||||
| BKE_mesh_runtime_looptri_len(&surface_me)}; | BKE_mesh_runtime_looptri_len(&surface_me)}; | ||||
| /* Find indices of curves that can be transferred to the old hair system. */ | /* Find indices of curves that can be transferred to the old hair system. */ | ||||
| Vector<int> curves_indices_to_transfer; | Vector<int> curves_indices_to_transfer; | ||||
| for (const int curve_i : curves.curves_range()) { | for (const int curve_i : curves.curves_range()) { | ||||
| const int looptri_i = looptri_indices[curve_i]; | const int looptri_i = looptri_indices[curve_i]; | ||||
| if (looptri_i >= 0 && looptri_i < looptris.size()) { | if (looptri_i >= 0 && looptri_i < looptris.size()) { | ||||
| curves_indices_to_transfer.append(curve_i); | curves_indices_to_transfer.append(curve_i); | ||||
| } | } | ||||
| else { | |||||
| *r_could_not_convert_some_curves = true; | |||||
| } | |||||
| } | } | ||||
| const int hairs_num = curves_indices_to_transfer.size(); | const int hairs_num = curves_indices_to_transfer.size(); | ||||
| if (hairs_num == 0) { | if (hairs_num == 0) { | ||||
| continue; | return; | ||||
| } | } | ||||
| ParticleSystem *particle_system = nullptr; | ParticleSystem *particle_system = nullptr; | ||||
| LISTBASE_FOREACH (ParticleSystem *, psys, &surface_ob.particlesystem) { | LISTBASE_FOREACH (ParticleSystem *, psys, &surface_ob.particlesystem) { | ||||
| if (STREQ(psys->name, curves_ob->id.name + 2)) { | if (STREQ(psys->name, curves_ob.id.name + 2)) { | ||||
| particle_system = psys; | particle_system = psys; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (particle_system == nullptr) { | if (particle_system == nullptr) { | ||||
| ParticleSystemModifierData &psmd = *reinterpret_cast<ParticleSystemModifierData *>( | ParticleSystemModifierData &psmd = *reinterpret_cast<ParticleSystemModifierData *>( | ||||
| object_add_particle_system(bmain, scene, &surface_ob, curves_ob->id.name + 2)); | object_add_particle_system(&bmain, &scene, &surface_ob, curves_ob.id.name + 2)); | ||||
| particle_system = psmd.psys; | particle_system = psmd.psys; | ||||
| particle_system->part->draw_step = 3; | |||||
| } | } | ||||
| ParticleSettings &settings = *particle_system->part; | ParticleSettings &settings = *particle_system->part; | ||||
| psys_free_particles(particle_system); | psys_free_particles(particle_system); | ||||
| settings.type = PART_HAIR; | settings.type = PART_HAIR; | ||||
| settings.totpart = 0; | settings.totpart = 0; | ||||
| psys_changed_type(&surface_ob, particle_system); | psys_changed_type(&surface_ob, particle_system); | ||||
| MutableSpan<ParticleData> particles{ | MutableSpan<ParticleData> particles{ | ||||
| static_cast<ParticleData *>(MEM_calloc_arrayN(hairs_num, sizeof(ParticleData), __func__)), | static_cast<ParticleData *>(MEM_calloc_arrayN(hairs_num, sizeof(ParticleData), __func__)), | ||||
| hairs_num}; | hairs_num}; | ||||
| /* The old hair system still uses #MFace, so make sure those are available on the mesh. */ | /* The old hair system still uses #MFace, so make sure those are available on the mesh. */ | ||||
| BKE_mesh_tessface_calc(&surface_me); | BKE_mesh_tessface_calc(&surface_me); | ||||
| /* Prepare utility data structure to map hair roots to mfaces. */ | /* Prepare utility data structure to map hair roots to mfaces. */ | ||||
| const Span<int> mface_to_poly_map{ | const Span<int> mface_to_poly_map{ | ||||
| static_cast<int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)), | static_cast<int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)), | ||||
| surface_me.totface}; | surface_me.totface}; | ||||
| Array<Vector<int>> poly_to_mface_map(surface_me.totpoly); | Array<Vector<int>> poly_to_mface_map(surface_me.totpoly); | ||||
| for (const int mface_i : mface_to_poly_map.index_range()) { | for (const int mface_i : mface_to_poly_map.index_range()) { | ||||
| const int poly_i = mface_to_poly_map[mface_i]; | const int poly_i = mface_to_poly_map[mface_i]; | ||||
| poly_to_mface_map[poly_i].append(mface_i); | poly_to_mface_map[poly_i].append(mface_i); | ||||
| } | } | ||||
| /* Prepare transformation matrices. */ | /* Prepare transformation matrices. */ | ||||
| const float4x4 curves_to_world_mat = curves_ob->obmat; | const float4x4 curves_to_world_mat = curves_ob.obmat; | ||||
| const float4x4 surface_to_world_mat = surface_ob.obmat; | const float4x4 surface_to_world_mat = surface_ob.obmat; | ||||
| const float4x4 world_to_surface_mat = surface_to_world_mat.inverted(); | const float4x4 world_to_surface_mat = surface_to_world_mat.inverted(); | ||||
| const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat; | const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat; | ||||
| for (const int new_hair_i : curves_indices_to_transfer.index_range()) { | for (const int new_hair_i : curves_indices_to_transfer.index_range()) { | ||||
| const int curve_i = curves_indices_to_transfer[new_hair_i]; | const int curve_i = curves_indices_to_transfer[new_hair_i]; | ||||
| const IndexRange points = curves.points_for_curve(curve_i); | const IndexRange points = curves.points_for_curve(curve_i); | ||||
| const int looptri_i = looptri_indices[curve_i]; | const int looptri_i = looptri_indices[curve_i]; | ||||
| const MLoopTri &looptri = looptris[looptri_i]; | const MLoopTri &looptri = looptris[looptri_i]; | ||||
| const int poly_i = looptri.poly; | const int poly_i = looptri.poly; | ||||
| const float3 &root_pos_cu = positions_cu[points.first()]; | const float3 &root_pos_cu = positions_cu[points.first()]; | ||||
| const float3 root_pos_su = curves_to_surface_mat * root_pos_cu; | const float3 root_pos_su = curves_to_surface_mat * root_pos_cu; | ||||
| const int mface_i = find_mface_for_root_position( | const int mface_i = find_mface_for_root_position( | ||||
| surface_me, poly_to_mface_map[poly_i], root_pos_su); | surface_me, poly_to_mface_map[poly_i], root_pos_su); | ||||
| const MFace &mface = surface_me.mface[mface_i]; | const MFace &mface = surface_me.mface[mface_i]; | ||||
| const float4 mface_weights = compute_mface_weights_for_position( | const float4 mface_weights = compute_mface_weights_for_position( | ||||
| surface_me, mface, root_pos_su); | surface_me, mface, root_pos_su); | ||||
| ParticleData &particle = particles[new_hair_i]; | ParticleData &particle = particles[new_hair_i]; | ||||
| const int num_keys = points.size(); | const int num_keys = points.size(); | ||||
| MutableSpan<HairKey> hair_keys{ | MutableSpan<HairKey> hair_keys{ | ||||
| static_cast<HairKey *>(MEM_calloc_arrayN(num_keys, sizeof(HairKey), __func__)), | static_cast<HairKey *>(MEM_calloc_arrayN(num_keys, sizeof(HairKey), __func__)), num_keys}; | ||||
| num_keys}; | |||||
| particle.hair = hair_keys.data(); | particle.hair = hair_keys.data(); | ||||
| particle.totkey = hair_keys.size(); | particle.totkey = hair_keys.size(); | ||||
| copy_v4_v4(particle.fuv, mface_weights); | copy_v4_v4(particle.fuv, mface_weights); | ||||
| particle.num = mface_i; | particle.num = mface_i; | ||||
| /* Not sure if there is a better way to initialize this. */ | /* Not sure if there is a better way to initialize this. */ | ||||
| particle.num_dmcache = DMCACHE_NOTFOUND; | particle.num_dmcache = DMCACHE_NOTFOUND; | ||||
| float4x4 hair_to_surface_mat; | float4x4 hair_to_surface_mat; | ||||
| psys_mat_hair_to_object( | psys_mat_hair_to_object( | ||||
| &surface_ob, &surface_me, PART_FROM_FACE, &particle, hair_to_surface_mat.values); | &surface_ob, &surface_me, PART_FROM_FACE, &particle, hair_to_surface_mat.values); | ||||
| /* In theory, #psys_mat_hair_to_object should handle this, but it doesn't right now. */ | /* In theory, #psys_mat_hair_to_object should handle this, but it doesn't right now. */ | ||||
| copy_v3_v3(hair_to_surface_mat.values[3], root_pos_su); | copy_v3_v3(hair_to_surface_mat.values[3], root_pos_su); | ||||
| const float4x4 surface_to_hair_mat = hair_to_surface_mat.inverted(); | const float4x4 surface_to_hair_mat = hair_to_surface_mat.inverted(); | ||||
| for (const int key_i : hair_keys.index_range()) { | for (const int key_i : hair_keys.index_range()) { | ||||
| const float3 &key_pos_cu = positions_cu[points[key_i]]; | const float3 &key_pos_cu = positions_cu[points[key_i]]; | ||||
| const float3 key_pos_su = curves_to_surface_mat * key_pos_cu; | const float3 key_pos_su = curves_to_surface_mat * key_pos_cu; | ||||
| const float3 key_pos_ha = surface_to_hair_mat * key_pos_su; | const float3 key_pos_ha = surface_to_hair_mat * key_pos_su; | ||||
| HairKey &key = hair_keys[key_i]; | HairKey &key = hair_keys[key_i]; | ||||
| copy_v3_v3(key.co, key_pos_ha); | copy_v3_v3(key.co, key_pos_ha); | ||||
| key.time = 100.0f * key_i / (float)(hair_keys.size() - 1); | key.time = 100.0f * key_i / (float)(hair_keys.size() - 1); | ||||
| } | } | ||||
| } | } | ||||
| particle_system->particles = particles.data(); | particle_system->particles = particles.data(); | ||||
| particle_system->totpart = particles.size(); | particle_system->totpart = particles.size(); | ||||
| particle_system->flag |= PSYS_EDITED; | particle_system->flag |= PSYS_EDITED; | ||||
| particle_system->recalc |= ID_RECALC_PSYS_RESET; | particle_system->recalc |= ID_RECALC_PSYS_RESET; | ||||
| DEG_id_tag_update(&surface_ob.id, ID_RECALC_GEOMETRY); | DEG_id_tag_update(&surface_ob.id, ID_RECALC_GEOMETRY); | ||||
| DEG_id_tag_update(&settings.id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(&settings.id, ID_RECALC_COPY_ON_WRITE); | ||||
| } | } | ||||
| static int curves_convert_to_particle_system_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| Main &bmain = *CTX_data_main(C); | |||||
| Scene &scene = *CTX_data_scene(C); | |||||
| bool could_not_convert_some_curves = false; | |||||
| Object &active_object = *CTX_data_active_object(C); | |||||
| try_convert_single_object(active_object, bmain, scene, &could_not_convert_some_curves); | |||||
| CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) { | |||||
| if (curves_ob != &active_object) { | |||||
| try_convert_single_object(*curves_ob, bmain, scene, &could_not_convert_some_curves); | |||||
| } | |||||
| } | |||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| if (could_not_convert_some_curves) { | |||||
| BKE_report(op->reports, | |||||
| RPT_INFO, | |||||
| "Some curves could not be converted because they were not attached to the surface"); | |||||
| } | |||||
| WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, nullptr); | WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, nullptr); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static bool curves_convert_to_particle_system_poll(bContext *C) | static bool curves_convert_to_particle_system_poll(bContext *C) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| ▲ Show 20 Lines • Show All 222 Lines • Show Last 20 Lines | |||||