Blender  V2.93
abc_reader_object.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include "abc_reader_object.h"
22 #include "abc_axis_conversion.h"
23 #include "abc_util.h"
24 
25 #include "DNA_cachefile_types.h"
26 #include "DNA_constraint_types.h"
27 #include "DNA_modifier_types.h"
28 #include "DNA_space_types.h" /* for FILE_MAX */
29 
30 #include "BKE_constraint.h"
31 #include "BKE_lib_id.h"
32 #include "BKE_modifier.h"
33 #include "BKE_object.h"
34 
35 #include "BLI_listbase.h"
36 #include "BLI_math_geom.h"
37 #include "BLI_string.h"
38 #include "BLI_utildefines.h"
39 
40 using Alembic::AbcGeom::IObject;
41 using Alembic::AbcGeom::IXform;
42 using Alembic::AbcGeom::IXformSchema;
43 
44 namespace blender::io::alembic {
45 
46 AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
47  : m_object(nullptr),
48  m_iobject(object),
49  m_settings(&settings),
50  m_min_time(std::numeric_limits<chrono_t>::max()),
51  m_max_time(std::numeric_limits<chrono_t>::min()),
52  m_refcount(0),
53  parent_reader(nullptr)
54 {
55  m_name = object.getFullName();
56  std::vector<std::string> parts;
57  split(m_name, '/', parts);
58 
59  if (parts.size() >= 2) {
60  m_object_name = parts[parts.size() - 2];
61  m_data_name = parts[parts.size() - 1];
62  }
63  else {
64  m_object_name = m_data_name = parts[parts.size() - 1];
65  }
66 
68 }
69 
70 /* Determine whether we can inherit our parent's XForm */
72 {
73  m_inherits_xform = false;
74 
75  IXform ixform = xform();
76  if (!ixform) {
77  return;
78  }
79 
80  const IXformSchema &schema(ixform.getSchema());
81  if (!schema.valid()) {
82  std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema."
83  << std::endl;
84  return;
85  }
86 
87  m_inherits_xform = schema.getInheritsXforms();
88 
89  IObject ixform_parent = ixform.getParent();
90  if (!ixform_parent.getParent()) {
91  /* The archive top object certainly is not a transform itself, so handle
92  * it as "no parent". */
93  m_inherits_xform = false;
94  }
95  else {
96  m_inherits_xform = ixform_parent && m_inherits_xform;
97  }
98 }
99 
100 const IObject &AbcObjectReader::iobject() const
101 {
102  return m_iobject;
103 }
104 
106 {
107  return m_object;
108 }
109 
111 {
112  m_object = ob;
113 }
114 
115 static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
116 {
117  float mat0[4][4], mat1[4][4], ret[4][4];
118 
119  /* Cannot use Imath::M44d::getValue() since this returns a pointer to
120  * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
121  * the matrices manually.
122  */
123 
124  for (int i = 0; i < 4; i++) {
125  for (int j = 0; j < 4; j++) {
126  mat0[i][j] = static_cast<float>(m0[i][j]);
127  }
128  }
129 
130  for (int i = 0; i < 4; i++) {
131  for (int j = 0; j < 4; j++) {
132  mat1[i][j] = static_cast<float>(m1[i][j]);
133  }
134  }
135 
136  interp_m4_m4m4(ret, mat0, mat1, weight);
137 
138  Imath::M44d m;
139 
140  for (int i = 0; i < 4; i++) {
141  for (int j = 0; j < 4; j++) {
142  m[i][j] = ret[i][j];
143  }
144  }
145 
146  return m;
147 }
148 
149 Imath::M44d get_matrix(const IXformSchema &schema, const float time)
150 {
151  Alembic::AbcGeom::index_t i0, i1;
152  Alembic::AbcGeom::XformSample s0, s1;
153 
154  const float weight = get_weight_and_index(
155  time, schema.getTimeSampling(), schema.getNumSamples(), i0, i1);
156 
157  schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
158 
159  if (i0 != i1) {
160  schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
161  return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
162  }
163 
164  return s0.getMatrix();
165 }
166 
167 struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
168  const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
169  int UNUSED(read_flag),
170  const char **UNUSED(err_str))
171 {
172  return existing_mesh;
173 }
174 
175 bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
176  const Alembic::Abc::ISampleSelector & /*sample_sel*/)
177 {
178  /* The default implementation of read_mesh() just returns the original mesh, so never changes the
179  * topology. */
180  return false;
181 }
182 
184 {
185  bool is_constant = false;
186  float transform_from_alembic[4][4];
187 
188  /* If the parent is a camera, apply the inverse rotation to make up for the from-Maya rotation.
189  * This assumes that the parent object also was imported from Alembic. */
190  if (m_object->parent != nullptr && m_object->parent->type == OB_CAMERA) {
192  }
193 
194  this->read_matrix(transform_from_alembic, time, m_settings->scale, is_constant);
195 
196  /* Apply the matrix to the object. */
197  BKE_object_apply_mat4(m_object, transform_from_alembic, true, false);
199 
200  if (!is_constant) {
204  BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
205 
206  data->cache_file = m_settings->cache_file;
207  id_us_plus(&data->cache_file->id);
208  }
209 }
210 
211 Alembic::AbcGeom::IXform AbcObjectReader::xform()
212 {
213  /* Check that we have an empty object (locator, bone head/tail...). */
214  if (IXform::matches(m_iobject.getMetaData())) {
215  try {
216  return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
217  }
218  catch (Alembic::Util::Exception &ex) {
219  printf("Alembic: error reading object transform for '%s': %s\n",
220  m_iobject.getFullName().c_str(),
221  ex.what());
222  return IXform();
223  }
224  }
225 
226  /* Check that we have an object with actual data, in which case the
227  * parent Alembic object should contain the transform. */
228  IObject abc_parent = m_iobject.getParent();
229 
230  /* The archive's top object can be recognized by not having a parent. */
231  if (abc_parent.getParent() && IXform::matches(abc_parent.getMetaData())) {
232  try {
233  return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
234  }
235  catch (Alembic::Util::Exception &ex) {
236  printf("Alembic: error reading object transform for '%s': %s\n",
237  abc_parent.getFullName().c_str(),
238  ex.what());
239  return IXform();
240  }
241  }
242 
243  /* This can happen in certain cases. For example, MeshLab exports
244  * point clouds without parent XForm. */
245  return IXform();
246 }
247 
248 void AbcObjectReader::read_matrix(float r_mat[4][4] /* local matrix */,
249  const float time,
250  const float scale,
251  bool &is_constant)
252 {
253  IXform ixform = xform();
254  if (!ixform) {
255  unit_m4(r_mat);
256  is_constant = true;
257  return;
258  }
259 
260  const IXformSchema &schema(ixform.getSchema());
261  if (!schema.valid()) {
262  std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema."
263  << std::endl;
264  return;
265  }
266 
267  const Imath::M44d matrix = get_matrix(schema, time);
268  convert_matrix_datatype(matrix, r_mat);
269  copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
270 
271  /* Convert from Maya to Blender camera orientation. Children of this camera
272  * will have the opposite transform as their Parent Inverse matrix.
273  * See AbcObjectReader::setupObjectTransform(). */
274  if (m_object->type == OB_CAMERA) {
275  float camera_rotation[4][4];
276  axis_angle_to_mat4_single(camera_rotation, 'X', M_PI_2);
277  mul_m4_m4m4(r_mat, r_mat, camera_rotation);
278  }
279 
280  if (!m_inherits_xform) {
281  /* Only apply scaling to root objects, parenting will propagate it. */
282  float scale_mat[4][4];
283  scale_m4_fl(scale_mat, scale);
284  mul_m4_m4m4(r_mat, scale_mat, r_mat);
285  }
286 
287  is_constant = schema.isConstant();
288 }
289 
291 {
294 
295  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
296 
298  id_us_plus(&mcmd->cache_file->id);
299 
300  BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
301 }
302 
303 chrono_t AbcObjectReader::minTime() const
304 {
305  return m_min_time;
306 }
307 
308 chrono_t AbcObjectReader::maxTime() const
309 {
310  return m_max_time;
311 }
312 
314 {
315  return m_refcount;
316 }
317 
319 {
320  m_refcount++;
321 }
322 
324 {
325  m_refcount--;
326  BLI_assert(m_refcount >= 0);
327 }
328 
329 } // namespace blender::io::alembic
struct bConstraint * BKE_constraint_add_for_object(struct Object *ob, const char *name, short type)
Definition: constraint.c:5672
void id_us_plus(struct ID *id)
Definition: lib_id.c:288
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.c:3234
void BKE_object_apply_mat4(struct Object *ob, const float mat[4][4], const bool use_compat, const bool use_parent)
Definition: object.c:3754
#define BLI_assert(a)
Definition: BLI_assert.h:58
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
#define M_PI_2
Definition: BLI_math_base.h:41
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void unit_m4(float m[4][4])
Definition: rct.c:1140
void scale_m4_fl(float R[4][4], float scale)
Definition: math_matrix.c:2309
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t)
Definition: math_matrix.c:2562
void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle)
#define FILE_MAX
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#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
virtual struct Mesh * read_mesh(struct Mesh *mesh, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char **err_str)
AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
const Alembic::Abc::IObject & iobject() const
virtual Alembic::AbcGeom::IXform xform()
virtual bool topology_changed(Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel)
void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant)
double time
static void get_weight_and_index(CDStreamConfig &config, Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling, size_t samples_number)
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
Imath::M44d get_matrix(const IXformSchema &schema, const float time)
Imath::M44d convert_matrix_datatype(float mat[4][4])
Definition: abc_util.cc:93
static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
return ret
#define min(a, b)
Definition: sort.c:51
struct CacheFile * cache_file
ListBase modifiers
float parentinv[4][4]
float obmat[4][4]
struct Object * parent
float max