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
path: root/source
diff options
context:
space:
mode:
authorKévin Dietrich <kevin.dietrich@mailoo.org>2021-11-22 14:04:37 +0300
committerKévin Dietrich <kevin.dietrich@mailoo.org>2021-12-01 14:44:32 +0300
commit02ab4ad991906f817698d3810c3d464cfaedcaff (patch)
tree1ce39dfc6dc73a16d8912b437bd816d6f01f9620 /source
parentfd224048375bf7a9d970c226b7ac843458d5428e (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')
-rw-r--r--source/blender/blenkernel/BKE_mesh.h4
-rw-r--r--source/blender/blenkernel/intern/mesh.cc12
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c7
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc20
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
5 files changed, 34 insertions, 12 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index be9b84ccd62..135f8128b9a 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -136,6 +136,10 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
+
+/* Add a CD_ORCO layer to the Mesh if there is none already. */
+void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh);
+
int BKE_mesh_mface_index_validate(struct MFace *mface,
struct CustomData *mfdata,
int mfindex,
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 24739233ea5..c367602f037 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -1332,6 +1332,18 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
}
}
+void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh)
+{
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ return;
+ }
+
+ /* Orcos are stored in normalized 0..1 range by convention. */
+ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
+}
+
/**
* Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
* this is necessary to make the if #MFace.v4 check for quads work.
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 863476c6638..fd4f89e3f6d 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -997,12 +997,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
- /* Orcos are stored in normalized 0..1 range by convention. */
- float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
- BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
- CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
- }
+ BKE_mesh_orco_ensure(ob, mesh);
if (from == PART_FROM_VERT) {
MVert *mv = mesh->mvert;
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,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index d57e92b4b35..194e7ac2a68 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -219,8 +219,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
if (use_orco) {
- CustomData_add_layer(
- &mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
+ BKE_mesh_orco_ensure(ob, mesh);
}
}
else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {