Blender  V3.3
abc_reader_object.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "abc_reader_object.h"
8 #include "abc_axis_conversion.h"
9 #include "abc_util.h"
10 
11 #include "DNA_cachefile_types.h"
12 #include "DNA_constraint_types.h"
13 #include "DNA_modifier_types.h"
14 #include "DNA_space_types.h" /* for FILE_MAX */
15 
16 #include "BKE_constraint.h"
17 #include "BKE_lib_id.h"
18 #include "BKE_modifier.h"
19 #include "BKE_object.h"
20 
21 #include "BLI_listbase.h"
22 #include "BLI_math_geom.h"
23 #include "BLI_string.h"
24 #include "BLI_utildefines.h"
25 
26 using Alembic::AbcGeom::IObject;
27 using Alembic::AbcGeom::IXform;
28 using Alembic::AbcGeom::IXformSchema;
29 
30 namespace blender::io::alembic {
31 
32 AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
33  : m_object(nullptr),
34  m_iobject(object),
35  m_settings(&settings),
36  m_min_time(std::numeric_limits<chrono_t>::max()),
37  m_max_time(std::numeric_limits<chrono_t>::min()),
38  m_refcount(0),
39  parent_reader(nullptr)
40 {
41  m_name = object.getFullName();
42  std::vector<std::string> parts;
43  split(m_name, '/', parts);
44 
45  if (parts.size() >= 2) {
46  m_object_name = parts[parts.size() - 2];
47  m_data_name = parts[parts.size() - 1];
48  }
49  else {
50  m_object_name = m_data_name = parts[parts.size() - 1];
51  }
52 
54 }
55 
57 {
58  m_inherits_xform = false;
59 
60  IXform ixform = xform();
61  if (!ixform) {
62  return;
63  }
64 
65  const IXformSchema &schema(ixform.getSchema());
66  if (!schema.valid()) {
67  std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema."
68  << std::endl;
69  return;
70  }
71 
72  m_inherits_xform = schema.getInheritsXforms();
73 
74  IObject ixform_parent = ixform.getParent();
75  if (!ixform_parent.getParent()) {
76  /* The archive top object certainly is not a transform itself, so handle
77  * it as "no parent". */
78  m_inherits_xform = false;
79  }
80  else {
81  m_inherits_xform = ixform_parent && m_inherits_xform;
82  }
83 }
84 
85 const IObject &AbcObjectReader::iobject() const
86 {
87  return m_iobject;
88 }
89 
91 {
92  return m_object;
93 }
94 
96 {
97  m_object = ob;
98 }
99 
100 static Imath::M44d blend_matrices(const Imath::M44d &m0,
101  const Imath::M44d &m1,
102  const double weight)
103 {
104  float mat0[4][4], mat1[4][4], ret[4][4];
105 
106  /* Cannot use Imath::M44d::getValue() since this returns a pointer to
107  * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
108  * the matrices manually.
109  */
110 
111  convert_matrix_datatype(m0, mat0);
112  convert_matrix_datatype(m1, mat1);
113  interp_m4_m4m4(ret, mat0, mat1, static_cast<float>(weight));
115 }
116 
117 Imath::M44d get_matrix(const IXformSchema &schema, const chrono_t time)
118 {
119  Alembic::AbcGeom::index_t i0, i1;
120  Alembic::AbcGeom::XformSample s0, s1;
121 
122  const double weight = get_weight_and_index(
123  time, schema.getTimeSampling(), schema.getNumSamples(), i0, i1);
124 
125  schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
126 
127  if (i0 != i1) {
128  schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
129  return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
130  }
131 
132  return s0.getMatrix();
133 }
134 
135 struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
136  const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
137  int UNUSED(read_flag),
138  const char *UNUSED(velocity_name),
139  const float UNUSED(velocity_scale),
140  const char **UNUSED(err_str))
141 {
142  return existing_mesh;
143 }
144 
145 bool AbcObjectReader::topology_changed(const Mesh * /*existing_mesh*/,
146  const Alembic::Abc::ISampleSelector & /*sample_sel*/)
147 {
148  /* The default implementation of read_mesh() just returns the original mesh, so never changes the
149  * topology. */
150  return false;
151 }
152 
154 {
155  bool is_constant = false;
156  float transform_from_alembic[4][4];
157 
158  /* If the parent is a camera, apply the inverse rotation to make up for the from-Maya rotation.
159  * This assumes that the parent object also was imported from Alembic. */
160  if (m_object->parent != nullptr && m_object->parent->type == OB_CAMERA) {
162  }
163 
164  this->read_matrix(transform_from_alembic, time, m_settings->scale, is_constant);
165 
166  /* Apply the matrix to the object. */
167  BKE_object_apply_mat4(m_object, transform_from_alembic, true, false);
169 
170  if (!is_constant || m_settings->always_add_cache_reader) {
174  BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
175 
176  data->cache_file = m_settings->cache_file;
177  id_us_plus(&data->cache_file->id);
178  }
179 }
180 
181 Alembic::AbcGeom::IXform AbcObjectReader::xform()
182 {
183  /* Check that we have an empty object (locator, bone head/tail...). */
184  if (IXform::matches(m_iobject.getMetaData())) {
185  try {
186  return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
187  }
188  catch (Alembic::Util::Exception &ex) {
189  printf("Alembic: error reading object transform for '%s': %s\n",
190  m_iobject.getFullName().c_str(),
191  ex.what());
192  return IXform();
193  }
194  }
195 
196  /* Check that we have an object with actual data, in which case the
197  * parent Alembic object should contain the transform. */
198  IObject abc_parent = m_iobject.getParent();
199 
200  /* The archive's top object can be recognized by not having a parent. */
201  if (abc_parent.getParent() && IXform::matches(abc_parent.getMetaData())) {
202  try {
203  return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
204  }
205  catch (Alembic::Util::Exception &ex) {
206  printf("Alembic: error reading object transform for '%s': %s\n",
207  abc_parent.getFullName().c_str(),
208  ex.what());
209  return IXform();
210  }
211  }
212 
213  /* This can happen in certain cases. For example, MeshLab exports
214  * point clouds without parent XForm. */
215  return IXform();
216 }
217 
218 void AbcObjectReader::read_matrix(float r_mat[4][4] /* local matrix */,
219  const chrono_t time,
220  const float scale,
221  bool &r_is_constant)
222 {
223  IXform ixform = xform();
224  if (!ixform) {
225  unit_m4(r_mat);
226  r_is_constant = true;
227  return;
228  }
229 
230  const IXformSchema &schema(ixform.getSchema());
231  if (!schema.valid()) {
232  std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema."
233  << std::endl;
234  return;
235  }
236 
237  const Imath::M44d matrix = get_matrix(schema, time);
238  convert_matrix_datatype(matrix, r_mat);
239  copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
240 
241  /* Convert from Maya to Blender camera orientation. Children of this camera
242  * will have the opposite transform as their Parent Inverse matrix.
243  * See AbcObjectReader::setupObjectTransform(). */
244  if (m_object->type == OB_CAMERA) {
245  float camera_rotation[4][4];
246  axis_angle_to_mat4_single(camera_rotation, 'X', M_PI_2);
247  mul_m4_m4m4(r_mat, r_mat, camera_rotation);
248  }
249 
250  if (!m_inherits_xform) {
251  /* Only apply scaling to root objects, parenting will propagate it. */
252  float scale_mat[4][4];
253  scale_m4_fl(scale_mat, scale);
254  mul_m4_m4m4(r_mat, scale_mat, r_mat);
255  }
256 
257  r_is_constant = schema.isConstant();
258 }
259 
261 {
264 
265  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
266 
268  id_us_plus(&mcmd->cache_file->id);
269 
270  BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
271 }
272 
273 chrono_t AbcObjectReader::minTime() const
274 {
275  return m_min_time;
276 }
277 
278 chrono_t AbcObjectReader::maxTime() const
279 {
280  return m_max_time;
281 }
282 
284 {
285  return m_refcount;
286 }
287 
289 {
290  m_refcount++;
291 }
292 
294 {
295  m_refcount--;
296  BLI_assert(m_refcount >= 0);
297 }
298 
299 } // namespace blender::io::alembic
struct bConstraint * BKE_constraint_add_for_object(struct Object *ob, const char *name, short type)
Definition: constraint.c:5870
void id_us_plus(struct ID *id)
Definition: lib_id.c:305
struct ModifierData * BKE_modifier_new(int type)
General operations, lookup, etc. for blender objects.
void BKE_object_to_mat4(struct Object *ob, float r_mat[4][4])
Definition: object.cc:3082
void BKE_object_apply_mat4(struct Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
Definition: object.cc:3575
#define BLI_assert(a)
Definition: BLI_assert.h:46
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
#define M_PI_2
Definition: BLI_math_base.h:23
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], float t)
Definition: math_matrix.c:2481
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void unit_m4(float m[4][4])
Definition: rct.c:1090
void scale_m4_fl(float R[4][4], float scale)
Definition: math_matrix.c:2297
void axis_angle_to_mat4_single(float R[4][4], char axis, float angle)
#define FILE_MAX
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define UNUSED(x)
@ CONSTRAINT_TYPE_TRANSFORM_CACHE
@ eModifierType_MeshSequenceCache
@ OB_CAMERA
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
void read_matrix(float r_mat[4][4], chrono_t time, float scale, bool &is_constant)
const Alembic::Abc::IObject & iobject() const
virtual bool topology_changed(const Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel)
virtual Alembic::AbcGeom::IXform xform()
virtual struct Mesh * read_mesh(struct Mesh *mesh, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **err_str)
double time
static void get_weight_and_index(CDStreamConfig &config, Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling, size_t samples_number)
Imath::M44d get_matrix(const IXformSchema &schema, const chrono_t time)
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const double weight)
Imath::M44d convert_matrix_datatype(float mat[4][4])
Definition: abc_util.cc:70
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:92
return ret
#define min(a, b)
Definition: sort.c:35
struct CacheFile * cache_file
ListBase modifiers
float parentinv[4][4]
float obmat[4][4]
struct Object * parent
float max