Merge branch 'master' into blender2.8
[blender.git] / source / blender / alembic / intern / abc_hair.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "abc_hair.h"
24
25 #include <cstdio>
26
27 #include "abc_transform.h"
28 #include "abc_util.h"
29
30 extern "C" {
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_modifier_types.h"
36
37 #include "BLI_listbase.h"
38 #include "BLI_math_geom.h"
39
40 #include "BKE_library.h"
41 #include "BKE_mesh.h"
42 #include "BKE_mesh_runtime.h"
43 #include "BKE_object.h"
44 #include "BKE_particle.h"
45 }
46
47 using Alembic::Abc::P3fArraySamplePtr;
48
49 using Alembic::AbcGeom::OCurves;
50 using Alembic::AbcGeom::OCurvesSchema;
51 using Alembic::AbcGeom::ON3fGeomParam;
52 using Alembic::AbcGeom::OV2fGeomParam;
53
54 /* ************************************************************************** */
55
56 AbcHairWriter::AbcHairWriter(Object *ob,
57                              AbcTransformWriter *parent,
58                              uint32_t time_sampling,
59                              ExportSettings &settings,
60                              ParticleSystem *psys)
61     : AbcObjectWriter(ob, time_sampling, settings, parent)
62     , m_uv_warning_shown(false)
63 {
64         m_psys = psys;
65
66         OCurves curves(parent->alembicXform(), psys->name, m_time_sampling);
67         m_schema = curves.getSchema();
68 }
69
70 void AbcHairWriter::do_write()
71 {
72         if (!m_psys) {
73                 return;
74         }
75         Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, m_settings.scene, m_object, CD_MASK_MESH);
76         BKE_mesh_tessface_ensure(mesh);
77
78         std::vector<Imath::V3f> verts;
79         std::vector<int32_t> hvertices;
80         std::vector<Imath::V2f> uv_values;
81         std::vector<Imath::V3f> norm_values;
82
83         if (m_psys->pathcache) {
84                 ParticleSettings *part = m_psys->part;
85
86                 write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
87
88                 if (m_settings.export_child_hairs && m_psys->childcache) {
89                         write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices);
90                 }
91         }
92
93         Alembic::Abc::P3fArraySample iPos(verts);
94         m_sample = OCurvesSchema::Sample(iPos, hvertices);
95         m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
96         m_sample.setType(Alembic::AbcGeom::kLinear);
97         m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
98
99         if (!uv_values.empty()) {
100                 OV2fGeomParam::Sample uv_smp;
101                 uv_smp.setVals(uv_values);
102                 m_sample.setUVs(uv_smp);
103         }
104
105         if (!norm_values.empty()) {
106                 ON3fGeomParam::Sample norm_smp;
107                 norm_smp.setVals(norm_values);
108                 m_sample.setNormals(norm_smp);
109         }
110
111         m_sample.setSelfBounds(bounds());
112         m_schema.set(m_sample);
113 }
114
115 void AbcHairWriter::write_hair_sample(Mesh *mesh,
116                                       ParticleSettings *part,
117                                       std::vector<Imath::V3f> &verts,
118                                       std::vector<Imath::V3f> &norm_values,
119                                       std::vector<Imath::V2f> &uv_values,
120                                       std::vector<int32_t> &hvertices)
121 {
122         /* Get untransformed vertices, there's a xform under the hair. */
123         float inv_mat[4][4];
124         invert_m4_m4_safe(inv_mat, m_object->obmat);
125
126         MTFace *mtface = mesh->mtface;
127         MFace *mface = mesh->mface;
128         MVert *mverts = mesh->mvert;
129
130         if ((!mtface || !mface) && !m_uv_warning_shown) {
131                 std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n",
132                              m_object->id.name + 2);
133                 m_uv_warning_shown = true;
134         }
135
136         ParticleData *pa = m_psys->particles;
137         int k;
138
139         ParticleCacheKey **cache = m_psys->pathcache;
140         ParticleCacheKey *path;
141         float normal[3];
142         Imath::V3f tmp_nor;
143
144         for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
145                 /* underlying info for faces-only emission */
146                 path = cache[p];
147
148                 /* Write UV and normal vectors */
149                 if (part->from == PART_FROM_FACE && mtface) {
150                         const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
151
152                         if (num < mesh->totface) {
153                                 /* TODO(Sybren): check whether the NULL check here and if(mface) are actually required */
154                                 MFace *face = mface == NULL ? NULL : &mface[num];
155                                 MTFace *tface = mtface + num;
156
157                                 if (mface) {
158                                         float r_uv[2], mapfw[4], vec[3];
159
160                                         psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
161                                         uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
162
163                                         psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL);
164
165                                         copy_yup_from_zup(tmp_nor.getValue(), normal);
166                                         norm_values.push_back(tmp_nor);
167                                 }
168                         }
169                         else {
170                                 std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, mesh->totface);
171                         }
172                 }
173                 else if (part->from == PART_FROM_VERT && mtface) {
174                         /* vertex id */
175                         const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
176
177                         /* iterate over all faces to find a corresponding underlying UV */
178                         for (int n = 0; n < mesh->totface; ++n) {
179                                 MFace *face  = &mface[n];
180                                 MTFace *tface = mtface + n;
181                                 unsigned int vtx[4];
182                                 vtx[0] = face->v1;
183                                 vtx[1] = face->v2;
184                                 vtx[2] = face->v3;
185                                 vtx[3] = face->v4;
186                                 bool found = false;
187
188                                 for (int o = 0; o < 4; ++o) {
189                                         if (o > 2 && vtx[o] == 0) {
190                                                 break;
191                                         }
192
193                                         if (vtx[o] == num) {
194                                                 uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
195
196                                                 MVert *mv = mverts + vtx[o];
197
198                                                 normal_short_to_float_v3(normal, mv->no);
199                                                 copy_yup_from_zup(tmp_nor.getValue(), normal);
200                                                 norm_values.push_back(tmp_nor);
201                                                 found = true;
202                                                 break;
203                                         }
204                                 }
205
206                                 if (found) {
207                                         break;
208                                 }
209                         }
210                 }
211
212                 int steps = path->segments + 1;
213                 hvertices.push_back(steps);
214
215                 for (k = 0; k < steps; ++k, ++path) {
216                         float vert[3];
217                         copy_v3_v3(vert, path->co);
218                         mul_m4_v3(inv_mat, vert);
219
220                         /* Convert Z-up to Y-up. */
221                         verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
222
223                 }
224         }
225 }
226
227 void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
228                                             ParticleSettings *part,
229                                             std::vector<Imath::V3f> &verts,
230                                             std::vector<Imath::V3f> &norm_values,
231                                             std::vector<Imath::V2f> &uv_values,
232                                             std::vector<int32_t> &hvertices)
233 {
234         /* Get untransformed vertices, there's a xform under the hair. */
235         float inv_mat[4][4];
236         invert_m4_m4_safe(inv_mat, m_object->obmat);
237
238         MTFace *mtface = mesh->mtface;
239         MVert *mverts = mesh->mvert;
240
241         ParticleCacheKey **cache = m_psys->childcache;
242         ParticleCacheKey *path;
243
244         ChildParticle *pc = m_psys->child;
245
246         for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
247                 path = cache[p];
248
249                 if (part->from == PART_FROM_FACE &&
250                     part->childtype != PART_CHILD_PARTICLES &&
251                     mtface)
252                 {
253                         const int num = pc->num;
254                         if (num < 0) {
255                                 ABC_LOG(m_settings.logger)
256                                         << "Warning, child particle of hair system " << m_psys->name
257                                         << " has unknown face index of geometry of "<< (m_object->id.name + 2)
258                                         << ", skipping child hair." << std::endl;
259                                 continue;
260                         }
261
262                         MFace *face = &mesh->mface[num];
263                         MTFace *tface = mtface + num;
264
265                         float r_uv[2], tmpnor[3], mapfw[4], vec[3];
266
267                         psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
268                         uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
269
270                         psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL);
271
272                         /* Convert Z-up to Y-up. */
273                         norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
274                 }
275                 else {
276                         if (uv_values.size()) {
277                                 uv_values.push_back(uv_values[pc->parent]);
278                         }
279                         if (norm_values.size()) {
280                                 norm_values.push_back(norm_values[pc->parent]);
281                         }
282                 }
283
284                 int steps = path->segments + 1;
285                 hvertices.push_back(steps);
286
287                 for (int k = 0; k < steps; ++k) {
288                         float vert[3];
289                         copy_v3_v3(vert, path->co);
290                         mul_m4_v3(inv_mat, vert);
291
292                         /* Convert Z-up to Y-up. */
293                         verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
294
295                         ++path;
296                 }
297         }
298 }