Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_boolean_convert.cc
| Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
| /* All meshes 1 and up will be transformed into the local space of operand 0. | /* All meshes 1 and up will be transformed into the local space of operand 0. | ||||
| * Historical behavior of the modifier has been to flip the faces of any meshes | * Historical behavior of the modifier has been to flip the faces of any meshes | ||||
| * that would have a negative transform if you do that. */ | * that would have a negative transform if you do that. */ | ||||
| bool need_face_flip = r_info->has_negative_transform[mi] != r_info->has_negative_transform[0]; | bool need_face_flip = r_info->has_negative_transform[mi] != r_info->has_negative_transform[0]; | ||||
| Vector<Vert *> verts(me->totvert); | Vector<Vert *> verts(me->totvert); | ||||
| const Span<float3> vert_positions = me->vert_positions(); | const Span<float3> vert_positions = me->vert_positions(); | ||||
| const Span<MPoly> polys = me->polys(); | const Span<MPoly> polys = me->polys(); | ||||
| const Span<MLoop> loops = me->loops(); | const Span<int> corner_verts = me->corner_verts(); | ||||
| const Span<int> corner_edges = me->corner_edges(); | |||||
| /* Allocate verts | /* Allocate verts | ||||
| * Skip the matrix multiplication for each point when there is no transform for a mesh, | * Skip the matrix multiplication for each point when there is no transform for a mesh, | ||||
| * for example when the first mesh is already in the target space. (Note the logic | * for example when the first mesh is already in the target space. (Note the logic | ||||
| * directly above, which uses an identity matrix with a null input transform). */ | * directly above, which uses an identity matrix with a null input transform). */ | ||||
| if (obmats[mi] == nullptr) { | if (obmats[mi] == nullptr) { | ||||
| threading::parallel_for(vert_positions.index_range(), 2048, [&](IndexRange range) { | threading::parallel_for(vert_positions.index_range(), 2048, [&](IndexRange range) { | ||||
| for (int i : range) { | for (int i : range) { | ||||
| Show All 18 Lines | |||||
| r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(verts[i]); | r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(verts[i]); | ||||
| ++v; | ++v; | ||||
| } | } | ||||
| for (const MPoly &poly : polys) { | for (const MPoly &poly : polys) { | ||||
| int flen = poly.totloop; | int flen = poly.totloop; | ||||
| face_vert.resize(flen); | face_vert.resize(flen); | ||||
| face_edge_orig.resize(flen); | face_edge_orig.resize(flen); | ||||
| const MLoop *l = &loops[poly.loopstart]; | |||||
| for (int i = 0; i < flen; ++i) { | for (int i = 0; i < flen; ++i) { | ||||
| int mverti = r_info->mesh_vert_offset[mi] + l->v; | const int corner_i = poly.loopstart + i; | ||||
| int mverti = r_info->mesh_vert_offset[mi] + corner_verts[corner_i]; | |||||
| const Vert *fv = r_info->mesh_to_imesh_vert[mverti]; | const Vert *fv = r_info->mesh_to_imesh_vert[mverti]; | ||||
| if (need_face_flip) { | if (need_face_flip) { | ||||
| face_vert[flen - i - 1] = fv; | face_vert[flen - i - 1] = fv; | ||||
| int iedge = i < flen - 1 ? flen - i - 2 : flen - 1; | int iedge = i < flen - 1 ? flen - i - 2 : flen - 1; | ||||
| face_edge_orig[iedge] = e + l->e; | face_edge_orig[iedge] = e + corner_edges[corner_i]; | ||||
| } | } | ||||
| else { | else { | ||||
| face_vert[i] = fv; | face_vert[i] = fv; | ||||
| face_edge_orig[i] = e + l->e; | face_edge_orig[i] = e + corner_edges[corner_i]; | ||||
| } | } | ||||
| ++l; | |||||
| } | } | ||||
| r_info->mesh_to_imesh_face[f] = arena.add_face(face_vert, f, face_edge_orig); | r_info->mesh_to_imesh_face[f] = arena.add_face(face_vert, f, face_edge_orig); | ||||
| ++f; | ++f; | ||||
| } | } | ||||
| e += me->totedge; | e += me->totedge; | ||||
| } | } | ||||
| return IMesh(r_info->mesh_to_imesh_face); | return IMesh(r_info->mesh_to_imesh_face); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | |||||
| static int fill_orig_loops(const Face *f, | static int fill_orig_loops(const Face *f, | ||||
| const MPoly *orig_mp, | const MPoly *orig_mp, | ||||
| const Mesh *orig_me, | const Mesh *orig_me, | ||||
| int orig_me_index, | int orig_me_index, | ||||
| MeshesToIMeshInfo &mim, | MeshesToIMeshInfo &mim, | ||||
| MutableSpan<int> r_orig_loops) | MutableSpan<int> r_orig_loops) | ||||
| { | { | ||||
| r_orig_loops.fill(-1); | r_orig_loops.fill(-1); | ||||
| const Span<MLoop> orig_loops = orig_me->loops(); | const Span<int> orig_corner_verts = orig_me->corner_verts(); | ||||
| int orig_mplen = orig_mp->totloop; | int orig_mplen = orig_mp->totloop; | ||||
| if (f->size() != orig_mplen) { | if (f->size() != orig_mplen) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| BLI_assert(r_orig_loops.size() == orig_mplen); | BLI_assert(r_orig_loops.size() == orig_mplen); | ||||
| /* We'll look for the case where the first vertex in f has an original vertex | /* We'll look for the case where the first vertex in f has an original vertex | ||||
| * that is the same as one in orig_me (after correcting for offset in mim meshes). | * that is the same as one in orig_me (after correcting for offset in mim meshes). | ||||
| Show All 11 Lines | |||||
| } | } | ||||
| int orig_me_vert_offset = mim.mesh_vert_offset[orig_me_index]; | int orig_me_vert_offset = mim.mesh_vert_offset[orig_me_index]; | ||||
| int first_orig_v_in_orig_me = first_orig_v - orig_me_vert_offset; | int first_orig_v_in_orig_me = first_orig_v - orig_me_vert_offset; | ||||
| BLI_assert(0 <= first_orig_v_in_orig_me && first_orig_v_in_orig_me < orig_me->totvert); | BLI_assert(0 <= first_orig_v_in_orig_me && first_orig_v_in_orig_me < orig_me->totvert); | ||||
| /* Assume all vertices in an mpoly are unique. */ | /* Assume all vertices in an mpoly are unique. */ | ||||
| int offset = -1; | int offset = -1; | ||||
| for (int i = 0; i < orig_mplen; ++i) { | for (int i = 0; i < orig_mplen; ++i) { | ||||
| int loop_i = i + orig_mp->loopstart; | int loop_i = i + orig_mp->loopstart; | ||||
| if (orig_loops[loop_i].v == first_orig_v_in_orig_me) { | if (orig_corner_verts[loop_i] == first_orig_v_in_orig_me) { | ||||
| offset = i; | offset = i; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (offset == -1) { | if (offset == -1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int num_orig_loops_found = 0; | int num_orig_loops_found = 0; | ||||
| for (int mp_loop_index = 0; mp_loop_index < orig_mplen; ++mp_loop_index) { | for (int mp_loop_index = 0; mp_loop_index < orig_mplen; ++mp_loop_index) { | ||||
| int orig_mp_loop_index = (mp_loop_index + offset) % orig_mplen; | int orig_mp_loop_index = (mp_loop_index + offset) % orig_mplen; | ||||
| const MLoop *l = &orig_loops[orig_mp->loopstart + orig_mp_loop_index]; | const int vert_i = orig_corner_verts[orig_mp->loopstart + orig_mp_loop_index]; | ||||
| int fv_orig = f->vert[mp_loop_index]->orig; | int fv_orig = f->vert[mp_loop_index]->orig; | ||||
| if (fv_orig != NO_INDEX) { | if (fv_orig != NO_INDEX) { | ||||
| fv_orig -= orig_me_vert_offset; | fv_orig -= orig_me_vert_offset; | ||||
| if (fv_orig < 0 || fv_orig >= orig_me->totvert) { | if (fv_orig < 0 || fv_orig >= orig_me->totvert) { | ||||
| fv_orig = NO_INDEX; | fv_orig = NO_INDEX; | ||||
| } | } | ||||
| } | } | ||||
| if (l->v == fv_orig) { | if (vert_i == fv_orig) { | ||||
| const MLoop *lnext = | const int vert_next = | ||||
| &orig_loops[orig_mp->loopstart + ((orig_mp_loop_index + 1) % orig_mplen)]; | orig_corner_verts[orig_mp->loopstart + ((orig_mp_loop_index + 1) % orig_mplen)]; | ||||
| int fvnext_orig = f->vert[(mp_loop_index + 1) % orig_mplen]->orig; | int fvnext_orig = f->vert[(mp_loop_index + 1) % orig_mplen]->orig; | ||||
| if (fvnext_orig != NO_INDEX) { | if (fvnext_orig != NO_INDEX) { | ||||
| fvnext_orig -= orig_me_vert_offset; | fvnext_orig -= orig_me_vert_offset; | ||||
| if (fvnext_orig < 0 || fvnext_orig >= orig_me->totvert) { | if (fvnext_orig < 0 || fvnext_orig >= orig_me->totvert) { | ||||
| fvnext_orig = NO_INDEX; | fvnext_orig = NO_INDEX; | ||||
| } | } | ||||
| } | } | ||||
| if (lnext->v == fvnext_orig) { | if (vert_next == fvnext_orig) { | ||||
| r_orig_loops[mp_loop_index] = orig_mp->loopstart + orig_mp_loop_index; | r_orig_loops[mp_loop_index] = orig_mp->loopstart + orig_mp_loop_index; | ||||
| ++num_orig_loops_found; | ++num_orig_loops_found; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return num_orig_loops_found; | return num_orig_loops_found; | ||||
| } | } | ||||
| /* Fill `cos_2d` with the 2d coordinates found by projection MPoly `mp` along | /* Fill `cos_2d` with the 2d coordinates found by projection MPoly `mp` along | ||||
| * its normal. Also fill in r_axis_mat with the matrix that does that projection. | * its normal. Also fill in r_axis_mat with the matrix that does that projection. | ||||
| * But before projecting, also transform the 3d coordinate by multiplying by trans_mat. | * But before projecting, also transform the 3d coordinate by multiplying by trans_mat. | ||||
| * `cos_2d` should have room for `mp->totloop` entries. */ | * `cos_2d` should have room for `mp->totloop` entries. */ | ||||
| static void get_poly2d_cos(const Mesh *me, | static void get_poly2d_cos(const Mesh *me, | ||||
| const MPoly *mp, | const MPoly *mp, | ||||
| float (*cos_2d)[2], | float (*cos_2d)[2], | ||||
| const float4x4 &trans_mat, | const float4x4 &trans_mat, | ||||
| float r_axis_mat[3][3]) | float r_axis_mat[3][3]) | ||||
| { | { | ||||
| const Span<float3> positions = me->vert_positions(); | const Span<float3> positions = me->vert_positions(); | ||||
| const Span<MLoop> loops = me->loops(); | const Span<int> corner_verts = me->corner_verts(); | ||||
| const Span<MLoop> poly_loops = loops.slice(mp->loopstart, mp->totloop); | const Span<int> poly_verts = corner_verts.slice(mp->loopstart, mp->totloop); | ||||
| /* Project coordinates to 2d in cos_2d, using normal as projection axis. */ | /* Project coordinates to 2d in cos_2d, using normal as projection axis. */ | ||||
| float axis_dominant[3]; | float axis_dominant[3]; | ||||
| BKE_mesh_calc_poly_normal(mp, | BKE_mesh_calc_poly_normal(mp, | ||||
| &loops[mp->loopstart], | &corner_verts[mp->loopstart], | ||||
| reinterpret_cast<const float(*)[3]>(positions.data()), | reinterpret_cast<const float(*)[3]>(positions.data()), | ||||
| axis_dominant); | axis_dominant); | ||||
| axis_dominant_v3_to_m3(r_axis_mat, axis_dominant); | axis_dominant_v3_to_m3(r_axis_mat, axis_dominant); | ||||
| for (const int i : poly_loops.index_range()) { | for (const int i : poly_verts.index_range()) { | ||||
| float3 co = positions[poly_loops[i].v]; | float3 co = positions[poly_verts[i]]; | ||||
| co = trans_mat * co; | co = trans_mat * co; | ||||
| mul_v2_m3v3(cos_2d[i], r_axis_mat, co); | mul_v2_m3v3(cos_2d[i], r_axis_mat, co); | ||||
| } | } | ||||
| } | } | ||||
| /* For the loops of `mp`, see if the face is unchanged from `orig_mp`, and if so, | /* For the loops of `mp`, see if the face is unchanged from `orig_mp`, and if so, | ||||
| * copy the Loop attributes from corresponding loops to corresponding loops. | * copy the Loop attributes from corresponding loops to corresponding loops. | ||||
| * Otherwise, interpolate the Loop attributes in the face `orig_mp`. */ | * Otherwise, interpolate the Loop attributes in the face `orig_mp`. */ | ||||
| Show All 21 Lines | |||||
| * so they don't have to be allocated per-layer. */ | * so they don't have to be allocated per-layer. */ | ||||
| cos_2d = (float(*)[2])BLI_array_alloca(cos_2d, orig_mp->totloop); | cos_2d = (float(*)[2])BLI_array_alloca(cos_2d, orig_mp->totloop); | ||||
| weights = Array<float>(orig_mp->totloop); | weights = Array<float>(orig_mp->totloop); | ||||
| src_blocks_ofs = Array<const void *>(orig_mp->totloop); | src_blocks_ofs = Array<const void *>(orig_mp->totloop); | ||||
| get_poly2d_cos(orig_me, orig_mp, cos_2d, mim.to_target_transform[orig_me_index], axis_mat); | get_poly2d_cos(orig_me, orig_mp, cos_2d, mim.to_target_transform[orig_me_index], axis_mat); | ||||
| } | } | ||||
| CustomData *target_cd = &dest_mesh->ldata; | CustomData *target_cd = &dest_mesh->ldata; | ||||
| const Span<float3> dst_positions = dest_mesh->vert_positions(); | const Span<float3> dst_positions = dest_mesh->vert_positions(); | ||||
| const Span<MLoop> dst_loops = dest_mesh->loops(); | const Span<int> dst_corner_verts = dest_mesh->corner_verts(); | ||||
| for (int i = 0; i < mp->totloop; ++i) { | for (int i = 0; i < mp->totloop; ++i) { | ||||
| int loop_index = mp->loopstart + i; | int loop_index = mp->loopstart + i; | ||||
| int orig_loop_index = norig > 0 ? orig_loops[i] : -1; | int orig_loop_index = norig > 0 ? orig_loops[i] : -1; | ||||
| const CustomData *source_cd = &orig_me->ldata; | const CustomData *source_cd = &orig_me->ldata; | ||||
| if (orig_loop_index == -1) { | if (orig_loop_index == -1) { | ||||
| /* Will need interpolation weights for this loop's vertex's coordinates. | /* Will need interpolation weights for this loop's vertex's coordinates. | ||||
| * The coordinate needs to be projected into 2d, just like the interpolating polygon's | * The coordinate needs to be projected into 2d, just like the interpolating polygon's | ||||
| * coordinates were. The `dest_mesh` coordinates are already in object 0 local space. */ | * coordinates were. The `dest_mesh` coordinates are already in object 0 local space. */ | ||||
| float co[2]; | float co[2]; | ||||
| mul_v2_m3v3(co, axis_mat, dst_positions[dst_loops[loop_index].v]); | mul_v2_m3v3(co, axis_mat, dst_positions[dst_corner_verts[loop_index]]); | ||||
| interp_weights_poly_v2(weights.data(), cos_2d, orig_mp->totloop, co); | interp_weights_poly_v2(weights.data(), cos_2d, orig_mp->totloop, co); | ||||
| } | } | ||||
| for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) { | for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) { | ||||
| int ty = source_cd->layers[source_layer_i].type; | int ty = source_cd->layers[source_layer_i].type; | ||||
| if (ty == CD_MLOOP) { | if (STREQ(source_cd->layers[source_layer_i].name, ".corner_vert") || | ||||
| STREQ(source_cd->layers[source_layer_i].name, ".corner_edge")) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| const char *name = source_cd->layers[source_layer_i].name; | const char *name = source_cd->layers[source_layer_i].name; | ||||
| int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name); | int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name); | ||||
| if (target_layer_i == -1) { | if (target_layer_i == -1) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (orig_loop_index != -1) { | if (orig_loop_index != -1) { | ||||
| ▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Set the loopstart and totloop for each output poly, | /* Set the loopstart and totloop for each output poly, | ||||
| * and set the vertices in the appropriate loops. */ | * and set the vertices in the appropriate loops. */ | ||||
| bke::SpanAttributeWriter<int> dst_material_indices = | bke::SpanAttributeWriter<int> dst_material_indices = | ||||
| result->attributes_for_write().lookup_or_add_for_write_only_span<int>("material_index", | result->attributes_for_write().lookup_or_add_for_write_only_span<int>("material_index", | ||||
| ATTR_DOMAIN_FACE); | ATTR_DOMAIN_FACE); | ||||
| int cur_loop_index = 0; | int cur_loop_index = 0; | ||||
| MutableSpan<MLoop> dst_loops = result->loops_for_write(); | MutableSpan<int> dst_corner_verts = result->corner_verts_for_write(); | ||||
| MutableSpan<MPoly> dst_polys = result->polys_for_write(); | MutableSpan<MPoly> dst_polys = result->polys_for_write(); | ||||
| MLoop *l = dst_loops.data(); | |||||
| for (int fi : im->face_index_range()) { | for (int fi : im->face_index_range()) { | ||||
| const Face *f = im->face(fi); | const Face *f = im->face(fi); | ||||
| const Mesh *orig_me; | const Mesh *orig_me; | ||||
| int index_in_orig_me; | int index_in_orig_me; | ||||
| int orig_me_index; | int orig_me_index; | ||||
| const MPoly *orig_mp = mim.input_mpoly_for_orig_index( | const MPoly *orig_mp = mim.input_mpoly_for_orig_index( | ||||
| f->orig, &orig_me, &orig_me_index, &index_in_orig_me); | f->orig, &orig_me, &orig_me_index, &index_in_orig_me); | ||||
| MPoly *mp = &dst_polys[fi]; | MPoly *mp = &dst_polys[fi]; | ||||
| mp->totloop = f->size(); | mp->totloop = f->size(); | ||||
| mp->loopstart = cur_loop_index; | mp->loopstart = cur_loop_index; | ||||
| for (int j : f->index_range()) { | for (int j : f->index_range()) { | ||||
| const Vert *vf = f->vert[j]; | const Vert *vf = f->vert[j]; | ||||
| const int vfi = im->lookup_vert(vf); | const int vfi = im->lookup_vert(vf); | ||||
| l->v = vfi; | dst_corner_verts[cur_loop_index] = vfi; | ||||
| ++l; | |||||
| ++cur_loop_index; | ++cur_loop_index; | ||||
| } | } | ||||
| copy_poly_attributes(result, | copy_poly_attributes(result, | ||||
| mp, | mp, | ||||
| orig_mp, | orig_mp, | ||||
| orig_me, | orig_me, | ||||
| fi, | fi, | ||||
| Show All 9 Lines | |||||
| /* BKE_mesh_calc_edges will calculate and populate all the | /* BKE_mesh_calc_edges will calculate and populate all the | ||||
| * MEdges from the MPolys. */ | * MEdges from the MPolys. */ | ||||
| BKE_mesh_calc_edges(result, false, false); | BKE_mesh_calc_edges(result, false, false); | ||||
| merge_edge_customdata_layers(result, mim); | merge_edge_customdata_layers(result, mim); | ||||
| /* Now that the MEdges are populated, we can copy over the required attributes and custom layers. | /* Now that the MEdges are populated, we can copy over the required attributes and custom layers. | ||||
| */ | */ | ||||
| MutableSpan<MEdge> edges = result->edges_for_write(); | MutableSpan<MEdge> edges = result->edges_for_write(); | ||||
| const Span<int> dst_corner_edges = result->corner_edges(); | |||||
| for (int fi : im->face_index_range()) { | for (int fi : im->face_index_range()) { | ||||
| const Face *f = im->face(fi); | const Face *f = im->face(fi); | ||||
| const MPoly *mp = &dst_polys[fi]; | const MPoly *mp = &dst_polys[fi]; | ||||
| for (int j : f->index_range()) { | for (int j : f->index_range()) { | ||||
| if (f->edge_orig[j] != NO_INDEX) { | if (f->edge_orig[j] != NO_INDEX) { | ||||
| const Mesh *orig_me; | const Mesh *orig_me; | ||||
| int index_in_orig_me; | int index_in_orig_me; | ||||
| const MEdge *orig_medge = mim.input_medge_for_orig_index( | const MEdge *orig_medge = mim.input_medge_for_orig_index( | ||||
| f->edge_orig[j], &orig_me, &index_in_orig_me); | f->edge_orig[j], &orig_me, &index_in_orig_me); | ||||
| int e_index = dst_loops[mp->loopstart + j].e; | int e_index = dst_corner_edges[mp->loopstart + j]; | ||||
| MEdge *medge = &edges[e_index]; | MEdge *medge = &edges[e_index]; | ||||
| copy_edge_attributes(result, medge, orig_medge, orig_me, e_index, index_in_orig_me); | copy_edge_attributes(result, medge, orig_medge, orig_me, e_index, index_in_orig_me); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (dbg_level > 0) { | if (dbg_level > 0) { | ||||
| BKE_mesh_validate(result, true, true); | BKE_mesh_validate(result, true, true); | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
| write_obj_mesh(m_out, "m_out"); | write_obj_mesh(m_out, "m_out"); | ||||
| } | } | ||||
| Mesh *result = imesh_to_mesh(&m_out, mim); | Mesh *result = imesh_to_mesh(&m_out, mim); | ||||
| /* Store intersecting edge indices. */ | /* Store intersecting edge indices. */ | ||||
| if (r_intersecting_edges != nullptr) { | if (r_intersecting_edges != nullptr) { | ||||
| const Span<MPoly> polys = result->polys(); | const Span<MPoly> polys = result->polys(); | ||||
| const Span<MLoop> loops = result->loops(); | const Span<int> corner_edges = result->corner_edges(); | ||||
| for (int fi : m_out.face_index_range()) { | for (int fi : m_out.face_index_range()) { | ||||
| const Face &face = *m_out.face(fi); | const Face &face = *m_out.face(fi); | ||||
| const MPoly &poly = polys[fi]; | const MPoly &poly = polys[fi]; | ||||
| for (int corner_i : face.index_range()) { | for (int corner_i : face.index_range()) { | ||||
| if (face.is_intersect[corner_i]) { | if (face.is_intersect[corner_i]) { | ||||
| int e_index = loops[poly.loopstart + corner_i].e; | int e_index = corner_edges[poly.loopstart + corner_i]; | ||||
| r_intersecting_edges->append(e_index); | r_intersecting_edges->append(e_index); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return result; | return result; | ||||
| #else // WITH_GMP | #else // WITH_GMP | ||||
| Show All 13 Lines | |||||