Cycles code refactor: improve vertex motion attribute storage and export.
[blender.git] / intern / cycles / blender / blender_mesh.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16
17  
18 #include "mesh.h"
19 #include "object.h"
20 #include "scene.h"
21
22 #include "blender_sync.h"
23 #include "blender_util.h"
24
25 #include "subd_mesh.h"
26 #include "subd_patch.h"
27 #include "subd_split.h"
28
29 #include "util_foreach.h"
30
31 #include "mikktspace.h"
32
33 CCL_NAMESPACE_BEGIN
34
35 /* Tangent Space */
36
37 struct MikkUserData {
38         MikkUserData(const BL::Mesh mesh_, const BL::MeshTextureFaceLayer layer_, int num_faces_)
39         : mesh(mesh_), layer(layer_), num_faces(num_faces_)
40         {
41                 tangent.resize(num_faces*4);
42         }
43
44         BL::Mesh mesh;
45         BL::MeshTextureFaceLayer layer;
46         int num_faces;
47         vector<float4> tangent;
48 };
49
50 static int mikk_get_num_faces(const SMikkTSpaceContext *context)
51 {
52         MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
53         return userdata->num_faces;
54 }
55
56 static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num)
57 {
58         MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
59         BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
60         int4 vi = get_int4(f.vertices_raw());
61
62         return (vi[3] == 0)? 3: 4;
63 }
64
65 static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], const int face_num, const int vert_num)
66 {
67         MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
68         BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
69         int4 vi = get_int4(f.vertices_raw());
70         BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
71         float3 vP = get_float3(v.co());
72
73         P[0] = vP.x;
74         P[1] = vP.y;
75         P[2] = vP.z;
76 }
77
78 static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float uv[2], const int face_num, const int vert_num)
79 {
80         MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
81         BL::MeshTextureFace tf = userdata->layer.data[face_num];
82         float3 tfuv;
83         
84         switch (vert_num) {
85                 case 0:
86                         tfuv = get_float3(tf.uv1());
87                         break;
88                 case 1:
89                         tfuv = get_float3(tf.uv2());
90                         break;
91                 case 2:
92                         tfuv = get_float3(tf.uv3());
93                         break;
94                 default:
95                         tfuv = get_float3(tf.uv4());
96                         break;
97         }
98         
99         uv[0] = tfuv.x;
100         uv[1] = tfuv.y;
101 }
102
103 static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const int face_num, const int vert_num)
104 {
105         MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
106         BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
107         float3 vN;
108
109         if(f.use_smooth()) {
110                 int4 vi = get_int4(f.vertices_raw());
111                 BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
112                 vN = get_float3(v.normal());
113         }
114         else {
115                 vN = get_float3(f.normal());
116         }
117
118         N[0] = vN.x;
119         N[1] = vN.y;
120         N[2] = vN.z;
121 }
122
123 static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const float T[], const float sign, const int face, const int vert)
124 {
125         MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
126
127         userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign);
128 }
129
130 static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_layer, Mesh *mesh, vector<int>& nverts, bool need_sign, bool active_render)
131 {
132         /* setup userdata */
133         MikkUserData userdata(b_mesh, b_layer, nverts.size());
134
135         /* setup interface */
136         SMikkTSpaceInterface sm_interface;
137         memset(&sm_interface, 0, sizeof(sm_interface));
138         sm_interface.m_getNumFaces = mikk_get_num_faces;
139         sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face;
140         sm_interface.m_getPosition = mikk_get_position;
141         sm_interface.m_getTexCoord = mikk_get_texture_coordinate;
142         sm_interface.m_getNormal = mikk_get_normal;
143         sm_interface.m_setTSpaceBasic = mikk_set_tangent_space;
144
145         /* setup context */
146         SMikkTSpaceContext context;
147         memset(&context, 0, sizeof(context));
148         context.m_pUserData = &userdata;
149         context.m_pInterface = &sm_interface;
150
151         /* compute tangents */
152         genTangSpaceDefault(&context);
153
154         /* create tangent attributes */
155         Attribute *attr;
156         ustring name = ustring((string(b_layer.name().c_str()) + ".tangent").c_str());
157
158         if(active_render)
159                 attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name);
160         else
161                 attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
162
163         float3 *tangent = attr->data_float3();
164
165         /* create bitangent sign attribute */
166         float *tangent_sign = NULL;
167
168         if(need_sign) {
169                 Attribute *attr_sign;
170                 ustring name_sign = ustring((string(b_layer.name().c_str()) + ".tangent_sign").c_str());
171
172                 if(active_render)
173                         attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
174                 else
175                         attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
176
177                 tangent_sign = attr_sign->data_float();
178         }
179
180         for(int i = 0; i < nverts.size(); i++) {
181                 tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]);
182                 tangent[1] = float4_to_float3(userdata.tangent[i*4 + 1]);
183                 tangent[2] = float4_to_float3(userdata.tangent[i*4 + 2]);
184                 tangent += 3;
185
186                 if(tangent_sign) {
187                         tangent_sign[0] = userdata.tangent[i*4 + 0].w;
188                         tangent_sign[1] = userdata.tangent[i*4 + 1].w;
189                         tangent_sign[2] = userdata.tangent[i*4 + 2].w;
190                         tangent_sign += 3;
191                 }
192
193                 if(nverts[i] == 4) {
194                         tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]);
195                         tangent[1] = float4_to_float3(userdata.tangent[i*4 + 2]);
196                         tangent[2] = float4_to_float3(userdata.tangent[i*4 + 3]);
197                         tangent += 3;
198
199                         if(tangent_sign) {
200                                 tangent_sign[0] = userdata.tangent[i*4 + 0].w;
201                                 tangent_sign[1] = userdata.tangent[i*4 + 2].w;
202                                 tangent_sign[2] = userdata.tangent[i*4 + 3].w;
203                                 tangent_sign += 3;
204                         }
205                 }
206         }
207 }
208
209 /* Create Mesh */
210
211 static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
212 {
213         /* count vertices and faces */
214         int numverts = b_mesh.vertices.length();
215         int numfaces = b_mesh.tessfaces.length();
216         int numtris = 0;
217
218         BL::Mesh::vertices_iterator v;
219         BL::Mesh::tessfaces_iterator f;
220
221         for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
222                 int4 vi = get_int4(f->vertices_raw());
223                 numtris += (vi[3] == 0)? 1: 2;
224         }
225
226         /* reserve memory */
227         mesh->reserve(numverts, numtris, 0, 0);
228
229         /* create vertex coordinates and normals */
230         int i = 0;
231         for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i)
232                 mesh->verts[i] = get_float3(v->co());
233
234         Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
235         float3 *N = attr_N->data_float3();
236
237         for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
238                 *N = get_float3(v->normal());
239
240         /* create faces */
241         vector<int> nverts(numfaces);
242         int fi = 0, ti = 0;
243
244         for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
245                 int4 vi = get_int4(f->vertices_raw());
246                 int n = (vi[3] == 0)? 3: 4;
247                 int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
248                 int shader = used_shaders[mi];
249                 bool smooth = f->use_smooth();
250
251                 if(n == 4) {
252                         if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
253                                 is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) {
254                                 mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
255                                 mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
256                         }
257                         else {
258                                 mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
259                                 mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth);
260                         }
261                 }
262                 else
263                         mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
264
265                 nverts[fi] = n;
266         }
267
268         /* create vertex color attributes */
269         {
270                 BL::Mesh::tessface_vertex_colors_iterator l;
271
272                 for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
273                         if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
274                                 continue;
275
276                         Attribute *attr = mesh->attributes.add(
277                                 ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
278
279                         BL::MeshColorLayer::data_iterator c;
280                         float3 *fdata = attr->data_float3();
281                         size_t i = 0;
282
283                         for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
284                                 fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
285                                 fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
286                                 fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));
287
288                                 if(nverts[i] == 4) {
289                                         fdata[3] = fdata[0];
290                                         fdata[4] = fdata[2];
291                                         fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
292                                         fdata += 6;
293                                 }
294                                 else
295                                         fdata += 3;
296                         }
297                 }
298         }
299
300         /* create uv map attributes */
301         {
302                 BL::Mesh::tessface_uv_textures_iterator l;
303
304                 for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
305                         bool active_render = l->active_render();
306                         AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
307                         ustring name = ustring(l->name().c_str());
308
309                         /* UV map */
310                         if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
311                                 Attribute *attr;
312
313                                 if(active_render)
314                                         attr = mesh->attributes.add(std, name);
315                                 else
316                                         attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
317
318                                 BL::MeshTextureFaceLayer::data_iterator t;
319                                 float3 *fdata = attr->data_float3();
320                                 size_t i = 0;
321
322                                 for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
323                                         fdata[0] =  get_float3(t->uv1());
324                                         fdata[1] =  get_float3(t->uv2());
325                                         fdata[2] =  get_float3(t->uv3());
326                                         fdata += 3;
327
328                                         if(nverts[i] == 4) {
329                                                 fdata[0] =  get_float3(t->uv1());
330                                                 fdata[1] =  get_float3(t->uv3());
331                                                 fdata[2] =  get_float3(t->uv4());
332                                                 fdata += 3;
333                                         }
334                                 }
335                         }
336
337                         /* UV tangent */
338                         std = (active_render)? ATTR_STD_UV_TANGENT: ATTR_STD_NONE;
339                         name = ustring((string(l->name().c_str()) + ".tangent").c_str());
340
341                         if(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, std))) {
342                                 std = (active_render)? ATTR_STD_UV_TANGENT_SIGN: ATTR_STD_NONE;
343                                 name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
344                                 bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std));
345
346                                 mikk_compute_tangents(b_mesh, *l, mesh, nverts, need_sign, active_render);
347                         }
348                 }
349         }
350
351         /* create generated coordinates from undeformed coordinates */
352         if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
353                 Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
354
355                 float3 loc, size;
356                 mesh_texture_space(b_mesh, loc, size);
357
358                 float3 *generated = attr->data_float3();
359                 size_t i = 0;
360
361                 for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
362                         generated[i++] = get_float3(v->undeformed_co())*size - loc;
363         }
364
365         /* for volume objects, create a matrix to transform from object space to
366          * mesh texture space. this does not work with deformations but that can
367          * probably only be done well with a volume grid mapping of coordinates */
368         if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
369                 Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
370                 Transform *tfm = attr->data_transform();
371
372                 float3 loc, size;
373                 mesh_texture_space(b_mesh, loc, size);
374
375                 *tfm = transform_translate(-loc)*transform_scale(size);
376         }
377 }
378
379 static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
380 {
381         /* create subd mesh */
382         SubdMesh sdmesh;
383
384         /* create vertices */
385         BL::Mesh::vertices_iterator v;
386
387         for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
388                 sdmesh.add_vert(get_float3(v->co()));
389
390         /* create faces */
391         BL::Mesh::tessfaces_iterator f;
392
393         for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
394                 int4 vi = get_int4(f->vertices_raw());
395                 int n = (vi[3] == 0) ? 3: 4;
396                 //int shader = used_shaders[f->material_index()];
397
398                 if(n == 4)
399                         sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
400                 else
401                         sdmesh.add_face(vi[0], vi[1], vi[2]);
402         }
403
404         /* finalize subd mesh */
405         sdmesh.finish();
406
407         /* parameters */
408         bool need_ptex = mesh->need_attribute(scene, ATTR_STD_PTEX_FACE_ID) ||
409                          mesh->need_attribute(scene, ATTR_STD_PTEX_UV);
410
411         SubdParams sdparams(mesh, used_shaders[0], true, need_ptex);
412         sdparams.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
413         //scene->camera->update();
414         //sdparams.camera = scene->camera;
415
416         /* tesselate */
417         DiagSplit dsplit(sdparams);
418         sdmesh.tessellate(&dsplit);
419 }
420
421 /* Sync */
422
423 Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
424 {
425         /* test if we can instance or if the object is modified */
426         BL::ID b_ob_data = b_ob.data();
427         BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
428         BL::Material material_override = render_layer.material_override;
429
430         /* find shader indices */
431         vector<uint> used_shaders;
432
433         BL::Object::material_slots_iterator slot;
434         for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
435                 if(material_override)
436                         find_shader(material_override, used_shaders, scene->default_surface);
437                 else
438                         find_shader(slot->material(), used_shaders, scene->default_surface);
439         }
440
441         if(used_shaders.size() == 0) {
442                 if(material_override)
443                         find_shader(material_override, used_shaders, scene->default_surface);
444                 else
445                         used_shaders.push_back(scene->default_surface);
446         }
447         
448         /* test if we need to sync */
449         Mesh *mesh;
450
451         if(!mesh_map.sync(&mesh, key)) {
452                 
453                 /* if transform was applied to mesh, need full update */
454                 if(object_updated && mesh->transform_applied);
455                 /* test if shaders changed, these can be object level so mesh
456                  * does not get tagged for recalc */
457                 else if(mesh->used_shaders != used_shaders);
458                 else {
459                         /* even if not tagged for recalc, we may need to sync anyway
460                          * because the shader needs different mesh attributes */
461                         bool attribute_recalc = false;
462
463                         foreach(uint shader, mesh->used_shaders)
464                                 if(scene->shaders[shader]->need_update_attributes)
465                                         attribute_recalc = true;
466
467                         if(!attribute_recalc)
468                                 return mesh;
469                 }
470         }
471
472         /* ensure we only sync instanced meshes once */
473         if(mesh_synced.find(mesh) != mesh_synced.end())
474                 return mesh;
475         
476         mesh_synced.insert(mesh);
477
478         /* create derived mesh */
479         PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
480
481         vector<Mesh::Triangle> oldtriangle = mesh->triangles;
482         
483         /* compares curve_keys rather than strands in order to handle quick hair
484          * adjustsments in dynamic BVH - other methods could probably do this better*/
485         vector<float4> oldcurve_keys = mesh->curve_keys;
486
487         mesh->clear();
488         mesh->used_shaders = used_shaders;
489         mesh->name = ustring(b_ob_data.name().c_str());
490
491         if(render_layer.use_surfaces || render_layer.use_hair) {
492                 if(preview)
493                         b_ob.update_from_editmode();
494
495                 bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
496                 BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
497
498                 if(b_mesh) {
499                         if(render_layer.use_surfaces && !hide_tris) {
500                                 if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
501                                         create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders);
502                                 else
503                                         create_mesh(scene, mesh, b_mesh, used_shaders);
504                         }
505
506                         if(render_layer.use_hair)
507                                 sync_curves(mesh, b_mesh, b_ob, false);
508
509                         /* free derived mesh */
510                         b_data.meshes.remove(b_mesh);
511                 }
512         }
513
514         /* displacement method */
515         if(cmesh.data) {
516                 const int method = RNA_enum_get(&cmesh, "displacement_method");
517
518                 if(method == 0 || !experimental)
519                         mesh->displacement_method = Mesh::DISPLACE_BUMP;
520                 else if(method == 1)
521                         mesh->displacement_method = Mesh::DISPLACE_TRUE;
522                 else
523                         mesh->displacement_method = Mesh::DISPLACE_BOTH;
524         }
525
526         /* tag update */
527         bool rebuild = false;
528
529         if(oldtriangle.size() != mesh->triangles.size())
530                 rebuild = true;
531         else if(oldtriangle.size()) {
532                 if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
533                         rebuild = true;
534         }
535
536         if(oldcurve_keys.size() != mesh->curve_keys.size())
537                 rebuild = true;
538         else if(oldcurve_keys.size()) {
539                 if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
540                         rebuild = true;
541         }
542         
543         mesh->tag_update(scene, rebuild);
544
545         return mesh;
546 }
547
548 void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
549 {
550         /* ensure we only sync instanced meshes once */
551         Mesh *mesh = object->mesh;
552
553         if(mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
554                 return;
555
556         mesh_motion_synced.insert(mesh);
557
558         /* for motion pass always compute, for motion blur it can be disabled */
559         int time_index = 0;
560
561         if(scene->need_motion() == Scene::MOTION_BLUR) {
562                 /* see if this mesh needs motion data at this time */
563                 vector<float> object_times = object->motion_times();
564                 bool found = false;
565
566                 foreach(float object_time, object_times) {
567                         if(motion_time == object_time) {
568                                 found = true;
569                                 break;
570                         }
571                         else
572                                 time_index++;
573                 }
574
575                 if(!found)
576                         return;
577         }
578         else {
579                 if(motion_time == -1.0f)
580                         time_index = 0;
581                 else if(motion_time == 1.0f)
582                         time_index = 1;
583                 else
584                         return;
585         }
586
587         /* skip objects without deforming modifiers. this is not totally reliable,
588          * would need a more extensive check to see which objects are animated */
589         size_t numverts = mesh->verts.size();
590         size_t numkeys = mesh->curve_keys.size();
591
592         if((!numverts && !numkeys) || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
593                 return;
594         
595         /* get derived mesh */
596         BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
597
598         if(!b_mesh)
599                 return;
600         
601         if(numverts) {
602                 /* find attributes */
603                 Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
604                 bool new_attribute = false;
605
606                 /* add new attributes if they don't exist already */
607                 if(!attr_mP) {
608                         attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
609
610                         new_attribute = true;
611                 }
612
613                 /* load vertex data from mesh */
614                 float3 *mP = attr_mP->data_float3() + time_index*numverts;
615
616                 BL::Mesh::vertices_iterator v;
617                 int i = 0;
618
619                 for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i)
620                         mP[i] = get_float3(v->co());
621
622                 /* in case of new attribute, we verify if there really was any motion */
623                 if(new_attribute) {
624                         if(i != numverts || memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) {
625                                 /* no motion, remove attributes again */
626                                 mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
627                         }
628                         else if(time_index > 0) {
629                                 /* motion, fill up previous steps that we might have skipped because
630                                  * they had no motion, but we need them anyway now */
631                                 float3 *P = &mesh->verts[0];
632
633                                 for(int step = 0; step < time_index; step++)
634                                         memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
635                         }
636                 }
637         }
638
639         /* hair motion */
640         if(numkeys)
641                 sync_curves(mesh, b_mesh, b_ob, true, time_index);
642
643         /* free derived mesh */
644         b_data.meshes.remove(b_mesh);
645 }
646
647 CCL_NAMESPACE_END
648