|
|
|
@ -33,21 +33,23 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
|
|
|
|
|
/* We need to copy the object because it may be in temporary space. */
|
|
|
|
|
Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object);
|
|
|
|
|
export_object_eval_ = dna::shallow_copy(*obj_eval);
|
|
|
|
|
export_mesh_eval_ = export_params.apply_modifiers ?
|
|
|
|
|
BKE_object_get_evaluated_mesh(&export_object_eval_) :
|
|
|
|
|
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
|
|
|
|
mesh_eval_needs_free_ = false;
|
|
|
|
|
|
|
|
|
|
if (!export_mesh_eval_) {
|
|
|
|
|
export_mesh_ = export_params.apply_modifiers ?
|
|
|
|
|
BKE_object_get_evaluated_mesh(&export_object_eval_) :
|
|
|
|
|
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
|
|
|
|
if (export_mesh_) {
|
|
|
|
|
mesh_positions_ = export_mesh_->positions();
|
|
|
|
|
mesh_edges_ = export_mesh_->edges();
|
|
|
|
|
mesh_polys_ = export_mesh_->polys();
|
|
|
|
|
mesh_corner_verts_ = export_mesh_->corner_verts();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Curves and NURBS surfaces need a new mesh when they're
|
|
|
|
|
* exported in the form of vertices and edges.
|
|
|
|
|
*/
|
|
|
|
|
export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true);
|
|
|
|
|
/* Since a new mesh been allocated, it needs to be freed in the destructor. */
|
|
|
|
|
mesh_eval_needs_free_ = true;
|
|
|
|
|
this->set_mesh(BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true));
|
|
|
|
|
}
|
|
|
|
|
if (export_params.export_triangulated_mesh && export_object_eval_.type == OB_MESH) {
|
|
|
|
|
std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
|
|
|
|
|
this->triangulate_mesh_eval();
|
|
|
|
|
}
|
|
|
|
|
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
|
|
|
|
|
}
|
|
|
|
@ -60,18 +62,26 @@ OBJMesh::~OBJMesh()
|
|
|
|
|
clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OBJMesh::free_mesh_if_needed()
|
|
|
|
|
void OBJMesh::set_mesh(Mesh *mesh)
|
|
|
|
|
{
|
|
|
|
|
if (mesh_eval_needs_free_ && export_mesh_eval_) {
|
|
|
|
|
BKE_id_free(nullptr, export_mesh_eval_);
|
|
|
|
|
export_mesh_eval_ = nullptr;
|
|
|
|
|
mesh_eval_needs_free_ = false;
|
|
|
|
|
if (owned_export_mesh_) {
|
|
|
|
|
BKE_id_free(nullptr, owned_export_mesh_);
|
|
|
|
|
}
|
|
|
|
|
owned_export_mesh_ = mesh;
|
|
|
|
|
export_mesh_ = owned_export_mesh_;
|
|
|
|
|
mesh_positions_ = mesh->positions();
|
|
|
|
|
mesh_edges_ = mesh->edges();
|
|
|
|
|
mesh_polys_ = mesh->polys();
|
|
|
|
|
mesh_corner_verts_ = mesh->corner_verts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OBJMesh::clear()
|
|
|
|
|
{
|
|
|
|
|
free_mesh_if_needed();
|
|
|
|
|
if (owned_export_mesh_) {
|
|
|
|
|
BKE_id_free(nullptr, owned_export_mesh_);
|
|
|
|
|
owned_export_mesh_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
export_mesh_ = nullptr;
|
|
|
|
|
uv_indices_.clear_and_make_inline();
|
|
|
|
|
uv_coords_.clear_and_make_inline();
|
|
|
|
|
loop_to_normal_index_.clear_and_make_inline();
|
|
|
|
@ -83,10 +93,10 @@ void OBJMesh::clear()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
|
|
|
|
void OBJMesh::triangulate_mesh_eval()
|
|
|
|
|
{
|
|
|
|
|
if (export_mesh_eval_->totpoly <= 0) {
|
|
|
|
|
return {export_mesh_eval_, false};
|
|
|
|
|
if (export_mesh_->totpoly <= 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const BMeshCreateParams bm_create_params = {false};
|
|
|
|
|
BMeshFromMeshParams bm_convert_params{};
|
|
|
|
@ -99,7 +109,7 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
|
|
|
|
* triangulated here. */
|
|
|
|
|
const int triangulate_min_verts = 4;
|
|
|
|
|
|
|
|
|
|
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params);
|
|
|
|
|
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_, &bm_create_params, &bm_convert_params);
|
|
|
|
|
BM_mesh_triangulate(bmesh,
|
|
|
|
|
MOD_TRIANGULATE_NGON_BEAUTY,
|
|
|
|
|
MOD_TRIANGULATE_QUAD_SHORTEDGE,
|
|
|
|
@ -108,11 +118,9 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
|
|
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_eval_);
|
|
|
|
|
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_);
|
|
|
|
|
BM_mesh_free(bmesh);
|
|
|
|
|
free_mesh_if_needed();
|
|
|
|
|
return {triangulated, true};
|
|
|
|
|
this->set_mesh(triangulated);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
|
|
|
|
@ -137,12 +145,12 @@ void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
|
|
|
|
|
|
|
|
|
|
int OBJMesh::tot_vertices() const
|
|
|
|
|
{
|
|
|
|
|
return export_mesh_eval_->totvert;
|
|
|
|
|
return export_mesh_->totvert;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int OBJMesh::tot_polygons() const
|
|
|
|
|
{
|
|
|
|
|
return export_mesh_eval_->totpoly;
|
|
|
|
|
return export_mesh_->totpoly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int OBJMesh::tot_uv_vertices() const
|
|
|
|
@ -152,12 +160,12 @@ int OBJMesh::tot_uv_vertices() const
|
|
|
|
|
|
|
|
|
|
int OBJMesh::tot_edges() const
|
|
|
|
|
{
|
|
|
|
|
return export_mesh_eval_->totedge;
|
|
|
|
|
return export_mesh_->totedge;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int16_t OBJMesh::tot_materials() const
|
|
|
|
|
{
|
|
|
|
|
return export_mesh_eval_->totcol;
|
|
|
|
|
return export_mesh_->totcol;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int OBJMesh::tot_normal_indices() const
|
|
|
|
@ -175,27 +183,25 @@ int OBJMesh::ith_smooth_group(const int poly_index) const
|
|
|
|
|
|
|
|
|
|
void OBJMesh::ensure_mesh_normals() const
|
|
|
|
|
{
|
|
|
|
|
BKE_mesh_calc_normals_split(export_mesh_eval_);
|
|
|
|
|
/* Const cast can be removed when calculating face corner normals lazily is possible. */
|
|
|
|
|
BKE_mesh_calc_normals_split(const_cast<Mesh *>(export_mesh_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
|
|
|
|
{
|
|
|
|
|
const Span<MEdge> edges = export_mesh_eval_->edges();
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
const Span<int> corner_edges = export_mesh_eval_->corner_edges();
|
|
|
|
|
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(edges.data(),
|
|
|
|
|
edges.size(),
|
|
|
|
|
polys.data(),
|
|
|
|
|
polys.size(),
|
|
|
|
|
corner_edges.data(),
|
|
|
|
|
corner_edges.size(),
|
|
|
|
|
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.data(),
|
|
|
|
|
mesh_edges_.size(),
|
|
|
|
|
mesh_polys_.data(),
|
|
|
|
|
mesh_polys_.size(),
|
|
|
|
|
export_mesh_->corner_edges().data(),
|
|
|
|
|
export_mesh_->totloop,
|
|
|
|
|
&tot_smooth_groups_,
|
|
|
|
|
use_bitflags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OBJMesh::calc_poly_order()
|
|
|
|
|
{
|
|
|
|
|
const bke::AttributeAccessor attributes = export_mesh_eval_->attributes();
|
|
|
|
|
const bke::AttributeAccessor attributes = export_mesh_->attributes();
|
|
|
|
|
const VArray<int> material_indices = attributes.lookup_or_default<int>(
|
|
|
|
|
"material_index", ATTR_DOMAIN_FACE, 0);
|
|
|
|
|
if (material_indices.is_single() && material_indices.get_internal_single() == 0) {
|
|
|
|
@ -234,8 +240,7 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
|
|
|
|
|
|
|
|
|
|
bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
|
|
|
|
|
{
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
return polys[poly_index].flag & ME_SMOOTH;
|
|
|
|
|
return mesh_polys_[poly_index].flag & ME_SMOOTH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *OBJMesh::get_object_name() const
|
|
|
|
@ -245,7 +250,7 @@ const char *OBJMesh::get_object_name() const
|
|
|
|
|
|
|
|
|
|
const char *OBJMesh::get_object_mesh_name() const
|
|
|
|
|
{
|
|
|
|
|
return export_mesh_eval_->id.name + 2;
|
|
|
|
|
return export_mesh_->id.name + 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
|
|
|
|
@ -259,9 +264,7 @@ const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
|
|
|
|
|
|
|
|
|
|
float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const
|
|
|
|
|
{
|
|
|
|
|
float3 r_coords;
|
|
|
|
|
const Span<float3> positions = export_mesh_eval_->positions();
|
|
|
|
|
copy_v3_v3(r_coords, positions[vert_index]);
|
|
|
|
|
float3 r_coords = mesh_positions_[vert_index];
|
|
|
|
|
mul_m4_v3(world_and_axes_transform_, r_coords);
|
|
|
|
|
mul_v3_fl(r_coords, global_scale);
|
|
|
|
|
return r_coords;
|
|
|
|
@ -269,43 +272,33 @@ float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scal
|
|
|
|
|
|
|
|
|
|
Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
|
|
|
|
|
{
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
const Span<MLoop> loops = export_mesh_eval_->loops();
|
|
|
|
|
const MPoly &mpoly = polys[poly_index];
|
|
|
|
|
const MLoop *mloop = &loops[mpoly.loopstart];
|
|
|
|
|
const int totloop = mpoly.totloop;
|
|
|
|
|
Vector<int> r_poly_vertex_indices(totloop);
|
|
|
|
|
for (int loop_index = 0; loop_index < totloop; loop_index++) {
|
|
|
|
|
r_poly_vertex_indices[loop_index] = mloop[loop_index].v;
|
|
|
|
|
}
|
|
|
|
|
return r_poly_vertex_indices;
|
|
|
|
|
const MPoly &mpoly = mesh_polys_[poly_index];
|
|
|
|
|
return mesh_corner_verts_.slice(mpoly.loopstart, mpoly.totloop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OBJMesh::store_uv_coords_and_indices()
|
|
|
|
|
{
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
const Span<MLoop> loops = export_mesh_eval_->loops();
|
|
|
|
|
const int totvert = export_mesh_eval_->totvert;
|
|
|
|
|
const int totvert = export_mesh_->totvert;
|
|
|
|
|
const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
|
|
|
|
|
CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
|
|
|
|
|
CustomData_get_layer(&export_mesh_->ldata, CD_MLOOPUV));
|
|
|
|
|
if (!mloopuv) {
|
|
|
|
|
tot_uv_vertices_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
|
|
|
|
|
|
|
|
|
|
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(polys.data(),
|
|
|
|
|
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(mesh_polys_.data(),
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
loops.data(),
|
|
|
|
|
mesh_corner_verts_.data(),
|
|
|
|
|
mloopuv,
|
|
|
|
|
polys.size(),
|
|
|
|
|
mesh_polys_.size(),
|
|
|
|
|
totvert,
|
|
|
|
|
limit,
|
|
|
|
|
false,
|
|
|
|
|
false);
|
|
|
|
|
|
|
|
|
|
uv_indices_.resize(polys.size());
|
|
|
|
|
uv_indices_.resize(mesh_polys_.size());
|
|
|
|
|
/* At least total vertices of a mesh will be present in its texture map. So
|
|
|
|
|
* reserve minimum space early. */
|
|
|
|
|
uv_coords_.reserve(totvert);
|
|
|
|
@ -317,11 +310,11 @@ void OBJMesh::store_uv_coords_and_indices()
|
|
|
|
|
if (uv_vert->separate) {
|
|
|
|
|
tot_uv_vertices_ += 1;
|
|
|
|
|
}
|
|
|
|
|
const int verts_in_poly = polys[uv_vert->poly_index].totloop;
|
|
|
|
|
const int verts_in_poly = mesh_polys_[uv_vert->poly_index].totloop;
|
|
|
|
|
|
|
|
|
|
/* Store UV vertex coordinates. */
|
|
|
|
|
uv_coords_.resize(tot_uv_vertices_);
|
|
|
|
|
const int loopstart = polys[uv_vert->poly_index].loopstart;
|
|
|
|
|
const int loopstart = mesh_polys_[uv_vert->poly_index].loopstart;
|
|
|
|
|
Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
|
|
|
|
|
uv_coords_[tot_uv_vertices_ - 1] = float2(vert_uv_coords[0], vert_uv_coords[1]);
|
|
|
|
|
|
|
|
|
@ -339,7 +332,7 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
|
|
|
|
|
if (uv_indices_.size() <= 0) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
BLI_assert(poly_index < export_mesh_eval_->totpoly);
|
|
|
|
|
BLI_assert(poly_index < export_mesh_->totpoly);
|
|
|
|
|
BLI_assert(poly_index < uv_indices_.size());
|
|
|
|
|
return uv_indices_[poly_index];
|
|
|
|
|
}
|
|
|
|
@ -347,13 +340,10 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
|
|
|
|
|
float3 OBJMesh::calc_poly_normal(const int poly_index) const
|
|
|
|
|
{
|
|
|
|
|
float3 r_poly_normal;
|
|
|
|
|
const Span<float3> positions = export_mesh_eval_->positions();
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
const Span<MLoop> loops = export_mesh_eval_->loops();
|
|
|
|
|
const MPoly &poly = polys[poly_index];
|
|
|
|
|
const MPoly &poly = mesh_polys_[poly_index];
|
|
|
|
|
BKE_mesh_calc_poly_normal(&poly,
|
|
|
|
|
&loops[poly.loopstart],
|
|
|
|
|
reinterpret_cast<const float(*)[3]>(positions.data()),
|
|
|
|
|
&mesh_corner_verts_[poly.loopstart],
|
|
|
|
|
reinterpret_cast<const float(*)[3]>(mesh_positions_.data()),
|
|
|
|
|
r_poly_normal);
|
|
|
|
|
mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
|
|
|
|
|
normalize_v3(r_poly_normal);
|
|
|
|
@ -378,8 +368,6 @@ static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
|
|
|
|
|
|
|
|
|
|
void OBJMesh::store_normal_coords_and_indices()
|
|
|
|
|
{
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
|
|
|
|
|
/* We'll round normal components to 4 digits.
|
|
|
|
|
* This will cover up some minor differences
|
|
|
|
|
* between floating point calculations on different platforms.
|
|
|
|
@ -389,19 +377,19 @@ void OBJMesh::store_normal_coords_and_indices()
|
|
|
|
|
int cur_normal_index = 0;
|
|
|
|
|
Map<float3, int> normal_to_index;
|
|
|
|
|
/* We don't know how many unique normals there will be, but this is a guess. */
|
|
|
|
|
normal_to_index.reserve(export_mesh_eval_->totpoly);
|
|
|
|
|
loop_to_normal_index_.resize(export_mesh_eval_->totloop);
|
|
|
|
|
normal_to_index.reserve(export_mesh_->totpoly);
|
|
|
|
|
loop_to_normal_index_.resize(export_mesh_->totloop);
|
|
|
|
|
loop_to_normal_index_.fill(-1);
|
|
|
|
|
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
|
|
|
|
CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
|
|
|
|
|
for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
|
|
|
|
|
const MPoly &mpoly = polys[poly_index];
|
|
|
|
|
CustomData_get_layer(&export_mesh_->ldata, CD_NORMAL));
|
|
|
|
|
for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) {
|
|
|
|
|
const MPoly &mpoly = mesh_polys_[poly_index];
|
|
|
|
|
bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
|
|
|
|
|
if (need_per_loop_normals) {
|
|
|
|
|
for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
|
|
|
|
|
float3 loop_normal;
|
|
|
|
|
int loop_index = mpoly.loopstart + loop_of_poly;
|
|
|
|
|
BLI_assert(loop_index < export_mesh_eval_->totloop);
|
|
|
|
|
BLI_assert(loop_index < export_mesh_->totloop);
|
|
|
|
|
copy_v3_v3(loop_normal, lnors[loop_index]);
|
|
|
|
|
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
|
|
|
|
normalize_v3(loop_normal);
|
|
|
|
@ -426,7 +414,7 @@ void OBJMesh::store_normal_coords_and_indices()
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < mpoly.totloop; ++i) {
|
|
|
|
|
int loop_index = mpoly.loopstart + i;
|
|
|
|
|
BLI_assert(loop_index < export_mesh_eval_->totloop);
|
|
|
|
|
BLI_assert(loop_index < export_mesh_->totloop);
|
|
|
|
|
loop_to_normal_index_[loop_index] = poly_norm_index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -439,8 +427,7 @@ Vector<int> OBJMesh::calc_poly_normal_indices(const int poly_index) const
|
|
|
|
|
if (loop_to_normal_index_.is_empty()) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
const MPoly &mpoly = polys[poly_index];
|
|
|
|
|
const MPoly &mpoly = mesh_polys_[poly_index];
|
|
|
|
|
const int totloop = mpoly.totloop;
|
|
|
|
|
Vector<int> r_poly_normal_indices(totloop);
|
|
|
|
|
for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
|
|
|
|
@ -461,21 +448,18 @@ int OBJMesh::tot_deform_groups() const
|
|
|
|
|
int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
|
|
|
|
|
MutableSpan<float> group_weights) const
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(poly_index < export_mesh_eval_->totpoly);
|
|
|
|
|
BLI_assert(poly_index < export_mesh_->totpoly);
|
|
|
|
|
BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
|
|
|
|
|
const Span<MPoly> polys = export_mesh_eval_->polys();
|
|
|
|
|
const Span<MLoop> loops = export_mesh_eval_->loops();
|
|
|
|
|
const Span<MDeformVert> dverts = export_mesh_eval_->deform_verts();
|
|
|
|
|
const Span<MDeformVert> dverts = export_mesh_->deform_verts();
|
|
|
|
|
if (dverts.is_empty()) {
|
|
|
|
|
return NOT_FOUND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group_weights.fill(0);
|
|
|
|
|
bool found_any_group = false;
|
|
|
|
|
const MPoly &mpoly = polys[poly_index];
|
|
|
|
|
const MLoop *mloop = &loops[mpoly.loopstart];
|
|
|
|
|
for (int loop_i = 0; loop_i < mpoly.totloop; ++loop_i, ++mloop) {
|
|
|
|
|
const MDeformVert &dv = dverts[mloop->v];
|
|
|
|
|
const MPoly &mpoly = mesh_polys_[poly_index];
|
|
|
|
|
for (const int vert_i : mesh_corner_verts_.slice(mpoly.loopstart, mpoly.totloop)) {
|
|
|
|
|
const MDeformVert &dv = dverts[vert_i];
|
|
|
|
|
for (int weight_i = 0; weight_i < dv.totweight; ++weight_i) {
|
|
|
|
|
const auto group = dv.dw[weight_i].def_nr;
|
|
|
|
|
if (group < group_weights.size()) {
|
|
|
|
|