2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
20 * ***** END GPL LICENSE BLOCK *****
27 #include "abc_transform.h"
31 #include "MEM_guardedalloc.h"
33 #include "DNA_modifier_types.h"
35 #include "BLI_listbase.h"
36 #include "BLI_math_geom.h"
38 #include "BKE_DerivedMesh.h"
39 #include "BKE_object.h"
40 #include "BKE_particle.h"
43 using Alembic::Abc::P3fArraySamplePtr;
45 using Alembic::AbcGeom::OCurves;
46 using Alembic::AbcGeom::OCurvesSchema;
47 using Alembic::AbcGeom::ON3fGeomParam;
48 using Alembic::AbcGeom::OV2fGeomParam;
50 /* ************************************************************************** */
52 AbcHairWriter::AbcHairWriter(Scene *scene,
54 AbcTransformWriter *parent,
55 uint32_t time_sampling,
56 ExportSettings &settings,
58 : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
62 OCurves curves(parent->alembicXform(), psys->name, m_time_sampling);
63 m_schema = curves.getSchema();
66 void AbcHairWriter::do_write()
72 ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
74 if (!psmd->dm_final) {
78 DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
79 DM_ensure_tessface(dm);
80 DM_update_tessface_data(dm);
82 std::vector<Imath::V3f> verts;
83 std::vector<int32_t> hvertices;
84 std::vector<Imath::V2f> uv_values;
85 std::vector<Imath::V3f> norm_values;
87 if (m_psys->pathcache) {
88 ParticleSettings *part = m_psys->part;
90 write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
92 if (m_settings.export_child_hairs && m_psys->childcache) {
93 write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
99 Alembic::Abc::P3fArraySample iPos(verts);
100 m_sample = OCurvesSchema::Sample(iPos, hvertices);
101 m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
102 m_sample.setType(Alembic::AbcGeom::kLinear);
103 m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
105 if (!uv_values.empty()) {
106 OV2fGeomParam::Sample uv_smp;
107 uv_smp.setVals(uv_values);
108 m_sample.setUVs(uv_smp);
111 if (!norm_values.empty()) {
112 ON3fGeomParam::Sample norm_smp;
113 norm_smp.setVals(norm_values);
114 m_sample.setNormals(norm_smp);
117 m_sample.setSelfBounds(bounds());
118 m_schema.set(m_sample);
121 void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
122 ParticleSettings *part,
123 std::vector<Imath::V3f> &verts,
124 std::vector<Imath::V3f> &norm_values,
125 std::vector<Imath::V2f> &uv_values,
126 std::vector<int32_t> &hvertices)
128 /* Get untransformed vertices, there's a xform under the hair. */
130 invert_m4_m4_safe(inv_mat, m_object->obmat);
132 MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
133 MFace *mface = dm->getTessFaceArray(dm);
134 MVert *mverts = dm->getVertArray(dm);
136 if (!mtface || !mface) {
137 std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
140 ParticleData * pa = m_psys->particles;
143 ParticleCacheKey **cache = m_psys->pathcache;
144 ParticleCacheKey *path;
148 for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
149 /* underlying info for faces-only emission */
152 if (part->from == PART_FROM_FACE && mtface) {
153 const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
155 if (num < dm->getNumTessFaces(dm)) {
156 MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
157 MTFace *tface = mtface + num;
160 float r_uv[2], mapfw[4], vec[3];
162 psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
163 uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
165 psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
167 copy_zup_yup(tmp_nor.getValue(), normal);
168 norm_values.push_back(tmp_nor);
172 std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
175 else if (part->from == PART_FROM_VERT && mtface) {
177 const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
179 /* iterate over all faces to find a corresponding underlying UV */
180 for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
181 MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
182 MTFace *tface = mtface + n;
190 for (int o = 0; o < 4; ++o) {
191 if (o > 2 && vtx[o] == 0) {
196 uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
198 MVert *mv = mverts + vtx[o];
200 normal_short_to_float_v3(normal, mv->no);
201 copy_zup_yup(tmp_nor.getValue(), normal);
202 norm_values.push_back(tmp_nor);
214 int steps = path->segments + 1;
215 hvertices.push_back(steps);
217 for (k = 0; k < steps; ++k) {
219 copy_v3_v3(vert, path->co);
220 mul_m4_v3(inv_mat, vert);
222 /* Convert Z-up to Y-up. */
223 verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
230 void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
231 ParticleSettings *part,
232 std::vector<Imath::V3f> &verts,
233 std::vector<Imath::V3f> &norm_values,
234 std::vector<Imath::V2f> &uv_values,
235 std::vector<int32_t> &hvertices)
237 /* Get untransformed vertices, there's a xform under the hair. */
239 invert_m4_m4_safe(inv_mat, m_object->obmat);
241 MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
242 MFace *mface = dm->getTessFaceArray(dm);
243 MVert *mverts = dm->getVertArray(dm);
245 if (!mtface || !mface) {
246 std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
249 ParticleCacheKey **cache = m_psys->childcache;
250 ParticleCacheKey *path;
252 ChildParticle *pc = m_psys->child;
254 for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
257 if (part->from == PART_FROM_FACE) {
258 const int num = pc->num;
260 MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
261 MTFace *tface = mtface + num;
263 if (mface && mtface) {
264 float r_uv[2], tmpnor[3], mapfw[4], vec[3];
266 psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
267 uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
269 psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
271 /* Convert Z-up to Y-up. */
272 norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
276 int steps = path->segments + 1;
277 hvertices.push_back(steps);
279 for (int k = 0; k < steps; ++k) {
281 copy_v3_v3(vert, path->co);
282 mul_m4_v3(inv_mat, vert);
284 /* Convert Z-up to Y-up. */
285 verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));