Fix T49813: crash after changing Alembic cache topology.

Crash is due by mismatching loops and faces counts between the Alembic
data and the Blender derivedmesh which does not appear so
straightforward to fix (the crash happens deep in the derivedmesh code).

So for now, try to detect if the topology has changed and if so, both
only read vertices (vertex colors and UVs won't be read, as tied to face
loops) and add a warning message in the modifier's UI to let the user
know.
This commit is contained in:
Kévin Dietrich 2016-11-30 09:20:45 +01:00
parent 514db9f014
commit 66a3671904
Notes: blender-bot 2023-02-14 07:29:13 +01:00
Referenced by issue #49813, Crash after changing Alembic cache topology
8 changed files with 47 additions and 16 deletions

View File

@ -361,7 +361,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
* object directly and create a new DerivedMesh from that. Also we might need to
* create new or delete existing NURBS in the curve.
*/
DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/)
DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/, const char **/*err_str*/)
{
ISampleSelector sample_sel(time);
const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);

View File

@ -56,7 +56,7 @@ public:
bool valid() const;
void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int);
DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int read_flag, const char **err_str);
};
/* ************************************************************************** */

View File

@ -896,7 +896,7 @@ void AbcMeshReader::readObjectData(Main *bmain, float time)
const ISampleSelector sample_sel(time);
DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL);
if (ndm != dm) {
dm->release(dm);
@ -978,7 +978,7 @@ CDStreamConfig get_config(DerivedMesh *dm)
return config;
}
DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
{
ISampleSelector sample_sel(time);
const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
@ -1003,6 +1003,21 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time,
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
else {
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813
* TODO(kevin): perhaps find a better way to do this? */
if (face_counts->size() != dm->getNumPolys(dm) ||
face_indices->size() != dm->getNumLoops(dm))
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
if (err_str) {
*err_str = "Topology has changed, perhaps by triangulating the"
" mesh. Only vertices will be read!";
}
}
}
CDStreamConfig config = get_config(new_dm ? new_dm : dm);
config.time = time;
@ -1177,7 +1192,7 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
m_object->data = mesh;
DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL);
if (ndm != dm) {
dm->release(dm);
@ -1257,7 +1272,7 @@ void read_subd_sample(ImportSettings *settings,
/* TODO: face sets */
}
DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
{
ISampleSelector sample_sel(time);
const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
@ -1281,6 +1296,21 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time,
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
else {
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813
* TODO(kevin): perhaps find a better way to do this? */
if (face_counts->size() != dm->getNumPolys(dm) ||
face_indices->size() != dm->getNumLoops(dm))
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
if (err_str) {
*err_str = "Topology has changed, perhaps by triangulating the"
" mesh. Only vertices will be read!";
}
}
}
/* Only read point data when streaming meshes, unless we need to create new ones. */
CDStreamConfig config = get_config(new_dm ? new_dm : dm);

View File

@ -102,7 +102,7 @@ public:
void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
@ -128,7 +128,7 @@ public:
bool valid() const;
void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
};
void read_subd_sample(ImportSettings *settings,

View File

@ -165,10 +165,11 @@ public:
virtual void readObjectData(Main *bmain, float time) = 0;
virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
{
(void)time;
(void)read_flag;
(void)err_str;
return dm;
}

View File

@ -156,7 +156,7 @@ void AbcPointsReader::readObjectData(Main *bmain, float time)
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0, NULL);
if (ndm != dm) {
dm->release(dm);
@ -199,7 +199,7 @@ void read_points_sample(const IPointsSchema &schema,
read_mverts(config.mvert, positions, vnormals);
}
DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/)
DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char **/*err_str*/)
{
ISampleSelector sample_sel(time);
const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);

View File

@ -61,7 +61,7 @@ public:
void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
};
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,

View File

@ -816,7 +816,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL;
}
return abc_reader->read_derivedmesh(dm, time, read_flag);
return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
}
else if (ISubD::matches(header)) {
if (ob->type != OB_MESH) {
@ -824,7 +824,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL;
}
return abc_reader->read_derivedmesh(dm, time, read_flag);
return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
}
else if (IPoints::matches(header)) {
if (ob->type != OB_MESH) {
@ -832,7 +832,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL;
}
return abc_reader->read_derivedmesh(dm, time, read_flag);
return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
}
else if (ICurves::matches(header)) {
if (ob->type != OB_CURVE) {
@ -840,7 +840,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL;
}
return abc_reader->read_derivedmesh(dm, time, read_flag);
return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
}
*err_str = "Unsupported object type: verify object path"; // or poke developer