diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-11-22 14:04:37 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-12-01 14:44:32 +0300 |
commit | 02ab4ad991906f817698d3810c3d464cfaedcaff (patch) | |
tree | 1ce39dfc6dc73a16d8912b437bd816d6f01f9620 /source/blender/io/alembic/intern | |
parent | fd224048375bf7a9d970c226b7ac843458d5428e (diff) |
Fix T92561: unstable particle distribution with Alembic files
When enabling or disabling a Mesh Sequence Cache modifier of an Object
with a hair particle system, the hair would switch positions. This is
caused because original coordinates in Blender are expected to be
normalized, and toggling the modifier would cause the usage of different
orco layers: one that is normalized, and the other which isn't.
This bug exposes a few related issues:
- if the Alembic file did not have orco data,
`MOD_deform_mesh_eval_get`, used by the particle system modifier, would
add an orco layer without normalization
- `MOD_deform_mesh_eval_get` would also ignore the presence of an orco
layer (e.g. one that could have been read from Alembic)
- if the Alembic file did have orco data, the data would be read
unnormalized
To fix those various issues, original coordinates are normalized when
read from Alembic and unnormalized when written to Alembic; and a new
utility function `BKE_mesh_orco_ensure` is added to add a normalized
orco layer if none exists on the mesh already, this function derives
from the code used in the particle system.
Reviewed By: brecht
Maniphest Tasks: T92561
Differential Revision: https://developer.blender.org/D13306
Diffstat (limited to 'source/blender/io/alembic/intern')
-rw-r--r-- | source/blender/io/alembic/intern/abc_customdata.cc | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 188e8daac8f..04add1c1360 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -36,6 +36,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" +#include "BKE_mesh.h" /* NOTE: for now only UVs and Vertex Colors are supported for streaming. * Although Alembic only allows for a single UV layer per {I|O}Schema, and does @@ -253,7 +254,8 @@ static void write_mcol(const OCompoundProperty &prop, void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config) { - const void *customdata = CustomData_get_layer(&config.mesh->vdata, CD_ORCO); + Mesh *mesh = config.mesh; + const void *customdata = CustomData_get_layer(&mesh->vdata, CD_ORCO); if (customdata == nullptr) { /* Data not available, so don't even bother creating an Alembic property for it. */ return; @@ -268,6 +270,11 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig & coords[vertex_idx].setValue(orco_yup[0], orco_yup[1], orco_yup[2]); } + /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them + * unnormalized, so we need to unnormalize (invert transform) them. */ + BKE_mesh_orco_verts_transform( + mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true); + if (!config.abc_orco.valid()) { /* Create the Alembic property and keep a reference so future frames can reuse it. */ config.abc_orco = OV3fGeomParam(prop, propNameOriginalCoordinates, false, kVertexScope, 1); @@ -536,13 +543,14 @@ void read_generated_coordinates(const ICompoundProperty &prop, IV3fGeomParam::Sample sample = param.getExpandedValue(iss); Alembic::AbcGeom::V3fArraySamplePtr abc_ocro = sample.getVals(); const size_t totvert = abc_ocro.get()->size(); + Mesh *mesh = config.mesh; void *cd_data; - if (CustomData_has_layer(&config.mesh->vdata, CD_ORCO)) { - cd_data = CustomData_get_layer(&config.mesh->vdata, CD_ORCO); + if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) { + cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO); } else { - cd_data = CustomData_add_layer(&config.mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert); + cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert); } float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data); @@ -550,6 +558,10 @@ void read_generated_coordinates(const ICompoundProperty &prop, const Imath::V3f &abc_coords = (*abc_ocro)[vertex_idx]; copy_zup_from_yup(orcodata[vertex_idx], abc_coords.getValue()); } + + /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them + * unnormalized, so we need to normalize them. */ + BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false); } void read_custom_data(const std::string &iobject_full_name, |