Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/io/alembic/intern/abc_reader_mesh.cc')
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc161
1 files changed, 107 insertions, 54 deletions
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 5a42be2bb02..14c3d756d56 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -33,6 +33,7 @@
#include "DNA_object_types.h"
#include "BLI_compiler_compat.h"
+#include "BLI_listbase.h"
#include "BLI_math_geom.h"
#include "BKE_main.h"
@@ -43,7 +44,10 @@
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::P3fArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
+using Alembic::AbcGeom::IC3fGeomParam;
+using Alembic::AbcGeom::IC4fGeomParam;
using Alembic::AbcGeom::IFaceSet;
using Alembic::AbcGeom::IFaceSetSchema;
using Alembic::AbcGeom::IN3fGeomParam;
@@ -67,55 +71,44 @@ namespace blender::io::alembic {
/* Some helpers for mesh generation */
namespace utils {
-static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
+static std::map<std::string, Material *> build_material_map(const Main *bmain)
{
- Material *material = static_cast<Material *>(bmain->materials.first);
-
- for (; material; material = static_cast<Material *>(material->id.next)) {
+ std::map<std::string, Material *> mat_map;
+ LISTBASE_FOREACH (Material *, material, &bmain->materials) {
mat_map[material->id.name + 2] = material;
}
+ return mat_map;
}
static void assign_materials(Main *bmain,
Object *ob,
const std::map<std::string, int> &mat_index_map)
{
- bool can_assign = true;
- std::map<std::string, int>::const_iterator it = mat_index_map.begin();
-
- int matcount = 0;
- for (; it != mat_index_map.end(); ++it, matcount++) {
+ std::map<std::string, int>::const_iterator it;
+ for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
if (!BKE_object_material_slot_add(bmain, ob)) {
- can_assign = false;
- break;
+ return;
}
}
- /* TODO(kevin): use global map? */
- std::map<std::string, Material *> mat_map;
- build_mat_map(bmain, mat_map);
-
+ std::map<std::string, Material *> matname_to_material = build_material_map(bmain);
std::map<std::string, Material *>::iterator mat_iter;
- if (can_assign) {
- it = mat_index_map.begin();
+ for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
+ const std::string mat_name = it->first;
+ const int mat_index = it->second;
- for (; it != mat_index_map.end(); ++it) {
- std::string mat_name = it->first;
- mat_iter = mat_map.find(mat_name);
-
- Material *assigned_mat;
-
- if (mat_iter == mat_map.end()) {
- assigned_mat = BKE_material_add(bmain, mat_name.c_str());
- mat_map[mat_name] = assigned_mat;
- }
- else {
- assigned_mat = mat_iter->second;
- }
-
- BKE_object_material_assign(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA);
+ Material *assigned_mat;
+ mat_iter = matname_to_material.find(mat_name);
+ if (mat_iter == matname_to_material.end()) {
+ assigned_mat = BKE_material_add(bmain, mat_name.c_str());
+ matname_to_material[mat_name] = assigned_mat;
+ }
+ else {
+ assigned_mat = mat_iter->second;
}
+
+ BKE_object_material_assign(bmain, ob, assigned_mat, mat_index, BKE_MAT_ASSIGN_OBDATA);
}
}
@@ -155,7 +148,8 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
MVert *mverts = config.mvert;
const P3fArraySamplePtr &positions = mesh_data.positions;
- if (config.weight != 0.0f && mesh_data.ceil_positions != NULL &&
+ if (config.use_vertex_interpolation && config.weight != 0.0f &&
+ mesh_data.ceil_positions != nullptr &&
mesh_data.ceil_positions->size() == positions->size()) {
read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight);
return;
@@ -258,7 +252,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
static void process_no_normals(CDStreamConfig &config)
{
- /* Absense of normals in the Alembic mesh is interpreted as 'smooth'. */
+ /* Absence of normals in the Alembic mesh is interpreted as 'smooth'. */
BKE_mesh_calc_normals(config.mesh);
}
@@ -271,10 +265,19 @@ static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr
return;
}
+ Mesh *mesh = config.mesh;
+ if (loop_count != mesh->totloop) {
+ /* This happens in certain Houdini exports. When a mesh is animated and then replaced by a
+ * fluid simulation, Houdini will still write the original mesh's loop normals, but the mesh
+ * verts/loops/polys are from the simulation. In such cases the normals cannot be mapped to the
+ * mesh, so it's better to ignore them. */
+ process_no_normals(config);
+ return;
+ }
+
float(*lnors)[3] = static_cast<float(*)[3]>(
MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals"));
- Mesh *mesh = config.mesh;
MPoly *mpoly = mesh->mpoly;
const N3fArraySample &loop_normals = *loop_normals_ptr;
int abc_index = 0;
@@ -327,11 +330,11 @@ static void process_normals(CDStreamConfig &config,
Alembic::AbcGeom::GeometryScope scope = normals.getScope();
switch (scope) {
- case Alembic::AbcGeom::kFacevaryingScope: // 'Vertex Normals' in Houdini.
+ case Alembic::AbcGeom::kFacevaryingScope: /* 'Vertex Normals' in Houdini. */
process_loop_normals(config, normsamp.getVals());
break;
case Alembic::AbcGeom::kVertexScope:
- case Alembic::AbcGeom::kVaryingScope: // 'Point Normals' in Houdini.
+ case Alembic::AbcGeom::kVaryingScope: /* 'Point Normals' in Houdini. */
process_vertex_normals(config, normsamp.getVals());
break;
case Alembic::AbcGeom::kConstantScope:
@@ -381,19 +384,19 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
/* unsupported custom data type -- don't do anything. */
if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
- return NULL;
+ return nullptr;
}
loopdata = &mesh->ldata;
cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
- if (cd_ptr != NULL) {
+ if (cd_ptr != nullptr) {
/* layer already exists, so just return it. */
return cd_ptr;
}
/* Create a new layer. */
numloops = mesh->totloop;
- cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name);
+ cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name);
return cd_ptr;
}
@@ -448,7 +451,7 @@ static void read_mesh_sample(const std::string &iobject_full_name,
}
}
-CDStreamConfig get_config(Mesh *mesh)
+CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
{
CDStreamConfig config;
@@ -462,6 +465,7 @@ CDStreamConfig get_config(Mesh *mesh)
config.totpoly = mesh->totpoly;
config.loopdata = &mesh->ldata;
config.add_customdata_cb = add_customdata_cb;
+ config.use_vertex_interpolation = use_vertex_interpolation;
return config;
}
@@ -484,6 +488,39 @@ bool AbcMeshReader::valid() const
return m_schema.valid();
}
+template<class typedGeomParam>
+bool is_valid_animated(const ICompoundProperty arbGeomParams, const PropertyHeader &prop_header)
+{
+ if (!typedGeomParam::matches(prop_header)) {
+ return false;
+ }
+
+ typedGeomParam geom_param(arbGeomParams, prop_header.getName());
+ return geom_param.valid() && !geom_param.isConstant();
+}
+
+static bool has_animated_geom_params(const ICompoundProperty arbGeomParams)
+{
+ if (!arbGeomParams.valid()) {
+ return false;
+ }
+
+ const int num_props = arbGeomParams.getNumProperties();
+ for (int i = 0; i < num_props; i++) {
+ const PropertyHeader &prop_header = arbGeomParams.getPropertyHeader(i);
+
+ /* These are interpreted as vertex colors later (see 'read_custom_data'). */
+ if (is_valid_animated<IC3fGeomParam>(arbGeomParams, prop_header)) {
+ return true;
+ }
+ if (is_valid_animated<IC4fGeomParam>(arbGeomParams, prop_header)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Specialisation of has_animations() as defined in abc_reader_object.h. */
template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
{
@@ -492,9 +529,21 @@ template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, Import
}
IV2fGeomParam uvsParam = schema.getUVsParam();
+ if (uvsParam.valid() && !uvsParam.isConstant()) {
+ return true;
+ }
+
IN3fGeomParam normalsParam = schema.getNormalsParam();
- return (uvsParam.valid() && !uvsParam.isConstant()) ||
- (normalsParam.valid() && !normalsParam.isConstant());
+ if (normalsParam.valid() && !normalsParam.isConstant()) {
+ return true;
+ }
+
+ ICompoundProperty arbGeomParams = schema.getArbGeomParams();
+ if (has_animated_geom_params(arbGeomParams)) {
+ return true;
+ }
+
+ return false;
}
void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
@@ -504,7 +553,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr);
if (read_mesh != mesh) {
/* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
@@ -556,7 +605,7 @@ bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector
m_schema.getName().c_str(),
sample_sel.getRequestedTime(),
ex.what());
- // A similar error in read_mesh() would just return existing_mesh.
+ /* A similar error in read_mesh() would just return existing_mesh. */
return false;
}
@@ -609,7 +658,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
return existing_mesh;
}
- Mesh *new_mesh = NULL;
+ Mesh *new_mesh = nullptr;
/* Only read point data when streaming meshes, unless we need to create new ones. */
ImportSettings settings;
@@ -637,7 +686,9 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
}
}
- CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
+ Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
+ const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
+ CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
config.time = sample_sel.getRequestedTime();
config.modifier_error_message = err_str;
@@ -677,7 +728,7 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
const std::string &grp_name = face_sets[i];
if (r_mat_map.find(grp_name) == r_mat_map.end()) {
- r_mat_map[grp_name] = 1 + current_mat++;
+ r_mat_map[grp_name] = ++current_mat;
}
const int assigned_mat = r_mat_map[grp_name];
@@ -727,7 +778,7 @@ BLI_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
}
}
- return NULL;
+ return nullptr;
}
static void read_subd_sample(const std::string &iobject_full_name,
@@ -817,7 +868,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr);
if (read_mesh != mesh) {
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true);
}
@@ -853,7 +904,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
}
MEdge *edge = find_edge(edges, totedge, v1, v2);
- if (edge == NULL) {
+ if (edge == nullptr) {
edge = find_edge(edges, totedge, v2, v1);
}
@@ -899,7 +950,7 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
- Mesh *new_mesh = NULL;
+ Mesh *new_mesh = nullptr;
ImportSettings settings;
settings.read_flag |= read_flag;
@@ -927,11 +978,13 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
}
/* Only read point data when streaming meshes, unless we need to create new ones. */
- CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
+ Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
+ const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
+ CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
config.time = sample_sel.getRequestedTime();
read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
- return config.mesh;
+ return mesh_to_export;
}
} // namespace blender::io::alembic