Cleanup: Avoid shallow copy in OBJ exporter

Similar to #114791, but a bit more complex since the object
was also used to access materials and vertex groups later on.

Pull Request: https://projects.blender.org/blender/blender/pulls/114796
This commit is contained in:
Hans Goudey
2023-11-14 10:58:58 +01:00
committed by Hans Goudey
parent 8f5ff2c5dd
commit 932f20135d
3 changed files with 27 additions and 56 deletions

View File

@@ -709,7 +709,7 @@ Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
Vector<int> r_mtl_indices;
r_mtl_indices.resize(mesh_to_export.tot_materials());
for (int16_t i = 0; i < mesh_to_export.tot_materials(); i++) {
const Material *material = mesh_to_export.get_object_material(i);
const Material *material = mesh_to_export.materials[i];
if (!material) {
r_mtl_indices[i] = -1;
continue;

View File

@@ -39,10 +39,9 @@ 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_ = export_params.apply_modifiers ?
BKE_object_get_evaluated_mesh(&export_object_eval_) :
BKE_object_get_pre_modified_mesh(&export_object_eval_);
object_name_ = obj_eval->id.name + 2;
export_mesh_ = export_params.apply_modifiers ? BKE_object_get_evaluated_mesh(obj_eval) :
BKE_object_get_pre_modified_mesh(obj_eval);
if (export_mesh_) {
mesh_positions_ = export_mesh_->vert_positions();
mesh_edges_ = export_mesh_->edges();
@@ -55,12 +54,18 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
/* Curves and NURBS surfaces need a new mesh when they're
* exported in the form of vertices and edges.
*/
this->set_mesh(BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true));
this->set_mesh(BKE_mesh_new_from_object(depsgraph, obj_eval, true, true));
}
if (export_params.export_triangulated_mesh && export_object_eval_.type == OB_MESH) {
if (export_params.export_triangulated_mesh && obj_eval->type == OB_MESH) {
this->triangulate_mesh_eval();
}
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
this->materials.reinitialize(export_mesh_->totcol);
for (const int i : this->materials.index_range()) {
this->materials[i] = BKE_object_material_get_eval(obj_eval, i + 1);
}
set_world_axes_transform(*obj_eval, export_params.forward_axis, export_params.up_axis);
}
/**
@@ -134,17 +139,18 @@ void OBJMesh::triangulate_mesh_eval()
this->set_mesh(triangulated);
}
void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
void OBJMesh::set_world_axes_transform(const Object &obj_eval,
const eIOAxis forward,
const eIOAxis up)
{
float axes_transform[3][3];
unit_m3(axes_transform);
/* +Y-forward and +Z-up are the default Blender axis settings. */
mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.object_to_world);
mul_m4_m3m4(world_and_axes_transform_, axes_transform, obj_eval.object_to_world);
/* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
mul_v3_m3v3(
world_and_axes_transform_[3], axes_transform, export_object_eval_.object_to_world[3]);
world_and_axes_transform_[3][3] = export_object_eval_.object_to_world[3][3];
mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, obj_eval.object_to_world[3]);
world_and_axes_transform_[3][3] = obj_eval.object_to_world[3][3];
/* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
float normal_matrix[3][3];
@@ -176,7 +182,7 @@ int OBJMesh::tot_edges() const
int16_t OBJMesh::tot_materials() const
{
return export_mesh_->totcol;
return this->materials.size();
}
int OBJMesh::tot_normal_indices() const
@@ -233,19 +239,6 @@ void OBJMesh::calc_poly_order()
});
}
const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
{
/**
* The const_cast is safe here because #BKE_object_material_get_eval won't change the object
* but it is a big can of worms to fix the declaration of that function right now.
*
* The call uses "+ 1" as material getter needs one-based indices.
*/
Object *obj = const_cast<Object *>(&export_object_eval_);
const Material *r_mat = BKE_object_material_get_eval(obj, mat_nr + 1);
return r_mat;
}
bool OBJMesh::is_ith_poly_smooth(const int face_index) const
{
return !sharp_faces_[face_index];
@@ -253,7 +246,7 @@ bool OBJMesh::is_ith_poly_smooth(const int face_index) const
const char *OBJMesh::get_object_name() const
{
return export_object_eval_.id.name + 2;
return object_name_.c_str();
}
const char *OBJMesh::get_object_mesh_name() const
@@ -261,15 +254,6 @@ const char *OBJMesh::get_object_mesh_name() const
return export_mesh_->id.name + 2;
}
const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
{
const Material *mat = get_object_material(mat_nr);
if (!mat) {
return nullptr;
}
return mat->id.name + 2;
}
float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const
{
float3 r_coords = mesh_positions_[vert_index];
@@ -428,10 +412,7 @@ Vector<int> OBJMesh::calc_poly_normal_indices(const int face_index) const
int OBJMesh::tot_deform_groups() const
{
if (!BKE_object_supports_vertex_groups(&export_object_eval_)) {
return 0;
}
return BKE_object_defgroup_count(&export_object_eval_);
return BLI_listbase_count(&export_mesh_->vertex_group_names);
}
int16_t OBJMesh::get_poly_deform_group_index(const int face_index,
@@ -469,7 +450,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int face_index,
const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const
{
const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>(
BLI_findlink(BKE_object_defgroup_list(&export_object_eval_), def_group_index)));
BLI_findlink(&export_mesh_->vertex_group_names, def_group_index)));
return vertex_group.name;
}

View File

@@ -30,11 +30,7 @@ const int NEGATIVE_INIT = -10;
class OBJMesh : NonCopyable {
private:
/**
* We need to copy the entire Object structure here because the dependency graph iterator
* sometimes builds an Object in a temporary space that doesn't persist.
*/
Object export_object_eval_;
std::string object_name_;
/** A pointer to #owned_export_mesh_ or the object'ed evaluated/original mesh. */
const Mesh *export_mesh_;
/** A mesh owned here, if created or modified for the export. May be null. */
@@ -89,6 +85,8 @@ class OBJMesh : NonCopyable {
Vector<int> poly_order_;
public:
Array<const Material *> materials;
/**
* Store evaluated Object and Mesh pointers. Conditionally triangulate a mesh, or
* create a new Mesh from a Curve.
@@ -114,10 +112,6 @@ class OBJMesh : NonCopyable {
* \return Total materials in the object.
*/
int16_t tot_materials() const;
/**
* Return mat_nr-th material of the object. The given index should be zero-based.
*/
const Material *get_object_material(int16_t mat_nr) const;
/**
* Calculate smooth groups of a smooth-shaded object.
@@ -138,10 +132,6 @@ class OBJMesh : NonCopyable {
* Get Object's Mesh's name.
*/
const char *get_object_mesh_name() const;
/**
* Get object's material (at the given index) name. The given index should be zero-based.
*/
const char *get_object_material_name(int16_t mat_nr) const;
/**
* Calculate coordinates of the vertex at the given index.
@@ -232,6 +222,6 @@ class OBJMesh : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
void set_world_axes_transform(eIOAxis forward, eIOAxis up);
void set_world_axes_transform(const Object &obj_eval, eIOAxis forward, eIOAxis up);
};
} // namespace blender::io::obj