Cycles code refactor: improve vertex motion attribute storage and export.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 29 Mar 2014 12:03:46 +0000 (13:03 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 29 Mar 2014 12:03:46 +0000 (13:03 +0100)
This now supports multiple steps and subframe sampling of motion.

There is one difference for object and camera transform motion blur. It still
only supports two steps there, but the transforms are now sampled at subframe
times instead of the previous and next frame and then interpolated/extrapolated.
This will give different render results in some cases but it's more accurate.

Part of the code is from the summer of code project by Gavin Howard, but it has
been significantly rewritten and extended.

14 files changed:
intern/cycles/blender/blender_camera.cpp
intern/cycles/blender/blender_curves.cpp
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/kernel/geom/geom_object.h
intern/cycles/kernel/kernel_camera.h
intern/cycles/kernel/kernel_primitive.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/attribute.cpp
intern/cycles/render/mesh.cpp
intern/cycles/render/object.cpp
intern/cycles/render/object.h
intern/cycles/render/scene.cpp

index 4c6b42a9cbc3f4726ba8220bb939cbbd0288e5f6..6bbd4106a961563693e1205100dcb09fcd803c02 100644 (file)
@@ -386,7 +386,7 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
        blender_camera_sync(cam, &bcam, width, height);
 }
 
-void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion)
+void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
 {
        Camera *cam = scene->camera;
 
@@ -394,12 +394,14 @@ void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion)
        tfm = blender_camera_matrix(tfm, cam->type);
 
        if(tfm != cam->matrix) {
-               if(motion == -1)
+               if(motion_time == -1.0f) {
                        cam->motion.pre = tfm;
-               else
+                       cam->use_motion = true;
+               }
+               else if(motion_time == 1.0f) {
                        cam->motion.post = tfm;
-
-               cam->use_motion = true;
+                       cam->use_motion = true;
+               }
        }
 }
 
index 4420a306e31ffee95f5ff8c24cc5153315d741f0..22de7b64273466955d62f2fdec62e0250ad52528 100644 (file)
@@ -612,16 +612,23 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
        }
 }
 
-static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int motion)
+static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int time_index)
 {
+       /* find attribute */
+       Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+       bool new_attribute = false;
+
+       /* add new attribute if it doesn't exist already */
+       if(!attr_mP) {
+               attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+               new_attribute = true;
+       }
+
        /* export motion vectors for curve keys */
-       AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
-       Attribute *attr_motion = mesh->curve_attributes.add(std);
-       float4 *data_motion = attr_motion->data_float4();
-       float4 *current_motion = data_motion;
-       size_t size = mesh->curve_keys.size();
-       size_t i = 0;
+       size_t numkeys = mesh->curve_keys.size();
+       float4 *mP = attr_mP->data_float4() + time_index*numkeys;
        bool have_motion = false;
+       int i = 0;
 
        for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
                if(CData->psys_curvenum[sys] == 0)
@@ -640,16 +647,14 @@ static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveDat
                                        if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
                                                radius = 0.0f;
 
-                                       *current_motion = float3_to_float4(ickey_loc);
-                                       current_motion->w = radius;
+                                       mP[i] = float3_to_float4(ickey_loc);
+                                       mP[i].w = radius;
 
                                        /* unlike mesh coordinates, these tend to be slightly different
                                         * between frames due to particle transforms into/out of object
                                         * space, so we use an epsilon to detect actual changes */
-                                       if(len_squared(*current_motion - mesh->curve_keys[i]) > 1e-5f*1e-5f)
+                                       if(len_squared(mP[i] - mesh->curve_keys[i]) > 1e-5f*1e-5f)
                                                have_motion = true;
-
-                                       current_motion++;
                                }
 
                                i++;
@@ -657,8 +662,23 @@ static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveDat
                }
        }
 
-       if(i != size || !have_motion)
-               mesh->curve_attributes.remove(std);
+       /* in case of new attribute, we verify if there really was any motion */
+       if(new_attribute) {
+               if(i != numkeys || !have_motion) {
+                       /* no motion, remove attributes again */
+                       mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+               }
+               else if(time_index > 0) {
+                       /* motion, fill up previous steps that we might have skipped because
+                        * they had no motion, but we need them anyway now */
+                       for(int step = 0; step < time_index; step++) {
+                               float4 *mP = attr_mP->data_float4() + step*numkeys;
+
+                               for(int key = 0; key < numkeys; key++)
+                                       mP[key] = mesh->curve_keys[key];
+                       }
+               }
+       }
 }
 
 void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata)
@@ -804,7 +824,7 @@ void BlenderSync::sync_curve_settings()
                curve_system_manager->tag_update(scene);
 }
 
-void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, int motion)
+void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index)
 {
        if(!motion) {
                /* Clear stored curve data */
@@ -859,7 +879,7 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, int
        }
        else {
                if(motion)
-                       ExportCurveSegmentsMotion(scene, mesh, &CData, motion);
+                       ExportCurveSegmentsMotion(scene, mesh, &CData, time_index);
                else
                        ExportCurveSegments(scene, mesh, &CData);
        }
index b356537e9717fa80d6db6ca6f7e99caf5b10b8fa..9e11cc1ae0b44a68efeab84ba0c026d9cb6a4489 100644 (file)
@@ -449,6 +449,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        Mesh *mesh;
 
        if(!mesh_map.sync(&mesh, key)) {
+               
                /* if transform was applied to mesh, need full update */
                if(object_updated && mesh->transform_applied);
                /* test if shaders changed, these can be object level so mesh
@@ -503,7 +504,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
                        }
 
                        if(render_layer.use_hair)
-                               sync_curves(mesh, b_mesh, b_ob, 0);
+                               sync_curves(mesh, b_mesh, b_ob, false);
 
                        /* free derived mesh */
                        b_data.meshes.remove(b_mesh);
@@ -544,46 +545,103 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        return mesh;
 }
 
-void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion)
+void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
 {
-       /* todo: displacement, subdivision */
-       size_t size = mesh->verts.size();
-
-       /* skip objects without deforming modifiers. this is not a totally reliable,
-        * would need a more extensive check to see which objects are animated */
-       if(!size || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
-               return;
-
        /* ensure we only sync instanced meshes once */
+       Mesh *mesh = object->mesh;
+
        if(mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
                return;
 
        mesh_motion_synced.insert(mesh);
 
+       /* for motion pass always compute, for motion blur it can be disabled */
+       int time_index = 0;
+
+       if(scene->need_motion() == Scene::MOTION_BLUR) {
+               /* see if this mesh needs motion data at this time */
+               vector<float> object_times = object->motion_times();
+               bool found = false;
+
+               foreach(float object_time, object_times) {
+                       if(motion_time == object_time) {
+                               found = true;
+                               break;
+                       }
+                       else
+                               time_index++;
+               }
+
+               if(!found)
+                       return;
+       }
+       else {
+               if(motion_time == -1.0f)
+                       time_index = 0;
+               else if(motion_time == 1.0f)
+                       time_index = 1;
+               else
+                       return;
+       }
+
+       /* skip objects without deforming modifiers. this is not totally reliable,
+        * would need a more extensive check to see which objects are animated */
+       size_t numverts = mesh->verts.size();
+       size_t numkeys = mesh->curve_keys.size();
+
+       if((!numverts && !numkeys) || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
+               return;
+       
        /* get derived mesh */
        BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
 
-       if(b_mesh) {
-               BL::Mesh::vertices_iterator v;
-               AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
-               Attribute *attr_M = mesh->attributes.add(std);
-               float3 *M = attr_M->data_float3(), *cur_M;
-               size_t i = 0;
+       if(!b_mesh)
+               return;
+       
+       if(numverts) {
+               /* find attributes */
+               Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+               bool new_attribute = false;
+
+               /* add new attributes if they don't exist already */
+               if(!attr_mP) {
+                       attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+
+                       new_attribute = true;
+               }
+
+               /* load vertex data from mesh */
+               float3 *mP = attr_mP->data_float3() + time_index*numverts;
 
-               for(b_mesh.vertices.begin(v), cur_M = M; v != b_mesh.vertices.end() && i < size; ++v, cur_M++, i++)
-                       *cur_M = get_float3(v->co());
+               BL::Mesh::vertices_iterator v;
+               int i = 0;
 
-               /* if number of vertices changed, or if coordinates stayed the same, drop it */
-               if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0)
-                       mesh->attributes.remove(std);
+               for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i)
+                       mP[i] = get_float3(v->co());
 
-               /* hair motion */
-               if(render_layer.use_hair)
-                       sync_curves(mesh, b_mesh, b_ob, motion);
+               /* in case of new attribute, we verify if there really was any motion */
+               if(new_attribute) {
+                       if(i != numverts || memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) {
+                               /* no motion, remove attributes again */
+                               mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+                       }
+                       else if(time_index > 0) {
+                               /* motion, fill up previous steps that we might have skipped because
+                                * they had no motion, but we need them anyway now */
+                               float3 *P = &mesh->verts[0];
 
-               /* free derived mesh */
-               b_data.meshes.remove(b_mesh);
+                               for(int step = 0; step < time_index; step++)
+                                       memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
+                       }
+               }
        }
+
+       /* hair motion */
+       if(numkeys)
+               sync_curves(mesh, b_mesh, b_ob, true, time_index);
+
+       /* free derived mesh */
+       b_data.meshes.remove(b_mesh);
 }
 
 CCL_NAMESPACE_END
index 6ffc8c81ce6ee5a294c8be6cd62be88827e99ebe..f5945a68fc1218b2f89229a58b5202866e47915a 100644 (file)
@@ -217,9 +217,11 @@ void BlenderSync::sync_background_light()
 
 /* Object */
 
-Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, bool hide_tris)
+Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
+                                 Transform& tfm, uint layer_flag, float motion_time, bool hide_tris)
 {
        BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
+       bool motion = motion_time != 0.0f;
        
        /* light is handled separately */
        if(object_is_light(b_ob)) {
@@ -243,18 +245,21 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
                object = object_map.find(key);
 
                if(object) {
+                       /* object transformation */
                        if(tfm != object->tfm) {
-                               if(motion == -1)
+                               if(motion_time == -1.0f) {
                                        object->motion.pre = tfm;
-                               else
+                                       object->use_motion = true;
+                               }
+                               else if(motion_time == 1.0f) {
                                        object->motion.post = tfm;
-
-                               object->use_motion = true;
+                                       object->use_motion = true;
+                               }
                        }
 
-                       /* mesh deformation blur not supported yet */
-                       if(!scene->integrator->motion_blur)
-                               sync_mesh_motion(b_ob, object->mesh, motion);
+                       /* mesh deformation */
+                       if(object->mesh)
+                               sync_mesh_motion(b_ob, object, motion_time);
                }
 
                return object;
@@ -314,6 +319,20 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
                object->motion.post = tfm;
                object->use_motion = false;
 
+               /* motion blur */
+               if(scene->need_motion() == Scene::MOTION_BLUR && object->mesh) {
+                       Mesh *mesh = object->mesh;
+
+                       if(true) {
+                               if(true)
+                                       mesh->motion_steps = 3;
+
+                               vector<float> times = object->motion_times();
+                               foreach(float time, times)
+                                       motion_times.insert(time);
+                       }
+               }
+
                /* random number */
                object->random_id = hash_string(object->name.c_str());
 
@@ -412,10 +431,11 @@ static bool object_render_hide_duplis(BL::Object b_ob)
 
 /* Object Loop */
 
-void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
+void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
 {
        /* layer data */
        uint scene_layer = render_layer.scene_layer;
+       bool motion = motion_time != 0.0f;
        
        if(!motion) {
                /* prepare for sync */
@@ -424,6 +444,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
                object_map.pre_sync();
                mesh_synced.clear();
                particle_system_map.pre_sync();
+               motion_times.clear();
        }
        else {
                mesh_motion_synced.clear();
@@ -468,7 +489,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
                                                        BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
 
                                                        /* sync object and mesh or light data */
-                                                       Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, hide_tris);
+                                                       Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion_time, hide_tris);
 
                                                        /* sync possible particle data, note particle_id
                                                         * starts counting at 1, first is dummy particle */
@@ -488,7 +509,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
                                if(!object_render_hide(*b_ob, true, true, hide_tris)) {
                                        /* object itself */
                                        Transform tfm = get_transform(b_ob->matrix_world());
-                                       sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris);
+                                       sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion_time, hide_tris);
                                }
                        }
 
@@ -528,31 +549,46 @@ void BlenderSync::sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override, void
                b_cam = b_override;
 
        Camera prevcam = *(scene->camera);
-       
-       /* go back and forth one frame */
-       int frame = b_scene.frame_current();
 
-       for(int motion = -1; motion <= 1; motion += 2) {
-               /* we need to set the python thread state again because this
-                * function assumes it is being executed from python and will
-                * try to save the thread state */
+       int frame_center = b_scene.frame_current();
+
+       /* always sample these times for camera motion */
+       motion_times.insert(-1.0f);
+       motion_times.insert(1.0f);
+
+       /* note iteration over motion_times set happens in sorted order */
+       foreach(float relative_time, motion_times) {
+               /* sync camera, only supports two times at the moment */
+               if(relative_time == -1.0f || relative_time == 1.0f)
+                       sync_camera_motion(b_cam, relative_time);
+
+               /* fixed shutter time to get previous and next frame for motion pass */
+               float shuttertime;
+
+               if(scene->need_motion() == Scene::MOTION_PASS)
+                       shuttertime = 2.0f;
+               else
+                       shuttertime = scene->camera->shuttertime;
+
+               /* compute frame and subframe time */
+               float time = frame_center + relative_time * shuttertime * 0.5f;
+               int frame = (int)floorf(time);
+               float subframe = time - frame;
+
+               /* change frame */
                python_thread_state_restore(python_thread_state);
-               b_scene.frame_set(frame + motion, 0.0f);
+               b_scene.frame_set(frame, subframe);
                python_thread_state_save(python_thread_state);
 
-               /* camera object */
-               if(b_cam)
-                       sync_camera_motion(b_cam, motion);
-
-               /* mesh objects */
-               sync_objects(b_v3d, motion);
+               /* sync object */
+               sync_objects(b_v3d, relative_time);
        }
 
        /* we need to set the python thread state again because this
         * function assumes it is being executed from python and will
         * try to save the thread state */
        python_thread_state_restore(python_thread_state);
-       b_scene.frame_set(frame, 0.0f);
+       b_scene.frame_set(frame_center, 0.0f);
        python_thread_state_save(python_thread_state);
 
        /* tag camera for motion update */
index 205761ad302949f7edeb165ba0064830efccf556..9c4175ef6904302068e3765f8aab504638270d1a 100644 (file)
@@ -71,7 +71,7 @@ private:
        /* sync */
        void sync_lamps(bool update_all);
        void sync_materials(bool update_all);
-       void sync_objects(BL::SpaceView3D b_v3d, int motion = 0);
+       void sync_objects(BL::SpaceView3D b_v3d, float motion_time = 0.0f);
        void sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override, void **python_thread_state);
        void sync_film();
        void sync_view();
@@ -81,12 +81,13 @@ private:
 
        void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
        Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
-       void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, int motion);
-       Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, bool hide_tris);
+       void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index = 0);
+       Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
+                                        Transform& tfm, uint layer_flag, float motion_time, bool hide_tris);
        void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm);
        void sync_background_light();
-       void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion);
-       void sync_camera_motion(BL::Object b_ob, int motion);
+       void sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time);
+       void sync_camera_motion(BL::Object b_ob, float motion_time);
 
        /* particles */
        bool sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Object *object);
@@ -109,6 +110,7 @@ private:
        id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
        set<Mesh*> mesh_synced;
        set<Mesh*> mesh_motion_synced;
+       std::set<float> motion_times;
        void *world_map;
        bool world_recalc;
 
index 3646615b9f615e1033e4830c696db4353a14f872..b1106c25fd7a003acf73b06458dce86d0ba1a2a5 100644 (file)
@@ -230,6 +230,21 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
        return make_float3(f.x, f.y, 0.0f);
 }
 
+ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
+{
+       int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
+
+       if(numkeys) {
+               float4 f = kernel_tex_fetch(__objects, offset);
+               *numkeys = __float_as_int(f.w);
+       }
+
+       float4 f = kernel_tex_fetch(__objects, offset + 1);
+       if(numsteps)
+               *numsteps = __float_as_int(f.z);
+       if(numverts)
+               *numverts = __float_as_int(f.w);
+}
 
 ccl_device int shader_pass_id(KernelGlobals *kg, ShaderData *sd)
 {
index 887b1afddd4a0255f839e8cb71ee6c5a059bf21c..fe995bbb594a5848f85110cb4fe38cd869977c53 100644 (file)
@@ -229,7 +229,7 @@ ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, f
        if(kernel_data.cam.shuttertime == -1.0f)
                ray->time = TIME_INVALID;
        else
-               ray->time = 0.5f + 0.5f*(time - 0.5f)*kernel_data.cam.shuttertime;
+               ray->time = time;
 #endif
 
        /* sample */
index f9efdd2cf562f97e78fe8d5b142a598f6ef21f93..af5faf37c3f0fa1613fc353e729c43a5b4860c81 100644 (file)
@@ -161,14 +161,20 @@ ccl_device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
        float3 motion_pre = sd->P, motion_post = sd->P;
 
        /* deformation motion */
-       AttributeElement elem_pre, elem_post;
-       int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre);
-       int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post);
-
-       if(offset_pre != ATTR_STD_NOT_FOUND)
-               motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL);
-       if(offset_post != ATTR_STD_NOT_FOUND)
-               motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL);
+       AttributeElement elem;
+       int offset = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
+
+       if(offset != ATTR_STD_NOT_FOUND) {
+               /* get motion info */
+               int numverts, numkeys;
+               object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
+
+               /* lookup attributes */
+               int offset_next = (sd->type & PRIMITIVE_ALL_TRIANGLE)? offset + numverts: offset + numkeys;
+
+               motion_pre = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+               motion_post = primitive_attribute_float3(kg, sd, elem, offset_next, NULL, NULL);
+       }
 
        /* object motion. note that depending on the mesh having motion vectors, this
         * transformation was set match the world/object space of motion_pre/post */
index b260a3d11ac1218718a0b94a61cc9a95bc8244fa..f708f01991229563fd34d2535680d46c1a95d0fd 100644 (file)
@@ -470,8 +470,7 @@ typedef enum AttributeStandard {
        ATTR_STD_GENERATED_TRANSFORM,
        ATTR_STD_POSITION_UNDEFORMED,
        ATTR_STD_POSITION_UNDISPLACED,
-       ATTR_STD_MOTION_PRE,
-       ATTR_STD_MOTION_POST,
+       ATTR_STD_MOTION_VERTEX_POSITION,
        ATTR_STD_PARTICLE,
        ATTR_STD_CURVE_INTERCEPT,
        ATTR_STD_PTEX_FACE_ID,
index bef3295d927a85cdf7ffec36ec7056ac7fe0db16..e730cab0c60f6ca2a4954b171f1dee319fc7ee28 100644 (file)
@@ -163,10 +163,8 @@ const char *Attribute::standard_name(AttributeStandard std)
                return "undeformed";
        else if(std == ATTR_STD_POSITION_UNDISPLACED)
                return "undisplaced";
-       else if(std == ATTR_STD_MOTION_PRE)
-               return "motion_pre";
-       else if(std == ATTR_STD_MOTION_POST)
-               return "motion_post";
+       else if(std == ATTR_STD_MOTION_VERTEX_POSITION)
+               return "motion_P";
        else if(std == ATTR_STD_PARTICLE)
                return "particle";
        else if(std == ATTR_STD_CURVE_INTERCEPT)
@@ -272,10 +270,11 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
                        case ATTR_STD_GENERATED:
                        case ATTR_STD_POSITION_UNDEFORMED:
                        case ATTR_STD_POSITION_UNDISPLACED:
-                       case ATTR_STD_MOTION_PRE:
-                       case ATTR_STD_MOTION_POST:
                                attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
                                break;
+                       case ATTR_STD_MOTION_VERTEX_POSITION:
+                               attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION);
+                               break;
                        case ATTR_STD_PTEX_FACE_ID:
                                attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE);
                                break;
@@ -296,9 +295,8 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
                        case ATTR_STD_GENERATED:
                                attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
                                break;
-                       case ATTR_STD_MOTION_PRE:
-                       case ATTR_STD_MOTION_POST:
-                               attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
+                       case ATTR_STD_MOTION_VERTEX_POSITION:
+                               attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION);
                                break;
                        case ATTR_STD_CURVE_INTERCEPT:
                                attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
index c6ddb00e76b959f74647b59ecf332df70e9600c3..0d09328119cec533921b9eaf3f34d3715f2f36e7 100644 (file)
@@ -187,6 +187,24 @@ void Mesh::compute_bounds()
 
                for(size_t i = 0; i < curve_keys_size; i++)
                        bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+               
+               Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+               if (attr) {
+                       size_t steps_size = verts.size() * (motion_steps - 1);
+                       float3 *vert_steps = attr->data_float3();
+       
+                       for (size_t i = 0; i < steps_size; i++)
+                               bnds.grow(vert_steps[i]);
+               }
+
+               Attribute *curve_attr = curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+               if (curve_attr) {
+                       size_t steps_size = curve_keys.size() * (motion_steps - 1);
+                       float3 *key_steps = curve_attr->data_float3();
+       
+                       for (size_t i = 0; i < steps_size; i++)
+                               bnds.grow(key_steps[i]);
+               }
 
                if(!bnds.valid()) {
                        bnds = BoundBox::empty;
@@ -197,6 +215,22 @@ void Mesh::compute_bounds()
 
                        for(size_t i = 0; i < curve_keys_size; i++)
                                bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+                       
+                       if (attr) {
+                               size_t steps_size = verts.size() * (motion_steps - 1);
+                               float3 *vert_steps = attr->data_float3();
+               
+                               for (size_t i = 0; i < steps_size; i++)
+                                       bnds.grow_safe(vert_steps[i]);
+                       }
+
+                       if (curve_attr) {
+                               size_t steps_size = curve_keys.size() * (motion_steps - 1);
+                               float3 *key_steps = curve_attr->data_float3();
+               
+                               for (size_t i = 0; i < steps_size; i++)
+                                       bnds.grow_safe(key_steps[i]);
+                       }
                }
        }
 
@@ -992,7 +1026,6 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
        foreach(Shader *shader, scene->shaders)
                shader->need_update_attributes = false;
 
-       float shuttertime = scene->camera->shuttertime;
 #ifdef __OBJECT_MOTION__
        Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading);
        bool motion_blur = need_motion == Scene::MOTION_BLUR;
@@ -1001,7 +1034,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 #endif
 
        foreach(Object *object, scene->objects)
-               object->compute_bounds(motion_blur, shuttertime);
+               object->compute_bounds(motion_blur);
 
        if(progress.get_cancel()) return;
 
index 362b4762b7478ffac9887ff6f56af85333a1e91b..e99ca32392940c540b7554c1279f91ef25b8c966 100644 (file)
@@ -55,7 +55,7 @@ Object::~Object()
 {
 }
 
-void Object::compute_bounds(bool motion_blur, float shuttertime)
+void Object::compute_bounds(bool motion_blur)
 {
        BoundBox mbounds = mesh->bounds;
 
@@ -68,10 +68,7 @@ void Object::compute_bounds(bool motion_blur, float shuttertime)
                /* todo: this is really terrible. according to pbrt there is a better
                 * way to find this iteratively, but did not find implementation yet
                 * or try to implement myself */
-               float start_t = 0.5f - shuttertime*0.25f;
-               float end_t = 0.5f + shuttertime*0.25f;
-
-               for(float t = start_t; t < end_t; t += (1.0f/128.0f)*shuttertime) {
+               for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
                        Transform ttfm;
 
                        transform_motion_interpolate(&ttfm, &decomp, t);
@@ -96,6 +93,15 @@ void Object::apply_transform()
        for(size_t i = 0; i < mesh->verts.size(); i++)
                mesh->verts[i] = transform_point(&tfm, mesh->verts[i]);
 
+       Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+       if (attr) {
+               size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1);
+               float3 *vert_steps = attr->data_float3();
+
+               for (size_t i = 0; i < steps_size; i++)
+                       vert_steps[i] = transform_point(&tfm, vert_steps[i]);
+       }
+
        /* apply to curve keys */
        for(size_t i = 0; i < mesh->curve_keys.size(); i++) {
                float3 co = transform_point(&tfm, float4_to_float3(mesh->curve_keys[i]));
@@ -106,6 +112,15 @@ void Object::apply_transform()
                mesh->curve_keys[i].w *= radius;
        }
 
+       Attribute *curve_attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+       if (curve_attr) {
+               size_t steps_size = mesh->curve_keys.size() * (mesh->motion_steps - 1);
+               float3 *vert_steps = curve_attr->data_float3();
+
+               for (size_t i = 0; i < steps_size; i++)
+                       vert_steps[i] = transform_point(&tfm, vert_steps[i]);
+       }
+
        /* store matrix to transform later. when accessing these as attributes we
         * do not want the transform to be applied for consistency between static
         * and dynamic BVH, so we do it on packing. */
@@ -118,7 +133,7 @@ void Object::apply_transform()
 
        if(bounds.valid()) {
                mesh->compute_bounds();
-               compute_bounds(false, 0.0f);
+               compute_bounds(false);
        }
 
        /* tfm is not reset to identity, all code that uses it needs to check the
@@ -144,6 +159,25 @@ void Object::tag_update(Scene *scene)
        scene->object_manager->need_update = true;
 }
 
+vector<float> Object::motion_times()
+{
+       /* compute times at which we sample motion for this object */
+       vector<float> times;
+       int motion_steps = mesh->motion_steps;
+
+       if(!mesh || motion_steps == 1)
+               return times;
+
+       for(int step = 0; step < motion_steps; step++) {
+               if(step != motion_steps / 2) {
+                       float time = 2.0f * step / (motion_steps - 1) - 1.0f;
+                       times.push_back(time);
+               }
+       }
+
+       return times;
+}
+
 /* Object Manager */
 
 ObjectManager::ObjectManager()
@@ -239,10 +273,10 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
                        Transform mtfm_pre = ob->motion.pre;
                        Transform mtfm_post = ob->motion.post;
 
-                       if(!(mesh->attributes.find(ATTR_STD_MOTION_PRE) || mesh->curve_attributes.find(ATTR_STD_MOTION_PRE)))
+                       if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
                                mtfm_pre = mtfm_pre * itfm;
-                       if(!(mesh->attributes.find(ATTR_STD_MOTION_POST) || mesh->curve_attributes.find(ATTR_STD_MOTION_POST)))
                                mtfm_post = mtfm_post * itfm;
+                       }
 
                        memcpy(&objects_vector[i*OBJECT_VECTOR_SIZE+0], &mtfm_pre, sizeof(float4)*3);
                        memcpy(&objects_vector[i*OBJECT_VECTOR_SIZE+3], &mtfm_post, sizeof(float4)*3);
@@ -261,9 +295,14 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
                }
 #endif
 
-               /* dupli object coords */
-               objects[offset+9] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], 0.0f);
-               objects[offset+10] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], 0.0f, 0.0f);
+               /* dupli object coords and motion info */
+               int totalsteps = mesh->motion_steps;
+               int numsteps = (totalsteps - 1)/2;
+               int numverts = mesh->verts.size();
+               int numkeys = mesh->curve_keys.size();
+
+               objects[offset+9] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], __int_as_float(numkeys));
+               objects[offset+10] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], __int_as_float(numsteps), __int_as_float(numverts));
 
                /* object flag */
                if(ob->use_holdout)
index 31400f3c7f1e9081652e1b874e490882f220559b..f3a019f4d733d87ea10dd35190a5105049be93d7 100644 (file)
@@ -53,14 +53,16 @@ public:
 
        ParticleSystem *particle_system;
        int particle_index;
-
+       
        Object();
        ~Object();
 
        void tag_update(Scene *scene);
 
-       void compute_bounds(bool motion_blur, float shuttertime);
+       void compute_bounds(bool motion_blur);
        void apply_transform();
+
+       vector<float> motion_times();
 };
 
 /* Object Manager */
index daf22d90978c3b94adfec95c57a3e0532f015639..f7d2f2d0a8ef0e9e579eed2c5113be6d9b419ebf 100644 (file)
@@ -226,8 +226,8 @@ bool Scene::need_global_attribute(AttributeStandard std)
 {
        if(std == ATTR_STD_UV)
                return Pass::contains(film->passes, PASS_UV);
-       if(std == ATTR_STD_MOTION_PRE || std == ATTR_STD_MOTION_POST)
-               return need_motion() == MOTION_PASS;
+       if(std == ATTR_STD_MOTION_VERTEX_POSITION)
+               return need_motion() != MOTION_NONE;
        
        return false;
 }