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:
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc43
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc41
3 files changed, 74 insertions, 20 deletions
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index ccf353595c9..eccb529e4d0 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -44,6 +44,7 @@
* in the write code for the conventions. */
using Alembic::AbcGeom::kFacevaryingScope;
+using Alembic::AbcGeom::kVaryingScope;
using Alembic::AbcGeom::kVertexScope;
using Alembic::Abc::C4fArraySample;
@@ -292,6 +293,7 @@ void write_custom_data(const OCompoundProperty &prop,
using Alembic::Abc::C3fArraySamplePtr;
using Alembic::Abc::C4fArraySamplePtr;
using Alembic::Abc::PropertyHeader;
+using Alembic::Abc::UInt32ArraySamplePtr;
using Alembic::AbcGeom::IC3fGeomParam;
using Alembic::AbcGeom::IC4fGeomParam;
@@ -300,21 +302,26 @@ using Alembic::AbcGeom::IV3fGeomParam;
static void read_uvs(const CDStreamConfig &config,
void *data,
+ const AbcUvScope uv_scope,
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
- const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
+ const UInt32ArraySamplePtr &indices)
{
MPoly *mpolys = config.mpoly;
+ MLoop *mloops = config.mloop;
MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
unsigned int uv_index, loop_index, rev_loop_index;
+ BLI_assert(uv_scope != ABC_UV_SCOPE_NONE);
+ const bool do_uvs_per_loop = (uv_scope == ABC_UV_SCOPE_LOOP);
+
for (int i = 0; i < config.totpoly; i++) {
MPoly &poly = mpolys[i];
unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1;
for (int f = 0; f < poly.totloop; f++) {
- loop_index = poly.loopstart + f;
rev_loop_index = rev_loop_offset - f;
+ loop_index = do_uvs_per_loop ? poly.loopstart + f : mloops[rev_loop_index].v;
uv_index = (*indices)[loop_index];
const Imath::V2f &uv = (*uvs)[uv_index];
@@ -473,13 +480,17 @@ static void read_custom_data_uvs(const ICompoundProperty &prop,
IV2fGeomParam::Sample sample;
uv_param.getIndexed(sample, iss);
- if (uv_param.getScope() != kFacevaryingScope) {
+ UInt32ArraySamplePtr uvs_indices = sample.getIndices();
+
+ const AbcUvScope uv_scope = get_uv_scope(uv_param.getScope(), config, uvs_indices);
+
+ if (uv_scope == ABC_UV_SCOPE_NONE) {
return;
}
void *cd_data = config.add_customdata_cb(config.mesh, prop_header.getName().c_str(), CD_MLOOPUV);
- read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
+ read_uvs(config, cd_data, uv_scope, sample.getVals(), uvs_indices);
}
void read_generated_coordinates(const ICompoundProperty &prop,
@@ -559,4 +570,28 @@ void read_custom_data(const std::string &iobject_full_name,
}
}
+/* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
+ * vertex). The first case is the most common, as this is the standard way of storing this data
+ * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
+ * second case can happen when the mesh is split according to the UV islands, in which case storing
+ * a single UV value per vertex allows to deduplicate data and thus to reduce the file size since
+ * vertices are guaranteed to only have a single UV coordinate. */
+AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
+ const CDStreamConfig &config,
+ const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
+{
+ if (scope == kFacevaryingScope && indices->size() == config.totloop) {
+ return ABC_UV_SCOPE_LOOP;
+ }
+
+ /* kVaryingScope is sometimes used for vertex scopes as the values vary across the vertices. To
+ * be sure, one has to check the size of the data against the number of vertices, as it could
+ * also be a varying attribute across the faces (i.e. one value per face). */
+ if ((scope == kVaryingScope || scope == kVertexScope) && indices->size() == config.totvert) {
+ return ABC_UV_SCOPE_VERTEX;
+ }
+
+ return ABC_UV_SCOPE_NONE;
+}
+
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 9ee964c0545..e9736555ead 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -122,4 +122,14 @@ void read_custom_data(const std::string &iobject_full_name,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);
+typedef enum {
+ ABC_UV_SCOPE_NONE,
+ ABC_UV_SCOPE_LOOP,
+ ABC_UV_SCOPE_VERTEX,
+} AbcUvScope;
+
+AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
+ const CDStreamConfig &config,
+ const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
+
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 11b6c1c18ca..79f34f671c7 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -121,6 +121,7 @@ struct AbcMeshData {
P3fArraySamplePtr positions;
P3fArraySamplePtr ceil_positions;
+ AbcUvScope uv_scope;
V2fArraySamplePtr uvs;
UInt32ArraySamplePtr uvs_indices;
};
@@ -192,8 +193,9 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
- const bool do_uvs = (mloopuvs && uvs && uvs_indices) &&
- (uvs_indices->size() == face_indices->size());
+ const bool do_uvs = (mloopuvs && uvs && uvs_indices);
+ const bool do_uvs_per_loop = do_uvs && mesh_data.uv_scope == ABC_UV_SCOPE_LOOP;
+ BLI_assert(!do_uvs || mesh_data.uv_scope != ABC_UV_SCOPE_NONE);
unsigned int loop_index = 0;
unsigned int rev_loop_index = 0;
unsigned int uv_index = 0;
@@ -227,8 +229,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
if (do_uvs) {
MLoopUV &loopuv = mloopuvs[rev_loop_index];
-
- uv_index = (*uvs_indices)[loop_index];
+ uv_index = (*uvs_indices)[do_uvs_per_loop ? loop_index : loop.v];
/* Some Alembic files are broken (or at least export UVs in a way we don't expect). */
if (uv_index >= uvs_size) {
@@ -357,22 +358,29 @@ BLI_INLINE void read_uvs_params(CDStreamConfig &config,
IV2fGeomParam::Sample uvsamp;
uv.getIndexed(uvsamp, selector);
- abc_data.uvs = uvsamp.getVals();
- abc_data.uvs_indices = uvsamp.getIndices();
+ UInt32ArraySamplePtr uvs_indices = uvsamp.getIndices();
- if (abc_data.uvs_indices->size() == config.totloop) {
- std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
+ const AbcUvScope uv_scope = get_uv_scope(uv.getScope(), config, uvs_indices);
- /* According to the convention, primary UVs should have had their name
- * set using Alembic::Abc::SetSourceName, but you can't expect everyone
- * to follow it! :) */
- if (name.empty()) {
- name = uv.getName();
- }
+ if (uv_scope == ABC_UV_SCOPE_NONE) {
+ return;
+ }
- void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
- config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
+ abc_data.uv_scope = uv_scope;
+ abc_data.uvs = uvsamp.getVals();
+ abc_data.uvs_indices = uvs_indices;
+
+ std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
+
+ /* According to the convention, primary UVs should have had their name
+ * set using Alembic::Abc::SetSourceName, but you can't expect everyone
+ * to follow it! :) */
+ if (name.empty()) {
+ name = uv.getName();
}
+
+ void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
+ config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
}
static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
@@ -462,6 +470,7 @@ CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
config.mvert = mesh->mvert;
config.mloop = mesh->mloop;
config.mpoly = mesh->mpoly;
+ config.totvert = mesh->totvert;
config.totloop = mesh->totloop;
config.totpoly = mesh->totpoly;
config.loopdata = &mesh->ldata;