Cycles: support for motion vector and UV passes.
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 30 Apr 2012 12:49:26 +0000 (12:49 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 30 Apr 2012 12:49:26 +0000 (12:49 +0000)
Most of the changes are related to adding support for motion data throughout
the code. There's some code for actual camera/object motion blur raytracing
but it's unfinished (it badly slows down the raytracing kernel even when the
option is turned off), so that code it disabled still.

Motion vector export from Blender tries to avoid computing derived meshes
when the mesh does not have a deforming modifier, and it also won't store
motion vectors for every vertex if only the object or camera is moving.

52 files changed:
CMakeLists.txt
intern/cycles/app/cycles_xml.cpp
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_camera.cpp
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_sync.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/blender/blender_util.h
intern/cycles/kernel/kernel_bvh.h
intern/cycles/kernel/kernel_camera.h
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_light.h
intern/cycles/kernel/kernel_object.h
intern/cycles/kernel/kernel_passes.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_triangle.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/svm/svm_tex_coord.h
intern/cycles/render/CMakeLists.txt
intern/cycles/render/attribute.cpp
intern/cycles/render/attribute.h
intern/cycles/render/buffers.cpp
intern/cycles/render/camera.cpp
intern/cycles/render/camera.h
intern/cycles/render/film.cpp
intern/cycles/render/film.h
intern/cycles/render/graph.cpp
intern/cycles/render/integrator.cpp
intern/cycles/render/integrator.h
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h
intern/cycles/render/mesh_displace.cpp
intern/cycles/render/nodes.cpp
intern/cycles/render/object.cpp
intern/cycles/render/object.h
intern/cycles/render/scene.cpp
intern/cycles/render/scene.h
intern/cycles/render/shader.cpp
intern/cycles/render/shader.h
intern/cycles/render/svm.cpp
intern/cycles/render/svm.h
intern/cycles/subd/subd_dice.cpp
intern/cycles/util/util_math.h
intern/cycles/util/util_transform.cpp
intern/cycles/util/util_transform.h
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/intern/object.c
source/blender/makesrna/intern/rna_object_api.c
source/blender/makesrna/intern/rna_scene_api.c

index e8bdc5375fca46f344a59723082136ea8f0fb021..577a0c9ba05662def9ccee064d618cccda2eb5b9 100644 (file)
@@ -304,7 +304,7 @@ endif()
 #-----------------------------------------------------------------------------
 # Check for conflicting/unsupported configurations
 
-if(NOT WITH_BLENDER AND NOT WITH_PLAYER)
+if(NOT WITH_BLENDER AND NOT WITH_PLAYER AND NOT WITH_CYCLES_TEST)
        message(FATAL_ERROR "At least one of WITH_BLENDER or WITH_PLAYER must be enabled, nothing to do!")
 endif()
 
index b954ff45e2781db68001b58b351df06567e81adc..82f1338d86bd9a05213fda7198a417affebe26e5 100644 (file)
@@ -284,8 +284,7 @@ static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
        xml_read_float(&cam->farclip, node, "farclip");
        xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop
        xml_read_float(&cam->focaldistance, node, "focaldistance");
-       xml_read_float(&cam->shutteropen, node, "shutteropen");
-       xml_read_float(&cam->shutterclose, node, "shutterclose");
+       xml_read_float(&cam->shuttertime, node, "shuttertime");
 
        if(xml_equal_string(node, "type", "orthographic"))
                cam->type = CAMERA_ORTHOGRAPHIC;
@@ -705,7 +704,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
        }
 
        /* temporary for test compatibility */
-       mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
+       mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
 }
 
 /* Patch */
@@ -766,7 +765,7 @@ static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
                delete patch;
 
                /* temporary for test compatibility */
-               mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
+               mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
        }
 }
 
index 0ed08589327a77a90a25ff6385887704fb95a474..8480b0a525611fd684b0531a2c1fc52ec90c3cea 100644 (file)
@@ -94,6 +94,29 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
         col.prop(cscene, "blur_glossy")
 
 
+class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel):
+    bl_label = "Motion Blur"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return False
+
+    def draw_header(self, context):
+        rd = context.scene.render
+
+        self.layout.prop(rd, "use_motion_blur", text="")
+
+    def draw(self, context):
+        layout = self.layout
+
+        rd = context.scene.render
+        layout.active = rd.use_motion_blur
+
+        row = layout.row()
+        row.prop(rd, "motion_blur_shutter")
+
+
 class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
     bl_label = "Film"
 
@@ -202,10 +225,10 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
         col.prop(rl, "use_pass_combined")
         col.prop(rl, "use_pass_z")
         col.prop(rl, "use_pass_normal")
+        col.prop(rl, "use_pass_vector")
+        col.prop(rl, "use_pass_uv")
         col.prop(rl, "use_pass_object_index")
         col.prop(rl, "use_pass_material_index")
-        col.prop(rl, "use_pass_emit")
-        col.prop(rl, "use_pass_environment")
         col.prop(rl, "use_pass_ambient_occlusion")
         col.prop(rl, "use_pass_shadow")
 
@@ -227,6 +250,9 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
         row.prop(rl, "use_pass_transmission_indirect", text="Indirect", toggle=True)
         row.prop(rl, "use_pass_transmission_color", text="Color", toggle=True)
 
+        col.prop(rl, "use_pass_emit", text="Emission")
+        col.prop(rl, "use_pass_environment")
+
 
 class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
     bl_label = "Post Processing"
index a21b22bc35a62a6e08754ae7b3c605d24efef1a4..55a32d8fc1064e11f7b3f70e729b5321abc5eddb 100644 (file)
@@ -35,6 +35,7 @@ struct BlenderCamera {
        float ortho_scale;
 
        float lens;
+       float shuttertime;
 
        float aperturesize;
        uint apertureblades;
@@ -64,6 +65,7 @@ static void blender_camera_init(BlenderCamera *bcam)
        bcam->sensor_width = 32.0f;
        bcam->sensor_height = 18.0f;
        bcam->sensor_fit = BlenderCamera::AUTO;
+       bcam->shuttertime = 1.0f;
 }
 
 static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
@@ -132,6 +134,28 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
        }
 }
 
+static Transform blender_camera_matrix(const Transform& tfm, CameraType type)
+{
+       Transform result;
+
+       if(type == CAMERA_ENVIRONMENT) {
+               /* make it so environment camera needs to be pointed in the direction
+                  of the positive x-axis to match an environment texture, this way
+                  it is looking at the center of the texture */
+               result = tfm *
+                       make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
+                                       0.0f,  0.0f, 1.0f, 0.0f,
+                                      -1.0f,  0.0f, 0.0f, 0.0f,
+                                       0.0f,  0.0f, 0.0f, 1.0f);
+       }
+       else {
+               /* note the blender camera points along the negative z-axis */
+               result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
+       }
+
+       return transform_clear_scale(result);
+}
+
 static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
 {
        /* copy camera to compare later */
@@ -224,24 +248,11 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
        cam->bladesrotation = bcam->aperturerotation;
 
        /* transform */
-       cam->matrix = bcam->matrix;
-
-       if(bcam->type == CAMERA_ENVIRONMENT) {
-               /* make it so environment camera needs to be pointed in the direction
-                  of the positive x-axis to match an environment texture, this way
-                  it is looking at the center of the texture */
-               cam->matrix = cam->matrix *
-                       make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
-                                       0.0f,  0.0f, 1.0f, 0.0f,
-                                      -1.0f,  0.0f, 0.0f, 0.0f,
-                                       0.0f,  0.0f, 0.0f, 1.0f);
-       }
-       else {
-               /* note the blender camera points along the negative z-axis */
-               cam->matrix = cam->matrix * transform_scale(1.0f, 1.0f, -1.0f);
-       }
-
-       cam->matrix = transform_clear_scale(cam->matrix);
+       cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type);
+       cam->motion.pre = cam->matrix;
+       cam->motion.post = cam->matrix;
+       cam->use_motion = false;
+       cam->shuttertime = bcam->shuttertime;
 
        /* set update flag */
        if(cam->modified(prevcam))
@@ -260,6 +271,7 @@ void BlenderSync::sync_camera(BL::Object b_override, int width, int height)
 
        bcam.pixelaspect.x = r.pixel_aspect_x();
        bcam.pixelaspect.y = r.pixel_aspect_y();
+       bcam.shuttertime = r.motion_blur_shutter();
 
        /* camera object */
        BL::Object b_ob = b_scene.camera();
@@ -277,6 +289,23 @@ void BlenderSync::sync_camera(BL::Object b_override, int width, int height)
        blender_camera_sync(cam, &bcam, width, height);
 }
 
+void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion)
+{
+       Camera *cam = scene->camera;
+
+       Transform tfm = get_transform(b_ob.matrix_world());
+       tfm = blender_camera_matrix(tfm, cam->type);
+
+       if(tfm != cam->matrix) {
+               if(motion == -1)
+                       cam->motion.pre = tfm;
+               else
+                       cam->motion.post = tfm;
+
+               cam->use_motion = true;
+       }
+}
+
 /* Sync 3D View Camera */
 
 void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
@@ -288,6 +317,7 @@ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int
        bcam.nearclip = b_v3d.clip_start();
        bcam.farclip = b_v3d.clip_end();
        bcam.lens = b_v3d.lens();
+       bcam.shuttertime = b_scene.render().motion_blur_shutter();
 
        if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
                /* camera view */
index 7caa6b3d511c2e47dbfbeb7c27f160aa27b16818..f77e6551de011badebd8fc542b1597b6052cd535 100644 (file)
@@ -33,30 +33,6 @@ CCL_NAMESPACE_BEGIN
 
 /* Find/Add */
 
-static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
-{
-       if(std == Attribute::STD_NONE)
-               return false;
-
-       foreach(uint shader, mesh->used_shaders)
-               if(scene->shaders[shader]->attributes.find(std))
-                       return true;
-       
-       return false;
-}
-
-static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
-{
-       if(name == ustring())
-               return false;
-
-       foreach(uint shader, mesh->used_shaders)
-               if(scene->shaders[shader]->attributes.find(name))
-                       return true;
-       
-       return false;
-}
-
 static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
 {
        /* create vertices */
@@ -66,7 +42,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                mesh->verts.push_back(get_float3(v->co()));
 
        /* create vertex normals */
-       Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
+       Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
        float3 *N = attr_N->data_float3();
 
        for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
@@ -94,8 +70,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
        /* create generated coordinates. todo: we should actually get the orco
           coordinates from modifiers, for now we use texspace loc/size which
           is available in the api. */
-       if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
-               Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
+       if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+               Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
                float3 loc = get_float3(b_mesh.texspace_location());
                float3 size = get_float3(b_mesh.texspace_size());
 
@@ -118,7 +94,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                BL::Mesh::tessface_vertex_colors_iterator l;
 
                for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
-                       if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
+                       if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
                                continue;
 
                        Attribute *attr = mesh->attributes.add(
@@ -150,10 +126,10 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                BL::Mesh::tessface_uv_textures_iterator l;
 
                for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
-                       Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
+                       AttributeStandard std = (l->active_render())? ATTR_STD_UV: ATTR_STD_NONE;
                        ustring name = ustring(l->name().c_str());
 
-                       if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
+                       if(!(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)))
                                continue;
 
                        Attribute *attr;
@@ -329,5 +305,38 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool holdout, bool object_updated)
        return mesh;
 }
 
+void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion)
+{
+       /* todo: displacement, subdivision */
+       BL::ID b_ob_data = b_ob.data();
+       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::object_is_deform_modified(b_ob, b_scene, preview))
+               return;
+
+       /* get derived mesh */
+       BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
+
+       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();
+               size_t i = 0, size = mesh->verts.size();
+
+               for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < size; ++v, M++, i++)
+                       *M = get_float3(v->co());
+
+               /* 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);
+
+               /* free derived mesh */
+               object_remove_mesh(b_data, b_mesh);
+       }
+}
+
 CCL_NAMESPACE_END
 
index 96faee19af4b27897e5a66fed28362386d678d44..b1cd778c6d3cd9564d779db8b0045bfeaee4fe67 100644 (file)
@@ -16,6 +16,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "camera.h"
 #include "graph.h"
 #include "light.h"
 #include "mesh.h"
@@ -188,11 +189,12 @@ void BlenderSync::sync_background_light()
 
 /* Object */
 
-void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag)
+void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion)
 {
        /* light is handled separately */
        if(object_is_light(b_ob)) {
-               sync_light(b_parent, b_index, b_ob, tfm);
+               if(!motion)
+                       sync_light(b_parent, b_index, b_ob, tfm);
                return;
        }
 
@@ -200,9 +202,31 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
        if(!object_is_mesh(b_ob))
                return;
 
-       /* test if we need to sync */
+       /* key to lookup object */
        ObjectKey key(b_parent, b_index, b_ob);
        Object *object;
+
+       /* motion vector case */
+       if(motion) {
+               object = object_map.find(key);
+
+               if(object) {
+                       if(tfm != object->tfm) {
+                               if(motion == -1)
+                                       object->motion.pre = tfm;
+                               else
+                                       object->motion.post = tfm;
+
+                               object->use_motion = true;
+                       }
+
+                       sync_mesh_motion(b_ob, object->mesh, motion);
+               }
+
+               return;
+       }
+
+       /* test if we need to sync */
        bool object_updated = false;
 
        if(object_map.sync(&object, b_ob, b_parent, key))
@@ -219,6 +243,9 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
                object->name = b_ob.name().c_str();
                object->pass_id = b_ob.pass_index();
                object->tfm = tfm;
+               object->motion.pre = tfm;
+               object->motion.post = tfm;
+               object->use_motion = false;
 
                /* visibility flags for both parent */
                object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL;
@@ -238,16 +265,18 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
 
 /* Object Loop */
 
-void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
+void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
 {
        /* layer data */
        uint scene_layer = render_layer.scene_layer;
        
-       /* prepare for sync */
-       light_map.pre_sync();
-       mesh_map.pre_sync();
-       object_map.pre_sync();
-       mesh_synced.clear();
+       if(!motion) {
+               /* prepare for sync */
+               light_map.pre_sync();
+               mesh_map.pre_sync();
+               object_map.pre_sync();
+               mesh_synced.clear();
+       }
 
        /* object loop */
        BL::Scene::objects_iterator b_ob;
@@ -270,7 +299,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
                                        bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render();
 
                                        if(!(b_dup->hide() || dup_hide))
-                                               sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer);
+                                               sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer, motion);
 
                                        b_index++;
                                }
@@ -296,21 +325,50 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
                        if(!hide) {
                                /* object itself */
                                Transform tfm = get_transform(b_ob->matrix_world());
-                               sync_object(*b_ob, 0, *b_ob, tfm, ob_layer);
+                               sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion);
                        }
                }
        }
 
-       sync_background_light();
+       if(!motion) {
+               sync_background_light();
+
+               /* handle removed data and modified pointers */
+               if(light_map.post_sync())
+                       scene->light_manager->tag_update(scene);
+               if(mesh_map.post_sync())
+                       scene->mesh_manager->tag_update(scene);
+               if(object_map.post_sync())
+                       scene->object_manager->tag_update(scene);
+               mesh_synced.clear();
+       }
+}
+
+void BlenderSync::sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override)
+{
+       if(scene->need_motion() == Scene::MOTION_NONE)
+               return;
+
+       /* get camera object here to deal with camera switch */
+       BL::Object b_cam = b_scene.camera();
+       if(b_override)
+               b_cam = b_override;
+
+       /* go back and forth one frame */
+       int frame = b_scene.frame_current();
+
+       for(int motion = -1; motion <= 1; motion += 2) {
+               scene_frame_set(b_scene, frame + motion);
+
+               /* camera object */
+               if(b_cam)
+                       sync_camera_motion(b_cam, motion);
+
+               /* mesh objects */
+               sync_objects(b_v3d, motion);
+       }
 
-       /* handle removed data and modified pointers */
-       if(light_map.post_sync())
-               scene->light_manager->tag_update(scene);
-       if(mesh_map.post_sync())
-               scene->mesh_manager->tag_update(scene);
-       if(object_map.post_sync())
-               scene->object_manager->tag_update(scene);
-       mesh_synced.clear();
+       scene_frame_set(b_scene, frame);
 }
 
 CCL_NAMESPACE_END
index 5ece7aa26e205d8953028a2add9eb067a78be781..f79b99951651d5effcd8979632c9fb1aa97c1028 100644 (file)
@@ -91,7 +91,7 @@ void BlenderSession::create_session()
 
        /* create sync */
        sync = new BlenderSync(b_data, b_scene, scene, !background);
-       sync->sync_data(b_v3d);
+       sync->sync_data(b_v3d, b_engine.camera_override());
 
        if(b_rv3d)
                sync->sync_view(b_v3d, b_rv3d, width, height);
@@ -130,6 +130,8 @@ static PassType get_pass_type(BL::RenderPass b_pass)
                        return PASS_OBJECT_ID;
                case BL::RenderPass::type_UV:
                        return PASS_UV;
+               case BL::RenderPass::type_VECTOR:
+                       return PASS_MOTION;
                case BL::RenderPass::type_MATERIAL_INDEX:
                        return PASS_MATERIAL_ID;
 
@@ -168,7 +170,6 @@ static PassType get_pass_type(BL::RenderPass b_pass)
                case BL::RenderPass::type_REFRACTION:
                case BL::RenderPass::type_SPECULAR:
                case BL::RenderPass::type_REFLECTION:
-               case BL::RenderPass::type_VECTOR:
                case BL::RenderPass::type_MIST:
                        return PASS_NONE;
        }
@@ -209,6 +210,8 @@ void BlenderSession::render()
                                BL::RenderPass b_pass(*b_pass_iter);
                                PassType pass_type = get_pass_type(b_pass);
 
+                               if(pass_type == PASS_MOTION && scene->integrator->motion_blur)
+                                       continue;
                                if(pass_type != PASS_NONE)
                                        Pass::add(pass_type, passes);
                        }
@@ -219,7 +222,7 @@ void BlenderSession::render()
                scene->film->tag_update(scene);
 
                /* update scene */
-               sync->sync_data(b_v3d, b_iter->name().c_str());
+               sync->sync_data(b_v3d, b_engine.camera_override(), b_iter->name().c_str());
 
                /* update session */
                int samples = sync->get_layer_samples();
@@ -310,7 +313,7 @@ void BlenderSession::synchronize()
        }
 
        /* data and camera synchronize */
-       sync->sync_data(b_v3d);
+       sync->sync_data(b_v3d, b_engine.camera_override());
 
        if(b_rv3d)
                sync->sync_view(b_v3d, b_rv3d, width, height);
index 41cd200d0031ea234a1cfb04c0409a53f836cdb0..24cf10bc02879f4d855c110c3bf8c09bbc689f61 100644 (file)
@@ -121,19 +121,21 @@ bool BlenderSync::sync_recalc()
        return recalc;
 }
 
-void BlenderSync::sync_data(BL::SpaceView3D b_v3d, const char *layer)
+void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const char *layer)
 {
        sync_render_layers(b_v3d, layer);
        sync_integrator();
        sync_film();
        sync_shaders();
        sync_objects(b_v3d);
+       sync_motion(b_v3d, b_override);
 }
 
 /* Integrator */
 
 void BlenderSync::sync_integrator()
 {
+       BL::RenderSettings r = b_scene.render();
        PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
 
        experimental = (RNA_enum_get(&cscene, "feature_set") != 0);
@@ -160,6 +162,9 @@ void BlenderSync::sync_integrator()
        integrator->layer_flag = render_layer.layer;
 
        integrator->sample_clamp = get_float(cscene, "sample_clamp");
+#ifdef __MOTION__
+       integrator->motion_blur = (!preview && r.use_motion_blur());
+#endif
 
        if(integrator->modified(previntegrator))
                integrator->tag_update(scene);
index ab8e4bd8d00afa7486a515d37c69c5b9c3bfa4b8..acdcea1ef9bca4f6cd2dab6f6909afbf6c7c9b1d 100644 (file)
@@ -54,7 +54,7 @@ public:
 
        /* sync */
        bool sync_recalc();
-       void sync_data(BL::SpaceView3D b_v3d, const char *layer = 0);
+       void sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const char *layer = 0);
        void sync_camera(BL::Object b_override, int width, int height);
        void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
        int get_layer_samples() { return render_layer.samples; }
@@ -69,7 +69,8 @@ private:
        /* sync */
        void sync_lamps();
        void sync_materials();
-       void sync_objects(BL::SpaceView3D b_v3d);
+       void sync_objects(BL::SpaceView3D b_v3d, int motion = 0);
+       void sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override);
        void sync_film();
        void sync_integrator();
        void sync_view();
@@ -79,9 +80,11 @@ private:
 
        void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
        Mesh *sync_mesh(BL::Object b_ob, bool holdout, bool object_updated);
-       void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag);
+       void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag, int motion);
        void sync_light(BL::Object b_parent, int b_index, 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);
 
        /* util */
        void find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader);
index 67f3a3ab7d90672c2ec89eb96edc981e90610124..9184e14bc7608ece419cbe47a5714d95b7b70884 100644 (file)
@@ -49,8 +49,10 @@ void RE_engine_update_progress(struct RenderEngine *engine, float progress);
 void engine_tag_redraw(void *engine);
 void engine_tag_update(void *engine);
 int rna_Object_is_modified(void *ob, void *scene, int settings);
+int rna_Object_is_deform_modified(void *ob, void *scene, int settings);
 void BLI_timestr(double _time, char *str);
 void rna_ColorRamp_eval(void *coba, float position, float color[4]);
+void rna_Scene_frame_set(void *scene, int frame, float subframe);
 
 }
 
@@ -94,6 +96,16 @@ static inline bool object_is_modified(BL::Object self, BL::Scene scene, bool pre
        return rna_Object_is_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false;
 }
 
+static inline bool object_is_deform_modified(BL::Object self, BL::Scene scene, bool preview)
+{
+       return rna_Object_is_deform_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false;
+}
+
+static inline void scene_frame_set(BL::Scene scene, int frame)
+{
+       rna_Scene_frame_set(scene.ptr.data, frame, 0.0f);
+}
+
 /* Utilities */
 
 static inline Transform get_transform(BL::Array<float, 16> array)
index 523ae8ae92621fb92d7167ee24418c7889e12904..5da4253bd86b8b7e7f973f78244c55a85e5de999 100644 (file)
@@ -57,7 +57,7 @@ __device_inline float3 bvh_inverse_direction(float3 dir)
 
 __device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
 {
-       Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+       Transform tfm = object_fetch_transform(kg, object, ray->time, OBJECT_INVERSE_TRANSFORM);
 
        *P = transform_point(&tfm, ray->P);
 
@@ -74,7 +74,7 @@ __device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray
 
 __device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
 {
-       Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+       Transform tfm = object_fetch_transform(kg, object, ray->time, OBJECT_TRANSFORM);
 
        if(*t != FLT_MAX)
                *t *= len(transform_direction(&tfm, 1.0f/(*idir)));
@@ -341,7 +341,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
 #endif
 }
 
-__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray)
+__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray)
 {
        float3 P = ray->P;
        float3 D = ray->D;
@@ -349,7 +349,11 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection
 
 #ifdef __INTERSECTION_REFINE__
        if(isect->object != ~0) {
-               Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
+#ifdef __MOTION__
+               Transform tfm = sd->ob_itfm;
+#else
+               Transform tfm = object_fetch_transform(kg, isect->object, ray->time, OBJECT_INVERSE_TRANSFORM);
+#endif
 
                P = transform_point(&tfm, P);
                D = transform_direction(&tfm, D*t);
@@ -366,7 +370,12 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection
        P = P + D*rt;
 
        if(isect->object != ~0) {
-               Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
+#ifdef __MOTION__
+               Transform tfm = sd->ob_tfm;
+#else
+               Transform tfm = object_fetch_transform(kg, isect->object, ray->time, OBJECT_TRANSFORM);
+#endif
+
                P = transform_point(&tfm, P);
        }
 
index 99dac18d54527a1e993879ed7db80f8123cee775..7b93ed7c0e6ef8d65e0dd8b827dd71461890e3cd 100644 (file)
@@ -63,6 +63,11 @@ __device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float
        /* transform ray from camera to world */
        Transform cameratoworld = kernel_data.cam.cameratoworld;
 
+#ifdef __MOTION__
+       if(ray->time != TIME_INVALID)
+               transform_motion_interpolate(&cameratoworld, &kernel_data.cam.motion, ray->time);
+#endif
+
        ray->P = transform_point(&cameratoworld, ray->P);
        ray->D = transform_direction(&cameratoworld, ray->D);
        ray->D = normalize(ray->D);
@@ -101,6 +106,11 @@ __device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, floa
        /* transform ray from camera to world */
        Transform cameratoworld = kernel_data.cam.cameratoworld;
 
+#ifdef __MOTION__
+       if(ray->time != TIME_INVALID)
+               transform_motion_interpolate(&cameratoworld, &kernel_data.cam.motion, ray->time);
+#endif
+
        ray->P = transform_point(&cameratoworld, ray->P);
        ray->D = transform_direction(&cameratoworld, ray->D);
        ray->D = normalize(ray->D);
@@ -136,6 +146,11 @@ __device void camera_sample_environment(KernelGlobals *kg, float raster_x, float
        /* transform ray from camera to world */
        Transform cameratoworld = kernel_data.cam.cameratoworld;
 
+#ifdef __MOTION__
+       if(ray->time != TIME_INVALID)
+               transform_motion_interpolate(&cameratoworld, &kernel_data.cam.motion, ray->time);
+#endif
+
        ray->P = transform_point(&cameratoworld, ray->P);
        ray->D = transform_direction(&cameratoworld, ray->D);
        ray->D = normalize(ray->D);
@@ -162,14 +177,20 @@ __device void camera_sample_environment(KernelGlobals *kg, float raster_x, float
 
 /* Common */
 
-__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, float lens_u, float lens_v, Ray *ray)
+__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v,
+       float lens_u, float lens_v, float time, Ray *ray)
 {
        /* pixel filter */
        float raster_x = x + kernel_tex_interp(__filter_table, filter_u, FILTER_TABLE_SIZE);
        float raster_y = y + kernel_tex_interp(__filter_table, filter_v, FILTER_TABLE_SIZE);
 
+#ifdef __MOTION__
        /* motion blur */
-       //ray->time = lerp(time_t, kernel_data.cam.shutter_open, kernel_data.cam.shutter_close);
+       if(kernel_data.cam.shuttertime == 0.0f)
+               ray->time = TIME_INVALID;
+       else
+               ray->time = 0.5f + (time - 0.5f)*kernel_data.cam.shuttertime;
+#endif
 
        /* sample */
        if(kernel_data.cam.type == CAMERA_PERSPECTIVE)
index 764ac599991b5053f7cfbb8bc25f41fe3f6e2392..cd7701a0c75e3a93315832b02580d5228de25ede 100644 (file)
@@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN
 /* Direction Emission */
 
 __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
-       LightSample *ls, float u, float v, float3 I)
+       LightSample *ls, float u, float v, float3 I, float time)
 {
        /* setup shading at emitter */
        ShaderData sd;
@@ -40,7 +40,7 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
        else
 #endif
        {
-               shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v);
+               shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, time);
                ls->Ng = sd.Ng;
 
                /* no path flag, we're evaluating this for all closures. that's weak but
@@ -76,7 +76,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
 #endif
        {
                /* sample a light and position on int */
-               light_sample(kg, randt, randu, randv, sd->P, &ls, &pdf);
+               light_sample(kg, randt, randu, randv, sd->time, sd->P, &ls, &pdf);
        }
 
        /* compute pdf */
@@ -87,7 +87,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
                return false;
 
        /* evaluate closure */
-       float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D);
+       float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D, sd->time);
 
        if(is_zero(light_eval))
                return false;
index 42260577069324d4672dee9230c9d54b08f9c86e..c2cf293cab32d4dad92b7362772fe591533e173b 100644 (file)
@@ -251,7 +251,7 @@ __device float regular_light_pdf(KernelGlobals *kg,
 /* Triangle Light */
 
 __device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
-       float randu, float randv, LightSample *ls)
+       float randu, float randv, float time, LightSample *ls)
 {
        /* triangle, so get position, normal, shader */
        ls->P = triangle_sample_MT(kg, prim, randu, randv);
@@ -264,8 +264,11 @@ __device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
 #ifdef __INSTANCING__
        /* instance transform */
        if(ls->object >= 0) {
-               object_position_transform(kg, ls->object, &ls->P);
-               object_normal_transform(kg, ls->object, &ls->Ng);
+               Transform tfm = object_fetch_transform(kg, ls->object, time, OBJECT_TRANSFORM);
+               Transform itfm = object_fetch_transform(kg, ls->object, time, OBJECT_INVERSE_TRANSFORM);
+
+               ls->P = transform_point(&tfm, ls->P);
+               ls->Ng = transform_direction_transposed(&itfm, ls->Ng);
        }
 #endif
 }
@@ -313,7 +316,7 @@ __device int light_distribution_sample(KernelGlobals *kg, float randt)
 
 /* Generic Light */
 
-__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls, float *pdf)
+__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float time, float3 P, LightSample *ls, float *pdf)
 {
        /* sample index */
        int index = light_distribution_sample(kg, randt);
@@ -324,7 +327,7 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
 
        if(prim >= 0) {
                int object = __float_as_int(l.w);
-               triangle_light_sample(kg, prim, object, randu, randv, ls);
+               triangle_light_sample(kg, prim, object, randu, randv, time, ls);
        }
        else {
                int point = -prim-1;
index b676f58e5d4fd74251ee4c83dc6a8818c9f70feb..262ca848f2834ee724bf2002fe80f7e24165f40a 100644 (file)
@@ -20,41 +20,87 @@ CCL_NAMESPACE_BEGIN
 
 enum ObjectTransform {
        OBJECT_TRANSFORM = 0,
-       OBJECT_INVERSE_TRANSFORM = 4,
-       OBJECT_NORMAL_TRANSFORM = 8,
-       OBJECT_PROPERTIES = 12
+       OBJECT_INVERSE_TRANSFORM = 3,
+       OBJECT_PROPERTIES = 6,
+       OBJECT_TRANSFORM_MOTION_PRE = 8,
+       OBJECT_TRANSFORM_MOTION_POST = 12
 };
 
-__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
+__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, float time, enum ObjectTransform type)
 {
        Transform tfm;
 
+#ifdef __MOTION__
+       /* if we do motion blur */
+       if(time != TIME_INVALID) {
+               int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE;
+               float4 have_motion = kernel_tex_fetch(__objects, offset + 0);
+
+               /* if this object have motion */
+               if(have_motion.x != FLT_MAX) {
+                       /* fetch motion transforms */
+                       MotionTransform motion;
+
+                       motion.pre.x = have_motion;
+                       motion.pre.y = kernel_tex_fetch(__objects, offset + 1);
+                       motion.pre.z = kernel_tex_fetch(__objects, offset + 2);
+                       motion.pre.w = kernel_tex_fetch(__objects, offset + 3);
+
+                       motion.post.x = kernel_tex_fetch(__objects, offset + 4);
+                       motion.post.y = kernel_tex_fetch(__objects, offset + 5);
+                       motion.post.z = kernel_tex_fetch(__objects, offset + 6);
+                       motion.post.w = kernel_tex_fetch(__objects, offset + 7);
+
+                       /* interpolate (todo: do only once per object) */
+                       transform_motion_interpolate(&tfm, &motion, time);
+
+                       /* invert */
+                       if(type == OBJECT_INVERSE_TRANSFORM)
+                               tfm = transform_quick_inverse(tfm);
+
+                       return tfm;
+               }
+       }
+#endif
+
        int offset = object*OBJECT_SIZE + (int)type;
 
        tfm.x = kernel_tex_fetch(__objects, offset + 0);
        tfm.y = kernel_tex_fetch(__objects, offset + 1);
        tfm.z = kernel_tex_fetch(__objects, offset + 2);
-       tfm.w = kernel_tex_fetch(__objects, offset + 3);
+       tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
 
        return tfm;
 }
 
-__device_inline void object_position_transform(KernelGlobals *kg, int object, float3 *P)
+__device_inline void object_position_transform(KernelGlobals *kg, ShaderData *sd, float3 *P)
 {
-       Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+#ifdef __MOTION__
+       *P = transform_point(&sd->ob_tfm, *P);
+#else
+       Transform tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM);
        *P = transform_point(&tfm, *P);
+#endif
 }
 
-__device_inline void object_normal_transform(KernelGlobals *kg, int object, float3 *N)
+__device_inline void object_normal_transform(KernelGlobals *kg, ShaderData *sd, float3 *N)
 {
-       Transform tfm = object_fetch_transform(kg, object, OBJECT_NORMAL_TRANSFORM);
-       *N = normalize(transform_direction(&tfm, *N));
+#ifdef __MOTION__
+       *N = normalize(transform_direction_transposed(&sd->ob_itfm, *N));
+#else
+       Transform tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_INVERSE_TRANSFORM);
+       *N = normalize(transform_direction_transposed(&tfm, *N));
+#endif
 }
 
-__device_inline void object_dir_transform(KernelGlobals *kg, int object, float3 *D)
+__device_inline void object_dir_transform(KernelGlobals *kg, ShaderData *sd, float3 *D)
 {
-       Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+#ifdef __MOTION__
+       *D = transform_direction(&sd->ob_tfm, *D);
+#else
+       Transform tfm = object_fetch_transform(kg, sd->object, 0.0f, OBJECT_TRANSFORM);
        *D = transform_direction(&tfm, *D);
+#endif
 }
 
 __device_inline float object_surface_area(KernelGlobals *kg, int object)
index fd4ee17cdc1120e5e69aa012c43a2057c8766726..f3ddda4a392b46b955c9fe50ccc43144e3cbe1b2 100644 (file)
@@ -72,9 +72,14 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float
                        kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal);
                }
                if(flag & PASS_UV) {
-                       float3 uv = make_float3(0.0f, 0.0f, 0.0f); /* todo: request and lookup */
+                       float3 uv = triangle_uv(kg, sd);
                        kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, sample, uv);
                }
+               if(flag & PASS_MOTION) {
+                       float4 speed = triangle_motion_vector(kg, sd);
+                       kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, sample, speed);
+                       kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, sample, 1.0f);
+               }
        }
 
        if(flag & (PASS_DIFFUSE_INDIRECT|PASS_DIFFUSE_COLOR|PASS_DIFFUSE_DIRECT))
index 8ebac1772770b0e46521534d241f3ec9d558e873..b7c22087e1f3c7b739c68ad01121245e84ba9375 100644 (file)
@@ -18,8 +18,8 @@
 
 #include "kernel_differential.h"
 #include "kernel_montecarlo.h"
-#include "kernel_triangle.h"
 #include "kernel_object.h"
+#include "kernel_triangle.h"
 #ifdef __QBVH__
 #include "kernel_qbvh.h"
 #else
@@ -324,6 +324,9 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
                                light_ray.P = ray_offset(sd.P, sd.Ng);
                                light_ray.D = ao_D;
                                light_ray.t = kernel_data.background.ao_distance;
+#ifdef __MOTION__
+                               light_ray.time = sd.time;
+#endif
 
                                if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) {
                                        float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*kernel_data.background.ao_factor;
@@ -346,6 +349,10 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
                                BsdfEval L_light;
                                bool is_lamp;
 
+#ifdef __MOTION__
+                               light_ray.time = sd.time;
+#endif
+
 #ifdef __MULTI_LIGHT__
                                /* index -1 means randomly sample from distribution */
                                int i = (kernel_data.integrator.num_distribution)? -1: 0;
@@ -449,7 +456,13 @@ __device void kernel_path_trace(KernelGlobals *kg,
        float lens_u = path_rng(kg, &rng, sample, PRNG_LENS_U);
        float lens_v = path_rng(kg, &rng, sample, PRNG_LENS_V);
 
-       camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, &ray);
+#ifdef __MOTION__
+       float time = path_rng(kg, &rng, sample, PRNG_TIME);
+#else
+       float time = 0.0f;
+#endif
+
+       camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, &ray);
 
        /* integrate */
        float4 L = kernel_path_integrate(kg, &rng, sample, ray, buffer);
index 46ef5d2022ae967ee67030c30c907daa9df0a6db..b2f2a7577be697ae02139e1d54c87f03d5a49be5 100644 (file)
@@ -53,16 +53,9 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
        float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
        int shader = __float_as_int(Ns.w);
 
-       /* vectors */
-       sd->P = bvh_triangle_refine(kg, isect, ray);
-       sd->Ng = Ng;
-       sd->N = Ng;
-       sd->I = -ray->D;
-       sd->shader = shader;
-
        /* triangle */
 #ifdef __INSTANCING__
-       sd->object = isect->object;
+       sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
 #endif
        sd->prim = prim;
 #ifdef __UV__
@@ -70,6 +63,21 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
        sd->v = isect->v;
 #endif
 
+       /* matrices and time */
+#ifdef __MOTION__
+       sd->ob_tfm = object_fetch_transform(kg, sd->object, ray->time, OBJECT_TRANSFORM);
+       sd->ob_itfm = object_fetch_transform(kg, sd->object, ray->time, OBJECT_INVERSE_TRANSFORM);
+
+       sd->time = ray->time;
+#endif
+
+       /* vectors */
+       sd->P = bvh_triangle_refine(kg, sd, isect, ray);
+       sd->Ng = Ng;
+       sd->N = Ng;
+       sd->I = -ray->D;
+       sd->shader = shader;
+
        /* smooth normal */
        if(sd->shader & SHADER_SMOOTH_NORMAL)
                sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
@@ -82,19 +90,15 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 #endif
 
 #ifdef __INSTANCING__
-       if(sd->object != ~0) {
+       if(isect->object != ~0) {
                /* instance transform */
-               object_normal_transform(kg, sd->object, &sd->N);
-               object_normal_transform(kg, sd->object, &sd->Ng);
+               object_normal_transform(kg, sd, &sd->N);
+               object_normal_transform(kg, sd, &sd->Ng);
 #ifdef __DPDU__
-               object_dir_transform(kg, sd->object, &sd->dPdu);
-               object_dir_transform(kg, sd->object, &sd->dPdv);
+               object_dir_transform(kg, sd, &sd->dPdu);
+               object_dir_transform(kg, sd, &sd->dPdv);
 #endif
        }
-       else {
-               /* non-instanced object index */
-               sd->object = kernel_tex_fetch(__prim_object, isect->prim);
-       }
 #endif
 
        /* backfacing test */
@@ -122,7 +126,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 
 __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
        const float3 P, const float3 Ng, const float3 I,
-       int shader, int object, int prim,  float u, float v)
+       int shader, int object, int prim, float u, float v, float time)
 {
        /* vectors */
        sd->P = P;
@@ -155,13 +159,20 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
        }
 #endif
 
+#ifdef __MOTION__
+       sd->time = time;
+
+       sd->ob_tfm = object_fetch_transform(kg, sd->object, time, OBJECT_TRANSFORM);
+       sd->ob_itfm = object_fetch_transform(kg, sd->object, time, OBJECT_INVERSE_TRANSFORM);
+#endif
+
        /* smooth normal */
        if(sd->shader & SHADER_SMOOTH_NORMAL) {
                sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
 
 #ifdef __INSTANCING__
                if(instanced)
-                       object_normal_transform(kg, sd->object, &sd->N);
+                       object_normal_transform(kg, sd, &sd->N);
 #endif
        }
 
@@ -178,8 +189,8 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
 
 #ifdef __INSTANCING__
                if(instanced) {
-                       object_dir_transform(kg, sd->object, &sd->dPdu);
-                       object_dir_transform(kg, sd->object, &sd->dPdv);
+                       object_dir_transform(kg, sd, &sd->dPdu);
+                       object_dir_transform(kg, sd, &sd->dPdv);
                }
 #endif
        }
@@ -229,7 +240,7 @@ __device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
 
        /* watch out: no instance transform currently */
 
-       shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v);
+       shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, TIME_INVALID);
 }
 
 /* ShaderData setup from ray into background */
@@ -243,6 +254,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
        sd->I = -sd->P;
        sd->shader = kernel_data.background.shader;
        sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+#ifdef __MOTION__
+       sd->time = ray->time;
+#endif
 
 #ifdef __INSTANCING__
        sd->object = ~0;
index 7eaf54d14bffc3e37a8f8678abdd3acc83be1b09..1b3956c1dd4e0e4421aca54ebf5c37eb97dd51aa 100644 (file)
@@ -179,5 +179,68 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s
        }
 }
 
+/* motion */
+
+__device int triangle_find_attribute(KernelGlobals *kg, ShaderData *sd, uint id)
+{
+       /* find attribute by unique id */
+       uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+       uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+
+       while(attr_map.x != id)
+               attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
+
+       /* return result */
+       return (attr_map.y == ATTR_ELEMENT_NONE)? ATTR_STD_NOT_FOUND: attr_map.z;
+}
+
+__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd)
+{
+       float3 motion_pre = sd->P, motion_post = sd->P;
+
+       /* deformation motion */
+       int offset_pre = triangle_find_attribute(kg, sd, ATTR_STD_MOTION_PRE);
+       int offset_post = triangle_find_attribute(kg, sd, ATTR_STD_MOTION_POST);
+
+       if(offset_pre != ATTR_STD_NOT_FOUND)
+               motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL);
+       if(offset_post != ATTR_STD_NOT_FOUND)
+               motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, 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 */
+       Transform tfm;
+       
+       tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM_MOTION_PRE);
+       motion_pre = transform_point(&tfm, motion_pre);
+
+       tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM_MOTION_POST);
+       motion_post = transform_point(&tfm, motion_post);
+
+       /* camera motion */
+       tfm = kernel_data.cam.worldtoraster;
+       float3 P = transform_perspective(&tfm, sd->P);
+
+       tfm = kernel_data.cam.motion.pre;
+       motion_pre = transform_perspective(&tfm, motion_pre) - P;
+
+       tfm = kernel_data.cam.motion.post;
+       motion_post = P - transform_perspective(&tfm, motion_post);
+
+       return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
+}
+
+__device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd)
+{
+       int offset_uv = triangle_find_attribute(kg, sd, ATTR_STD_UV);
+
+       if(offset_uv == ATTR_STD_NOT_FOUND)
+               return make_float3(0.0f, 0.0f, 0.0f);
+
+       float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL);
+       uv.z = 1.0f;
+       return uv;
+}
+
 CCL_NAMESPACE_END
 
index 102a2bb036dc27405cbf206889a4c59953aa8d5d..e91030870257f9f43c95c62c1dc3f29d65e4291e 100644 (file)
 #define __KERNEL_TYPES_H__
 
 #include "kernel_math.h"
-
 #include "svm/svm_types.h"
 
+#ifndef __KERNEL_GPU__
+#define __KERNEL_CPU__
+#endif
+
 CCL_NAMESPACE_BEGIN
 
 /* constants */
@@ -30,6 +33,7 @@ CCL_NAMESPACE_BEGIN
 #define LIGHT_SIZE                     4
 #define FILTER_TABLE_SIZE      256
 #define RAMP_TABLE_SIZE                256
+#define TIME_INVALID           FLT_MAX
 
 /* device capabilities */
 #ifdef __KERNEL_CPU__
@@ -75,6 +79,7 @@ CCL_NAMESPACE_BEGIN
 #define __PASSES__
 #define __BACKGROUND_MIS__
 #define __AO__
+//#define __MOTION__
 #endif
 
 //#define __MULTI_LIGHT__
@@ -90,14 +95,21 @@ enum ShaderEvalType {
        SHADER_EVAL_BACKGROUND
 };
 
-/* Path Tracing */
+/* Path Tracing
+ * note we need to keep the u/v pairs at even values */
 
 enum PathTraceDimension {
        PRNG_FILTER_U = 0,
        PRNG_FILTER_V = 1,
        PRNG_LENS_U = 2,
        PRNG_LENS_V = 3,
+#ifdef __MOTION__
+       PRNG_TIME = 4,
+       PRNG_UNUSED = 5,
+       PRNG_BASE_NUM = 6,
+#else
        PRNG_BASE_NUM = 4,
+#endif
 
        PRNG_BSDF_U = 0,
        PRNG_BSDF_V = 1,
@@ -177,7 +189,9 @@ typedef enum PassType {
        PASS_EMISSION = 65536,
        PASS_BACKGROUND = 131072,
        PASS_AO = 262144,
-       PASS_SHADOW = 524288
+       PASS_SHADOW = 524288,
+       PASS_MOTION = 1048576,
+       PASS_MOTION_WEIGHT = 2097152
 } PassType;
 
 #define PASS_ALL (~0)
@@ -275,6 +289,7 @@ typedef struct Ray {
        float3 P;
        float3 D;
        float t;
+       float time;
 
 #ifdef __RAY_DIFFERENTIALS__
        differential3 dP;
@@ -300,6 +315,21 @@ typedef enum AttributeElement {
        ATTR_ELEMENT_NONE
 } AttributeElement;
 
+typedef enum AttributeStandard {
+       ATTR_STD_NONE = 0,
+       ATTR_STD_VERTEX_NORMAL,
+       ATTR_STD_FACE_NORMAL,
+       ATTR_STD_UV,
+       ATTR_STD_GENERATED,
+       ATTR_STD_POSITION_UNDEFORMED,
+       ATTR_STD_POSITION_UNDISPLACED,
+       ATTR_STD_MOTION_PRE,
+       ATTR_STD_MOTION_POST,
+       ATTR_STD_NUM,
+
+       ATTR_STD_NOT_FOUND = ~0
+} AttributeStandard;
+
 /* Closure data */
 
 #define MAX_CLOSURE 8
@@ -365,6 +395,16 @@ typedef struct ShaderData {
        /* object id if there is one, ~0 otherwise */
        int object;
 
+       /* motion blur sample time */
+       float time;
+
+#ifdef __MOTION__
+       /* object <-> world space transformations, cached to avoid
+        * re-interpolating them constantly for shading */
+       Transform ob_tfm;
+       Transform ob_itfm;
+#endif
+
 #ifdef __RAY_DIFFERENTIALS__
        /* differential of P. these are orthogonal to Ng, not N */
        differential3 dP;
@@ -422,8 +462,8 @@ typedef struct KernelCamera {
        float focaldistance;
 
        /* motion blur */
-       float shutteropen;
-       float shutterclose;
+       float shuttertime;
+       float pad;
 
        /* clipping */
        float nearclip;
@@ -437,6 +477,8 @@ typedef struct KernelCamera {
        Transform worldtoraster;
        Transform worldtondc;
        Transform worldtocamera;
+
+       MotionTransform motion;
 } KernelCamera;
 
 typedef struct KernelFilm {
@@ -448,27 +490,32 @@ typedef struct KernelFilm {
        int pass_combined;
        int pass_depth;
        int pass_normal;
-       int pass_pad;
+       int pass_motion;
 
+       int pass_motion_weight;
        int pass_uv;
        int pass_object_id;
        int pass_material_id;
-       int pass_diffuse_color;
 
+       int pass_diffuse_color;
        int pass_glossy_color;
        int pass_transmission_color;
        int pass_diffuse_indirect;
-       int pass_glossy_indirect;
 
+       int pass_glossy_indirect;
        int pass_transmission_indirect;
        int pass_diffuse_direct;
        int pass_glossy_direct;
-       int pass_transmission_direct;
 
+       int pass_transmission_direct;
        int pass_emission;
        int pass_background;
        int pass_ao;
+
        int pass_shadow;
+       int pass_pad1;
+       int pass_pad2;
+       int pass_pad3;
 } KernelFilm;
 
 typedef struct KernelBackground {
index 98f8734aed29437dc05f49e990daa0f97f032407..5ecda7952519a220558f28840a18dfcf12c2775a 100644 (file)
@@ -33,8 +33,8 @@ __device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack
        switch(type) {
                case NODE_TEXCO_OBJECT: {
                        if(sd->object != ~0) {
-                               Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-                               data = transform_point(&tfm, sd->P);
+                               data = sd->P;
+                               object_position_transform(kg, sd, &data);
                        }
                        else
                                data = sd->P;
@@ -42,8 +42,8 @@ __device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack
                }
                case NODE_TEXCO_NORMAL: {
                        if(sd->object != ~0) {
-                               Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-                               data = transform_direction(&tfm, sd->N);
+                               data = sd->N;
+                               object_normal_transform(kg, sd, &data);
                        }
                        else
                                data = sd->N;
@@ -87,8 +87,8 @@ __device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, floa
        switch(type) {
                case NODE_TEXCO_OBJECT: {
                        if(sd->object != ~0) {
-                               Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-                               data = transform_point(&tfm, sd->P + sd->dP.dx);
+                               data = sd->P + sd->dP.dx;
+                               object_position_transform(kg, sd, &data);
                        }
                        else
                                data = sd->P + sd->dP.dx;
@@ -96,8 +96,8 @@ __device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, floa
                }
                case NODE_TEXCO_NORMAL: {
                        if(sd->object != ~0) {
-                               Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-                               data = transform_direction(&tfm, sd->N);
+                               data = sd->N;
+                               object_normal_transform(kg, sd, &data);
                        }
                        else
                                data = sd->N;
@@ -144,8 +144,8 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa
        switch(type) {
                case NODE_TEXCO_OBJECT: {
                        if(sd->object != ~0) {
-                               Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-                               data = transform_point(&tfm, sd->P + sd->dP.dy);
+                               data = sd->P + sd->dP.dy;
+                               object_position_transform(kg, sd, &data);
                        }
                        else
                                data = sd->P + sd->dP.dy;
@@ -153,8 +153,8 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa
                }
                case NODE_TEXCO_NORMAL: {
                        if(sd->object != ~0) {
-                               Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-                               data = normalize(transform_direction(&tfm, sd->N));
+                               data = sd->N;
+                               object_normal_transform(kg, sd, &data);
                        }
                        else
                                data = sd->N;
index db92cf4ef5430a0618a29a2e481f93afed253f58..4d4fbfe681460a3ea19bd59de51c3fff42e8ae9b 100644 (file)
@@ -16,7 +16,7 @@ set(SRC
        buffers.cpp
        camera.cpp
        film.cpp
-       # film_response.cpp  # XXX, why isn't this in?
+       # film_response.cpp (code unused)
        filter.cpp
        graph.cpp
        image.cpp
@@ -41,7 +41,7 @@ set(SRC_HEADERS
        buffers.h
        camera.h
        film.h
-       # film_response.h  # XXX, why isn't this in?
+       # film_response.h (code unused)
        filter.h
        graph.h
        image.h
index 9e90bf1b6253a3ec31992d9e181264b6f2382299..c1a089cc8721abd2cec61977212b5a876617d505 100644 (file)
@@ -31,7 +31,7 @@ void Attribute::set(ustring name_, TypeDesc type_, Element element_)
        name = name_;
        type = type_;
        element = element_;
-       std = STD_NONE;
+       std = ATTR_STD_NONE;
 
        /* string and matrix not supported! */
        assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
@@ -81,20 +81,24 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b)
        return false;
 }
 
-ustring Attribute::standard_name(Attribute::Standard std)
+ustring Attribute::standard_name(AttributeStandard std)
 {
-       if(std == Attribute::STD_VERTEX_NORMAL)
+       if(std == ATTR_STD_VERTEX_NORMAL)
                return ustring("N");
-       else if(std == Attribute::STD_FACE_NORMAL)
+       else if(std == ATTR_STD_FACE_NORMAL)
                return ustring("Ng");
-       else if(std == Attribute::STD_UV)
+       else if(std == ATTR_STD_UV)
                return ustring("uv");
-       else if(std == Attribute::STD_GENERATED)
+       else if(std == ATTR_STD_GENERATED)
                return ustring("generated");
-       else if(std == Attribute::STD_POSITION_UNDEFORMED)
+       else if(std == ATTR_STD_POSITION_UNDEFORMED)
                return ustring("undeformed");
-       else if(std == Attribute::STD_POSITION_UNDISPLACED)
+       else if(std == ATTR_STD_POSITION_UNDISPLACED)
                return ustring("undisplaced");
+       else if(std == ATTR_STD_MOTION_PRE)
+               return ustring("motion_pre");
+       else if(std == ATTR_STD_MOTION_POST)
+               return ustring("motion_post");
 
        return ustring();
 }
@@ -164,24 +168,28 @@ void AttributeSet::remove(ustring name)
        }
 }
 
-Attribute *AttributeSet::add(Attribute::Standard std, ustring name)
+Attribute *AttributeSet::add(AttributeStandard std, ustring name)
 {
        Attribute *attr = NULL;
 
        if(name == ustring())
                name = Attribute::standard_name(std);
 
-       if(std == Attribute::STD_VERTEX_NORMAL)
+       if(std == ATTR_STD_VERTEX_NORMAL)
                attr = add(name, TypeDesc::TypeNormal, Attribute::VERTEX);
-       else if(std == Attribute::STD_FACE_NORMAL)
+       else if(std == ATTR_STD_FACE_NORMAL)
                attr = add(name, TypeDesc::TypeNormal, Attribute::FACE);
-       else if(std == Attribute::STD_UV)
+       else if(std == ATTR_STD_UV)
                attr = add(name, TypeDesc::TypePoint, Attribute::CORNER);
-       else if(std == Attribute::STD_GENERATED)
+       else if(std == ATTR_STD_GENERATED)
                attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
-       else if(std == Attribute::STD_POSITION_UNDEFORMED)
+       else if(std == ATTR_STD_POSITION_UNDEFORMED)
                attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
-       else if(std == Attribute::STD_POSITION_UNDISPLACED)
+       else if(std == ATTR_STD_POSITION_UNDISPLACED)
+               attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
+       else if(std == ATTR_STD_MOTION_PRE)
+               attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
+       else if(std == ATTR_STD_MOTION_POST)
                attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
        else
                assert(0);
@@ -191,7 +199,7 @@ Attribute *AttributeSet::add(Attribute::Standard std, ustring name)
        return attr;
 }
 
-Attribute *AttributeSet::find(Attribute::Standard std)
+Attribute *AttributeSet::find(AttributeStandard std)
 {
        foreach(Attribute& attr, attributes)
                if(attr.std == std)
@@ -200,7 +208,7 @@ Attribute *AttributeSet::find(Attribute::Standard std)
        return NULL;
 }
 
-void AttributeSet::remove(Attribute::Standard std)
+void AttributeSet::remove(AttributeStandard std)
 {
        Attribute *attr = find(std);
 
@@ -218,7 +226,7 @@ void AttributeSet::remove(Attribute::Standard std)
 
 Attribute *AttributeSet::find(AttributeRequest& req)
 {
-       if(req.std == Attribute::STD_NONE)
+       if(req.std == ATTR_STD_NONE)
                return find(req.name);
        else
                return find(req.std);
@@ -240,14 +248,14 @@ void AttributeSet::clear()
 AttributeRequest::AttributeRequest(ustring name_)
 {
        name = name_;
-       std = Attribute::STD_NONE;
+       std = ATTR_STD_NONE;
 
        type = TypeDesc::TypeFloat;
        element = ATTR_ELEMENT_NONE;
        offset = 0;
 }
 
-AttributeRequest::AttributeRequest(Attribute::Standard std_)
+AttributeRequest::AttributeRequest(AttributeStandard std_)
 {
        name = ustring();
        std = std_;
@@ -296,7 +304,7 @@ void AttributeRequestSet::add(ustring name)
        requests.push_back(AttributeRequest(name));
 }
 
-void AttributeRequestSet::add(Attribute::Standard std)
+void AttributeRequestSet::add(AttributeStandard std)
 {
        foreach(AttributeRequest& req, requests)
                if(req.std == std)
@@ -308,7 +316,7 @@ void AttributeRequestSet::add(Attribute::Standard std)
 void AttributeRequestSet::add(AttributeRequestSet& reqs)
 {
        foreach(AttributeRequest& req, reqs.requests) {
-               if(req.std == Attribute::STD_NONE)
+               if(req.std == ATTR_STD_NONE)
                        add(req.name);
                else
                        add(req.std);
@@ -324,7 +332,7 @@ bool AttributeRequestSet::find(ustring name)
        return false;
 }
 
-bool AttributeRequestSet::find(Attribute::Standard std)
+bool AttributeRequestSet::find(AttributeStandard std)
 {
        foreach(AttributeRequest& req, requests)
                if(req.std == std)
index 7af4657daa3efb114d0497c8d33f55fcb8376919..707d558fc794465c937ac0acc3613a1d9de34ceb 100644 (file)
@@ -47,19 +47,8 @@ public:
                CORNER
        };
 
-       enum Standard {
-               STD_NONE = 0,
-               STD_VERTEX_NORMAL,
-               STD_FACE_NORMAL,
-               STD_UV,
-               STD_GENERATED,
-               STD_POSITION_UNDEFORMED,
-               STD_POSITION_UNDISPLACED,
-               STD_NUM
-       };
-
        ustring name;
-       Standard std;
+       AttributeStandard std;
 
        TypeDesc type;
        vector<char> buffer;
@@ -82,7 +71,7 @@ public:
        const float *data_float() const { return (float*)data(); }
 
        static bool same_storage(TypeDesc a, TypeDesc b);
-       static ustring standard_name(Attribute::Standard std);
+       static ustring standard_name(AttributeStandard std);
 };
 
 /* Attribute Set
@@ -101,9 +90,9 @@ public:
        Attribute *find(ustring name);
        void remove(ustring name);
 
-       Attribute *add(Attribute::Standard std, ustring name = ustring());
-       Attribute *find(Attribute::Standard std);
-       void remove(Attribute::Standard std);
+       Attribute *add(AttributeStandard std, ustring name = ustring());
+       Attribute *find(AttributeStandard std);
+       void remove(AttributeStandard std);
 
        Attribute *find(AttributeRequest& req);
 
@@ -120,7 +109,7 @@ public:
 class AttributeRequest {
 public:
        ustring name;
-       Attribute::Standard std;
+       AttributeStandard std;
 
        /* temporary variables used by MeshManager */
        TypeDesc type;
@@ -128,7 +117,7 @@ public:
        int offset;
 
        AttributeRequest(ustring name_);
-       AttributeRequest(Attribute::Standard std);
+       AttributeRequest(AttributeStandard std);
 };
 
 /* AttributeRequestSet
@@ -143,11 +132,11 @@ public:
        ~AttributeRequestSet();
 
        void add(ustring name);
-       void add(Attribute::Standard std);
+       void add(AttributeStandard std);
        void add(AttributeRequestSet& reqs);
 
        bool find(ustring name);
-       bool find(Attribute::Standard std);
+       bool find(AttributeStandard std);
 
        size_t size();
        void clear();
index bda20a8ab9d6ab3cd084c07b56ceec8794566574..a80851b945a14746414609cdf4d2b553058332b7 100644 (file)
@@ -221,6 +221,28 @@ bool RenderBuffers::get_pass(PassType type, float exposure, int sample, int comp
                                        pixels[3] = 1.0f;
                                }
                        }
+                       else if(type == PASS_MOTION) {
+                               /* need to normalize by number of samples accumulated for motion */
+                               pass_offset = 0;
+                               foreach(Pass& color_pass, params.passes) {
+                                       if(color_pass.type == PASS_MOTION_WEIGHT)
+                                               break;
+                                       pass_offset += color_pass.components;
+                               }
+
+                               float *in_weight = (float*)buffer.data_pointer + pass_offset;
+
+                               for(int i = 0; i < size; i++, in += pass_stride, in_weight += pass_stride, pixels += 4) {
+                                       float4 f = make_float4(in[0], in[1], in[2], in[3]);
+                                       float w = in_weight[0];
+                                       float invw = (w > 0.0f)? 1.0f/w: 0.0f;
+
+                                       pixels[0] = f.x*invw;
+                                       pixels[1] = f.y*invw;
+                                       pixels[2] = f.z*invw;
+                                       pixels[3] = f.w*invw;
+                               }
+                       }
                        else {
                                for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
                                        float4 f = make_float4(in[0], in[1], in[2], in[3]);
index f9290dfc83544d59da2b6a451c65cd20b69b448c..e9ca7c3a366939e55d05588d70db4f3e78e41f60 100644 (file)
@@ -25,8 +25,7 @@ CCL_NAMESPACE_BEGIN
 
 Camera::Camera()
 {
-       shutteropen = 0.0f;
-       shutterclose = 1.0f;
+       shuttertime = 1.0f;
 
        aperturesize = 0.0f;
        focaldistance = 10.0f;
@@ -35,6 +34,10 @@ Camera::Camera()
 
        matrix = transform_identity();
 
+       motion.pre = transform_identity();
+       motion.post = transform_identity();
+       use_motion = false;
+
        type = CAMERA_PERSPECTIVE;
        fov = M_PI_F/4.0f;
 
@@ -124,7 +127,7 @@ void Camera::update()
        need_device_update = true;
 }
 
-void Camera::device_update(Device *device, DeviceScene *dscene)
+void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
 {
        update();
 
@@ -140,10 +143,28 @@ void Camera::device_update(Device *device, DeviceScene *dscene)
        kcam->rastertocamera = rastertocamera;
        kcam->cameratoworld = cameratoworld;
        kcam->worldtoscreen = transform_inverse(screentoworld);
-       kcam->worldtoraster = transform_inverse(rastertoworld);
+       kcam->worldtoraster = worldtoraster;
        kcam->worldtondc = transform_inverse(ndctoworld);
        kcam->worldtocamera = transform_inverse(cameratoworld);
 
+       /* camera motion */
+       Scene::MotionType need_motion = scene->need_motion();
+
+       if(need_motion == Scene::MOTION_PASS) {
+               if(use_motion) {
+                       kcam->motion.pre = transform_inverse(motion.pre * rastertocamera);
+                       kcam->motion.post = transform_inverse(motion.post * rastertocamera);
+               }
+               else {
+                       kcam->motion.pre = worldtoraster;
+                       kcam->motion.post = worldtoraster;
+               }
+       }
+       else if(need_motion == Scene::MOTION_BLUR) {
+               /* todo: exact camera position will not be hit this way */
+               transform_motion_decompose(&kcam->motion, &motion);
+       }
+
        /* depth of field */
        kcam->aperturesize = aperturesize;
        kcam->focaldistance = focaldistance;
@@ -151,8 +172,7 @@ void Camera::device_update(Device *device, DeviceScene *dscene)
        kcam->bladesrotation = bladesrotation;
 
        /* motion blur */
-       kcam->shutteropen = shutteropen;
-       kcam->shutterclose = shutterclose;
+       kcam->shuttertime= (need_motion == Scene::MOTION_BLUR)? shuttertime: 0.0f;
 
        /* type */
        kcam->type = type;
@@ -175,8 +195,7 @@ void Camera::device_free(Device *device, DeviceScene *dscene)
 
 bool Camera::modified(const Camera& cam)
 {
-       return !((shutteropen == cam.shutteropen) &&
-               (shutterclose == cam.shutterclose) &&
+       return !((shuttertime== cam.shuttertime) &&
                (aperturesize == cam.aperturesize) &&
                (blades == cam.blades) &&
                (bladesrotation == cam.bladesrotation) &&
@@ -192,7 +211,9 @@ bool Camera::modified(const Camera& cam)
                (right == cam.right) &&
                (bottom == cam.bottom) &&
                (top == cam.top) &&
-               (matrix == cam.matrix));
+               (matrix == cam.matrix) &&
+               (motion == cam.motion) &&
+               (use_motion == cam.use_motion));
 }
 
 void Camera::tag_update()
index cfcc5406ee35c16fbe3cc6251a0c006604e22df3..935489711c84f9dc39863eadefaec223f01d71ce 100644 (file)
@@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN
 
 class Device;
 class DeviceScene;
+class Scene;
 
 /* Camera
  *
@@ -37,8 +38,7 @@ class DeviceScene;
 class Camera {
 public:
        /* motion blur */
-       float shutteropen;
-       float shutterclose;
+       float shuttertime;
 
        /* depth of field */
        float focaldistance;
@@ -61,6 +61,10 @@ public:
        /* transformation */
        Transform matrix;
 
+       /* motion */
+       MotionTransform motion;
+       bool use_motion;
+
        /* computed camera parameters */
     Transform screentoworld;
        Transform rastertoworld;
@@ -82,7 +86,7 @@ public:
 
        void update();
 
-       void device_update(Device *device, DeviceScene *dscene);
+       void device_update(Device *device, DeviceScene *dscene, Scene *scene);
        void device_free(Device *device, DeviceScene *dscene);
 
        bool modified(const Camera& cam);
index cc17f86fcb67860479cae6a55ddc498828cf88d4..55c89b7b1b2641ed3cc7835e06079900c8fc2c19 100644 (file)
@@ -67,6 +67,13 @@ void Pass::add(PassType type, vector<Pass>& passes)
                case PASS_UV:
                        pass.components = 4;
                        break;
+               case PASS_MOTION:
+                       pass.components = 4;
+                       pass.divide_type = PASS_MOTION_WEIGHT;
+                       break;
+               case PASS_MOTION_WEIGHT:
+                       pass.components = 1;
+                       break;
                case PASS_OBJECT_ID:
                        pass.components = 1;
                        pass.filter = false;
@@ -154,6 +161,15 @@ bool Pass::equals(const vector<Pass>& A, const vector<Pass>& B)
        return true;
 }
 
+bool Pass::contains(const vector<Pass>& passes, PassType type)
+{
+       foreach(const Pass& pass, passes)
+               if(pass.type == type)
+                       return true;
+       
+       return false;
+}
+
 /* Film */
 
 Film::Film()
@@ -196,6 +212,12 @@ void Film::device_update(Device *device, DeviceScene *dscene)
                        case PASS_UV:
                                kfilm->pass_uv = kfilm->pass_stride;
                                break;
+                       case PASS_MOTION:
+                               kfilm->pass_motion = kfilm->pass_stride;
+                               break;
+                       case PASS_MOTION_WEIGHT:
+                               kfilm->pass_motion_weight = kfilm->pass_stride;
+                               break;
                        case PASS_OBJECT_ID:
                                kfilm->pass_object_id = kfilm->pass_stride;
                                break;
index 8a3dbbf1b0872f0e10604ec573183f3560c5f951..c7d2ee243881545e654ba50535d12bb9087fe041 100644 (file)
@@ -40,6 +40,7 @@ public:
 
        static void add(PassType type, vector<Pass>& passes);
        static bool equals(const vector<Pass>& A, const vector<Pass>& B);
+       static bool contains(const vector<Pass>& passes, PassType);
 };
 
 class Film {
index cc29047f0487cad59dd33afe311e0cea216383bb..d9486de47c9975d916b5181c8f9c9df24eb4e504 100644 (file)
@@ -120,9 +120,9 @@ void ShaderNode::attributes(AttributeRequestSet *attributes)
        foreach(ShaderInput *input, inputs) {
                if(!input->link) {
                        if(input->default_value == ShaderInput::TEXTURE_GENERATED)
-                               attributes->add(Attribute::STD_GENERATED);
+                               attributes->add(ATTR_STD_GENERATED);
                        else if(input->default_value == ShaderInput::TEXTURE_UV)
-                               attributes->add(Attribute::STD_UV);
+                               attributes->add(ATTR_STD_UV);
                }
        }
 }
index c1f066df10cea011e25c082381a55219ba940b91..b26ebfd91e178733c82773d724a1f4b8f152bded 100644 (file)
@@ -45,6 +45,7 @@ Integrator::Integrator()
        seed = 0;
        layer_flag = ~0;
        sample_clamp = 0.0f;
+       motion_blur = false;
 
        need_update = true;
 }
@@ -125,7 +126,8 @@ bool Integrator::modified(const Integrator& integrator)
                filter_glossy == integrator.filter_glossy &&
                layer_flag == integrator.layer_flag &&
                seed == integrator.seed &&
-               sample_clamp == integrator.sample_clamp);
+               sample_clamp == integrator.sample_clamp &&
+               motion_blur == integrator.motion_blur);
 }
 
 void Integrator::tag_update(Scene *scene)
index 0817fcaa457ec807481761e15a7cab291fcddf41..afda41a857ddc022412ed8fcad9e6ad851e93b8c 100644 (file)
@@ -47,6 +47,7 @@ public:
        int layer_flag;
 
        float sample_clamp;
+       bool motion_blur;
 
        bool need_update;
 
index 0ce16e65621e82aef13f21264f3535d52555977f..5d96611ff26a3c7e9918c43468dec49f171dcb2e 100644 (file)
@@ -113,11 +113,11 @@ void Mesh::compute_bounds()
 void Mesh::add_face_normals()
 {
        /* don't compute if already there */
-       if(attributes.find(Attribute::STD_FACE_NORMAL))
+       if(attributes.find(ATTR_STD_FACE_NORMAL))
                return;
 
        /* get attributes */
-       Attribute *attr_fN = attributes.add(Attribute::STD_FACE_NORMAL);
+       Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
        float3 *fN = attr_fN->data_float3();
 
        /* compute face normals */
@@ -145,12 +145,12 @@ void Mesh::add_face_normals()
 void Mesh::add_vertex_normals()
 {
        /* don't compute if already there */
-       if(attributes.find(Attribute::STD_VERTEX_NORMAL))
+       if(attributes.find(ATTR_STD_VERTEX_NORMAL))
                return;
 
        /* get attributes */
-       Attribute *attr_fN = attributes.find(Attribute::STD_FACE_NORMAL);
-       Attribute *attr_vN = attributes.add(Attribute::STD_VERTEX_NORMAL);
+       Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
+       Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
 
        float3 *fN = attr_fN->data_float3();
        float3 *vN = attr_vN->data_float3();
@@ -179,8 +179,8 @@ void Mesh::add_vertex_normals()
 
 void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
 {
-       Attribute *attr_fN = attributes.find(Attribute::STD_FACE_NORMAL);
-       Attribute *attr_vN = attributes.find(Attribute::STD_VERTEX_NORMAL);
+       Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
+       Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
 
        float3 *fN = attr_fN->data_float3();
        float3 *vN = attr_vN->data_float3();
@@ -348,7 +348,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
                        else
                                osl_attr.type = TypeDesc::TypeColor;
 
-                       if(req.std != Attribute::STD_NONE) {
+                       if(req.std != ATTR_STD_NONE) {
                                /* if standard attribute, add lookup by std:: name convention */
                                ustring stdname = ustring(string("std::") + Attribute::standard_name(req.std).c_str());
                                og->attribute_map[i][stdname] = osl_attr;
@@ -371,7 +371,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
        int attr_map_stride = 0;
 
        for(size_t i = 0; i < scene->meshes.size(); i++)
-               attr_map_stride = max(attr_map_stride, mesh_attributes[i].size());
+               attr_map_stride = max(attr_map_stride, mesh_attributes[i].size()+1);
 
        if(attr_map_stride == 0)
                return;
@@ -393,13 +393,12 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
                AttributeRequestSet& attributes = mesh_attributes[j];
 
                /* set object attributes */
-               j = 0;
+               int index = i*attr_map_stride;
 
                foreach(AttributeRequest& req, attributes.requests) {
-                       int index = i*attr_map_stride + j;
                        uint id;
 
-                       if(req.std == Attribute::STD_NONE)
+                       if(req.std == ATTR_STD_NONE)
                                id = scene->shader_manager->get_attribute_id(req.name);
                        else
                                id = scene->shader_manager->get_attribute_id(req.std);
@@ -413,8 +412,14 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
                        else
                                attr_map[index].w = NODE_ATTR_FLOAT3;
 
-                       j++;
+                       index++;
                }
+
+               /* terminator */
+               attr_map[index].x = ATTR_STD_NONE;
+               attr_map[index].y = 0;
+               attr_map[index].z = 0;
+               attr_map[index].w = 0;
        }
 
        /* copy to device */
@@ -434,6 +439,8 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
        for(size_t i = 0; i < scene->meshes.size(); i++) {
                Mesh *mesh = scene->meshes[i];
 
+               scene->need_global_attributes(mesh_attributes[i]);
+
                foreach(uint sindex, mesh->used_shaders) {
                        Shader *shader = scene->shaders[sindex];
                        mesh_attributes[i].add(shader->attributes);
@@ -456,8 +463,8 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
                        Attribute *mattr = mesh->attributes.find(req);
 
                        /* todo: get rid of this exception */
-                       if(!mattr && req.std == Attribute::STD_GENERATED) {
-                               mattr = mesh->attributes.add(Attribute::STD_GENERATED);
+                       if(!mattr && req.std == ATTR_STD_GENERATED) {
+                               mattr = mesh->attributes.add(ATTR_STD_GENERATED);
                                if(mesh->verts.size())
                                        memcpy(mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
                        }
@@ -489,19 +496,19 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
                                float *data = mattr->data_float();
                                req.offset = attr_float.size();
 
+                               attr_float.resize(attr_float.size() + size);
+
                                for(size_t k = 0; k < size; k++)
-                                       attr_float.push_back(data[k]);
+                                       attr_float[req.offset+k] = data[k];
                        }
                        else {
                                float3 *data = mattr->data_float3();
                                req.offset = attr_float3.size();
 
-                               for(size_t k = 0; k < size; k++) {
-                                       float3 f3 = data[k];
-                                       float4 f4 = make_float4(f3.x, f3.y, f3.z, 0.0f);
+                               attr_float3.resize(attr_float3.size() + size);
 
-                                       attr_float3.push_back(f4);
-                               }
+                               for(size_t k = 0; k < size; k++)
+                                       attr_float3[req.offset+k] = float3_to_float4(data[k]);
                        }
 
                        /* mesh vertex/triangle index is global, not per object, so we sneak
@@ -712,8 +719,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
        foreach(Shader *shader, scene->shaders)
                shader->need_update_attributes = false;
 
+       bool motion_blur = scene->need_motion() == Scene::MOTION_BLUR;
+
        foreach(Object *object, scene->objects)
-               object->compute_bounds();
+               object->compute_bounds(motion_blur);
 
        if(progress.get_cancel()) return;
 
@@ -759,5 +768,32 @@ void MeshManager::tag_update(Scene *scene)
        scene->object_manager->need_update = true;
 }
 
+bool Mesh::need_attribute(Scene *scene, AttributeStandard std)
+{
+       if(std == ATTR_STD_NONE)
+               return false;
+       
+       if(scene->need_global_attribute(std))
+               return true;
+
+       foreach(uint shader, used_shaders)
+               if(scene->shaders[shader]->attributes.find(std))
+                       return true;
+       
+       return false;
+}
+
+bool Mesh::need_attribute(Scene *scene, ustring name)
+{
+       if(name == ustring())
+               return false;
+
+       foreach(uint shader, used_shaders)
+               if(scene->shaders[shader]->attributes.find(name))
+                       return true;
+       
+       return false;
+}
+
 CCL_NAMESPACE_END
 
index 585203484c79342cbfc72f756188bd2cffa283a2..047a2d2624d420a22f9bc3b1696b98dc785230e4 100644 (file)
@@ -98,6 +98,9 @@ public:
        void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
        void compute_bvh(SceneParams *params, Progress& progress);
 
+       bool need_attribute(Scene *scene, AttributeStandard std);
+       bool need_attribute(Scene *scene, ustring name);
+
        void tag_update(Scene *scene, bool rebuild);
 };
 
index a6f8e3f6be88b3ff309c64028d68b0e2ab9fadc6..dea694a811e9e82f8264e029515f1251a830c37c 100644 (file)
@@ -140,11 +140,11 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
         * normals, as bump mapping in the shader will already alter the
         * vertex normal, so we start from the non-displaced vertex normals
         * to avoid applying the perturbation twice. */
-       mesh->attributes.remove(Attribute::STD_FACE_NORMAL);
+       mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
        mesh->add_face_normals();
 
        if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
-               mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
+               mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
                mesh->add_vertex_normals();
        }
 
index d71438ebae1bd8053878b64d113598437ae43200..7039f5b64122e57e95fd1a34827778b38b5c016a 100644 (file)
@@ -1514,9 +1514,9 @@ TextureCoordinateNode::TextureCoordinateNode()
 void TextureCoordinateNode::attributes(AttributeRequestSet *attributes)
 {
        if(!output("Generated")->links.empty())
-               attributes->add(Attribute::STD_GENERATED);
+               attributes->add(ATTR_STD_GENERATED);
        if(!output("UV")->links.empty())
-               attributes->add(Attribute::STD_UV);
+               attributes->add(ATTR_STD_UV);
 
        ShaderNode::attributes(attributes);
 }
@@ -1546,7 +1546,7 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
                        compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset);
                }
                else {
-                       int attr = compiler.attribute(Attribute::STD_GENERATED);
+                       int attr = compiler.attribute(ATTR_STD_GENERATED);
                        compiler.stack_assign(out);
                        compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3);
                }
@@ -1560,7 +1560,7 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
 
        out = output("UV");
        if(!out->links.empty()) {
-               int attr = compiler.attribute(Attribute::STD_UV);
+               int attr = compiler.attribute(ATTR_STD_UV);
                compiler.stack_assign(out);
                compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3);
        }
index 28645d856a83a0eeaaa079950fae2334d8fd140a..ccc654965f1e040ec85eb35888c69f9f4d804286 100644 (file)
@@ -38,15 +38,37 @@ Object::Object()
        visibility = ~0;
        pass_id = 0;
        bounds = BoundBox::empty;
+       motion.pre = transform_identity();
+       motion.post = transform_identity();
+       use_motion = false;
 }
 
 Object::~Object()
 {
 }
 
-void Object::compute_bounds()
+void Object::compute_bounds(bool motion_blur)
 {
-       bounds = mesh->bounds.transformed(&tfm);
+       BoundBox mbounds = mesh->bounds;
+
+       if(motion_blur && use_motion) {
+               MotionTransform decomp;
+               transform_motion_decompose(&decomp, &motion);
+
+               bounds = BoundBox::empty;
+
+               /* 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 */
+               for(float t = 0.0f; t < 1.0f; t += 1.0f/128.0f) {
+                       Transform ttfm;
+
+                       transform_motion_interpolate(&ttfm, &decomp, t);
+                       bounds.grow(mbounds.transformed(&ttfm));
+               }
+       }
+       else
+               bounds = mbounds.transformed(&tfm);
 }
 
 void Object::apply_transform()
@@ -57,8 +79,8 @@ 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_fN = mesh->attributes.find(Attribute::STD_FACE_NORMAL);
-       Attribute *attr_vN = mesh->attributes.find(Attribute::STD_VERTEX_NORMAL);
+       Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
+       Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
 
        Transform ntfm = transform_transpose(transform_inverse(tfm));
 
@@ -83,7 +105,7 @@ void Object::apply_transform()
 
        if(bounds.valid()) {
                mesh->compute_bounds();
-               compute_bounds();
+               compute_bounds(false);
        }
        
        tfm = transform_identity();
@@ -123,6 +145,7 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
        float4 *objects = dscene->objects.resize(OBJECT_SIZE*scene->objects.size());
        int i = 0;
        map<Mesh*, float> surface_area_map;
+       Scene::MotionType need_motion = scene->need_motion();
 
        foreach(Object *ob, scene->objects) {
                Mesh *mesh = ob->mesh;
@@ -130,7 +153,6 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
                /* compute transformations */
                Transform tfm = ob->tfm;
                Transform itfm = transform_inverse(tfm);
-               Transform ntfm = transform_transpose(itfm);
 
                /* compute surface area. for uniform scale we can do avoid the many
                   transform calls and share computation for instances */
@@ -171,10 +193,38 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
                /* pack in texture */
                int offset = i*OBJECT_SIZE;
 
-               memcpy(&objects[offset], &tfm, sizeof(float4)*4);
-               memcpy(&objects[offset+4], &itfm, sizeof(float4)*4);
-               memcpy(&objects[offset+8], &ntfm, sizeof(float4)*4);
-               objects[offset+12] = make_float4(surface_area, pass_id, 0.0f, 0.0f);
+               memcpy(&objects[offset], &tfm, sizeof(float4)*3);
+               memcpy(&objects[offset+3], &itfm, sizeof(float4)*3);
+               objects[offset+6] = make_float4(surface_area, pass_id, 0.0f, 0.0f);
+
+               if(need_motion == Scene::MOTION_PASS) {
+                       /* motion transformations, is world/object space depending if mesh
+                          comes with deformed position in object space, or if we transform
+                          the shading point in world space */
+                       Transform mtfm_pre = ob->motion.pre;
+                       Transform mtfm_post = ob->motion.post;
+
+                       if(!mesh->attributes.find(ATTR_STD_MOTION_PRE))
+                               mtfm_pre = mtfm_pre * itfm;
+                       if(!mesh->attributes.find(ATTR_STD_MOTION_POST))
+                               mtfm_post = mtfm_post * itfm;
+
+                       memcpy(&objects[offset+8], &mtfm_pre, sizeof(float4)*4);
+                       memcpy(&objects[offset+12], &mtfm_post, sizeof(float4)*4);
+               }
+               else if(need_motion == Scene::MOTION_BLUR) {
+                       if(ob->use_motion) {
+                               /* decompose transformations for interpolation */
+                               MotionTransform decomp;
+
+                               transform_motion_decompose(&decomp, &ob->motion);
+                               memcpy(&objects[offset+8], &decomp, sizeof(float4)*8);
+                       }
+                       else {
+                               float4 no_motion = make_float4(FLT_MAX);
+                               memcpy(&objects[offset+8], &no_motion, sizeof(float4));
+                       }
+               }
 
                i++;
 
@@ -225,6 +275,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress)
 
        /* counter mesh users */
        map<Mesh*, int> mesh_users;
+       bool motion_blur = scene->need_motion() == Scene::MOTION_BLUR;
 
        foreach(Object *object, scene->objects) {
                map<Mesh*, int>::iterator it = mesh_users.find(object->mesh);
@@ -240,12 +291,14 @@ void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress)
        /* apply transforms for objects with single user meshes */
        foreach(Object *object, scene->objects) {
                if(mesh_users[object->mesh] == 1) {
-                       if(!object->mesh->transform_applied) {
-                               object->apply_transform();
-                               object->mesh->transform_applied = true;
-                       }
+                       if(!(motion_blur && object->use_motion)) {
+                               if(!object->mesh->transform_applied) {
+                                       object->apply_transform();
+                                       object->mesh->transform_applied = true;
 
-                       if(progress.get_cancel()) return;
+                                       if(progress.get_cancel()) return;
+                               }
+                       }
                }
        }
 }
index 14da2cfb35d4f4fa420be4cd0e3114f72a75acd3..e84c4b267672d2d564d07c70a1f9f4e766728f29 100644 (file)
@@ -44,13 +44,15 @@ public:
        int pass_id;
        vector<ParamValue> attributes;
        uint visibility;
+       MotionTransform motion;
+       bool use_motion;
 
        Object();
        ~Object();
 
        void tag_update(Scene *scene);
 
-       void compute_bounds();
+       void compute_bounds(bool motion_blur);
        void apply_transform();
 };
 
index 079f2744e730d621218e6acba0eefb08c2ac9e5f..b6453339d41f1287a700144653b27faf8be465da 100644 (file)
@@ -128,7 +128,7 @@ void Scene::device_update(Device *device_, Progress& progress)
        if(progress.get_cancel()) return;
 
        progress.set_status("Updating Camera");
-       camera->device_update(device, &dscene);
+       camera->device_update(device, &dscene, this);
 
        if(progress.get_cancel()) return;
 
@@ -166,6 +166,33 @@ void Scene::device_update(Device *device_, Progress& progress)
        device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
 }
 
+Scene::MotionType Scene::need_motion()
+{
+       if(integrator->motion_blur)
+               return MOTION_BLUR;
+       else if(Pass::contains(film->passes, PASS_MOTION))
+               return MOTION_PASS;
+       else
+               return MOTION_NONE;
+}
+
+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 || ATTR_STD_MOTION_POST)
+               return need_motion() == MOTION_PASS;
+       
+       return false;
+}
+
+void Scene::need_global_attributes(AttributeRequestSet& attributes)
+{
+       for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++)
+               if(need_global_attribute((AttributeStandard)std))
+                       attributes.add((AttributeStandard)std);
+}
+
 bool Scene::need_update()
 {
        return (need_reset() || film->need_update);
index af4301b1cd95d1fe7e9d2838373bcd4beea877f3..7d4acf369fdc5441ef2976835b228c4a40977951 100644 (file)
@@ -33,6 +33,7 @@
 
 CCL_NAMESPACE_BEGIN
 
+class AttributeRequestSet;
 class Background;
 class Camera;
 class Device;
@@ -175,6 +176,12 @@ public:
 
        void device_update(Device *device, Progress& progress);
 
+       bool need_global_attribute(AttributeStandard std);
+       void need_global_attributes(AttributeRequestSet& attributes);
+
+       enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
+       MotionType need_motion();
+
        bool need_update();
        bool need_reset();
 };
index c1f7b3518d21225129f118bfbde4945c2ed54799..f50709146efd68d36cde87970106c1a630d13a2e 100644 (file)
@@ -133,12 +133,12 @@ uint ShaderManager::get_attribute_id(ustring name)
        if(it != unique_attribute_id.end())
                return it->second;
        
-       uint id = (uint)Attribute::STD_NUM + unique_attribute_id.size();
+       uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size();
        unique_attribute_id[name] = id;
        return id;
 }
 
-uint ShaderManager::get_attribute_id(Attribute::Standard std)
+uint ShaderManager::get_attribute_id(AttributeStandard std)
 {
        return (uint)std;
 }
index 35f3cfe27f5e0d973ef0e965ea67d20060d97ded..48d517ce21aa9b8d46734f2b2efc2e5d4051bee1 100644 (file)
@@ -103,7 +103,7 @@ public:
 
        /* get globally unique id for a type of attribute */
        uint get_attribute_id(ustring name);
-       uint get_attribute_id(Attribute::Standard std);
+       uint get_attribute_id(AttributeStandard std);
 
        /* get shader id for mesh faces */
        int get_shader_id(uint shader, Mesh *mesh = NULL, bool smooth = false);
index a52e30c6030f364536197b01cc72ae469fa99a06..1ff3ac20d5051a55d6b3bfbf31504f6353ee5333 100644 (file)
@@ -337,7 +337,7 @@ uint SVMCompiler::attribute(ustring name)
        return shader_manager->get_attribute_id(name);
 }
 
-uint SVMCompiler::attribute(Attribute::Standard std)
+uint SVMCompiler::attribute(AttributeStandard std)
 {
        return shader_manager->get_attribute_id(std);
 }
index 56c930f6217a111446d57c46837be38097cbab82..0db68f400fc62ceb87a3ec4cc34f5851b69bd6c2 100644 (file)
@@ -69,7 +69,7 @@ public:
        void add_node(const float4& f);
        void add_array(float4 *f, int num);
        uint attribute(ustring name);
-       uint attribute(Attribute::Standard std);
+       uint attribute(AttributeStandard std);
        uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
        uint closure_mix_weight_offset() { return mix_weight_offset; }
 
index 6b29d1ca51a21481ed111bbba93883ecac72287a..6e24bb410b578f1913c1635022ce8f665e0f8ac9 100644 (file)
@@ -39,7 +39,7 @@ EdgeDice::EdgeDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_)
        smooth = smooth_;
        camera = NULL;
 
-       mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
+       mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
 }
 
 void EdgeDice::reserve(int num_verts, int num_tris)
@@ -49,7 +49,7 @@ void EdgeDice::reserve(int num_verts, int num_tris)
 
        mesh->reserve(vert_offset + num_verts, tri_offset + num_tris);
 
-       Attribute *attr_vN = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
+       Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
 
        mesh_P = &mesh->verts[0];
        mesh_N = attr_vN->data_float3();
index 53c1302b4a1168df554279c9f23eb64f41b81349..f09803d8b0908058dd78660099bee32b0d4464a7 100644 (file)
@@ -55,6 +55,10 @@ CCL_NAMESPACE_BEGIN
 #ifndef M_2_PI_F
 #define M_2_PI_F       ((float)0.636619772367581343075535053490057448)
 #endif
+#ifndef M_SQRT2_F
+#define M_SQRT2_F      ((float)1.41421356237309504880)
+#endif
+
 
 /* Scalar */
 
@@ -719,6 +723,45 @@ __device_inline float4 cross(const float4& a, const float4& b)
 #endif
 }
 
+__device_inline bool is_zero(const float4& a)
+{
+#ifdef __KERNEL_SSE__
+       return a == make_float4(0.0f);
+#else
+       return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f);
+#endif
+}
+
+__device_inline float reduce_add(const float4& a)
+{
+#ifdef __KERNEL_SSE__
+       float4 h = shuffle<1,0,3,2>(a) + a;
+       return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); /* todo: efficiency? */
+#else
+       return ((a.x + a.y) + (a.z + a.w));
+#endif
+}
+
+__device_inline float average(const float4& a)
+{
+       return reduce_add(a) * 0.25f;
+}
+
+__device_inline float dot(const float4& a, const float4& b)
+{
+       return reduce_add(a * b);
+}
+
+__device_inline float len(const float4 a)
+{
+       return sqrtf(dot(a, a));
+}
+
+__device_inline float4 normalize(const float4 a)
+{
+       return a/len(a);
+}
+
 __device_inline float4 min(float4 a, float4 b)
 {
 #ifdef __KERNEL_SSE__
@@ -790,39 +833,6 @@ __device_inline void print_float4(const char *label, const float4& a)
 
 #endif
 
-#ifndef __KERNEL_OPENCL__
-
-__device_inline bool is_zero(const float4& a)
-{
-#ifdef __KERNEL_SSE__
-       return a == make_float4(0.0f);
-#else
-       return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f);
-#endif
-}
-
-__device_inline float reduce_add(const float4& a)
-{
-#ifdef __KERNEL_SSE__
-       float4 h = shuffle<1,0,3,2>(a) + a;
-       return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); /* todo: efficiency? */
-#else
-       return ((a.x + a.y) + (a.z + a.w));
-#endif
-}
-
-__device_inline float average(const float4& a)
-{
-       return reduce_add(a) * 0.25f;
-}
-
-__device_inline float dot(const float4& a, const float4& b)
-{
-       return reduce_add(a * b);
-}
-
-#endif
-
 /* Int3 */
 
 #ifndef __KERNEL_OPENCL__
index 0fd26825911873b7380be0623c3fa1057a4bd777..1780994da27f48e679b8de7a6a18dd8ce47c5757 100644 (file)
@@ -53,6 +53,8 @@
 
 CCL_NAMESPACE_BEGIN
 
+/* Transform Inverse */
+
 static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
 {
        /* forward elimination */
@@ -151,5 +153,104 @@ Transform transform_inverse(const Transform& tfm)
        return tfmR;
 }
 
+/* Motion Transform */
+
+static float4 transform_to_quat(const Transform& tfm)
+{
+       double trace = tfm[0][0] + tfm[1][1] + tfm[2][2];
+       float4 qt;
+
+       if(trace > 0.0f) {
+               double s = sqrt(trace + 1.0);
+
+               qt.w = (float)(s/2.0);
+               s = 0.5/s;
+
+               qt.x = (float)((tfm[2][1] - tfm[1][2]) * s);
+               qt.y = (float)((tfm[0][2] - tfm[2][0]) * s);
+               qt.z = (float)((tfm[1][0] - tfm[0][1]) * s);
+       }
+       else {
+               int i = 0;
+
+               if(tfm[1][1] > tfm[i][i])
+                       i = 1;
+               if(tfm[2][2] > tfm[i][i])
+                       i = 2;
+
+               int j = (i + 1)%3;
+               int k = (j + 1)%3;
+
+               double s = sqrt((tfm[i][i] - (tfm[j][j] + tfm[k][k])) + 1.0);
+
+               double q[3];
+               q[i] = s * 0.5;
+               if(s != 0.0)
+                       s = 0.5/s;
+
+               double w = (tfm[k][j] - tfm[j][k]) * s;
+               q[j] = (tfm[j][i] + tfm[i][j]) * s;
+               q[k] = (tfm[k][i] + tfm[i][k]) * s;
+
+               qt.x = (float)q[0];
+               qt.y = (float)q[1];
+               qt.z = (float)q[2];
+               qt.w = (float)w;
+       }
+
+       return qt;
+}
+
+static void transform_decompose(Transform *decomp, const Transform *tfm)
+{
+       /* extract translation */
+       decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f);
+
+       /* extract rotation */
+       Transform M = *tfm;
+       M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f; M.w.w = 1.0f;
+
+       Transform R = M;
+       float norm;
+       int iteration = 0;
+
+       do {
+               Transform Rnext;
+               Transform Rit = transform_inverse(transform_transpose(R));
+
+               for(int i = 0; i < 4; i++)
+                       for(int j = 0; j < 4; j++)
+                               Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
+               
+               norm = 0.0f;
+               for(int i = 0; i < 3; i++) {
+                       norm = max(norm,
+                               fabsf(R[i][0] - Rnext[i][0]) +
+                               fabsf(R[i][1] - Rnext[i][1]) +
+                               fabsf(R[i][2] - Rnext[i][2]));
+               }
+
+               R = Rnext;
+               iteration++;
+       } while(iteration < 100 && norm > 1e-4f);
+
+       if(transform_negative_scale(R))
+               R = R * transform_scale(-1.0f, -1.0f, -1.0f); /* todo: test scale */
+
+       decomp->x = transform_to_quat(R);
+
+       /* extract scale and pack it */
+       Transform scale = transform_inverse(R) * M;
+       decomp->y.w = scale.x.x;
+       decomp->z = make_float4(scale.x.y, scale.x.z, scale.y.x, scale.y.y);
+       decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z);
+}
+
+void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion)
+{
+       transform_decompose(&decomp->pre, &motion->pre);
+       transform_decompose(&decomp->post, &motion->post);
+}
+
 CCL_NAMESPACE_END
 
index aeaef7b0e216c72e8356b202423a2fc804a3ce70..03dfbaa441d20be31ee92819862d850869acd460 100644 (file)
@@ -28,6 +28,8 @@
 
 CCL_NAMESPACE_BEGIN
 
+/* Data Types */
+
 typedef struct Transform {
        float4 x, y, z, w; /* rows */
 
@@ -37,6 +39,17 @@ typedef struct Transform {
 #endif
 } Transform;
 
+typedef struct MotionTransform {
+       Transform pre;
+       Transform post;
+} MotionTransform;
+
+/* transform decomposed in rotation/translation/scale. we use the same data
+ * structure as Transform, and tightly pack decomposition into it. first the
+ * rotation (4), then translation (3), then 3x3 scale matrix (9) */
+
+/* Functions */
+
 __device_inline float3 transform_perspective(const Transform *t, const float3 a)
 {
        float4 b = make_float4(a.x, a.y, a.z, 1.0f);
@@ -62,6 +75,15 @@ __device_inline float3 transform_direction(const Transform *t, const float3 a)
        return c;
 }
 
+__device_inline float3 transform_direction_transposed(const Transform *t, const float3 a)
+{
+       float3 x = make_float3(t->x.x, t->y.x, t->z.x);
+       float3 y = make_float3(t->x.y, t->y.y, t->z.y);
+       float3 z = make_float3(t->x.z, t->y.z, t->z.z);
+
+       return make_float3(dot(x, a), dot(y, a), dot(z, a));
+}
+
 #ifndef __KERNEL_GPU__
 
 __device_inline void print_transform(const char *label, const Transform& t)
@@ -272,6 +294,102 @@ __device_inline Transform transform_clear_scale(const Transform& tfm)
 
 #endif
 
+/* Motion Transform */
+
+__device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
+{
+       float costheta = dot(q1, q2);
+
+       if(costheta > 0.9995f) {
+               return normalize((1.0f - t)*q1 + t*q2);
+       }
+       else  {
+               float theta = acosf(clamp(costheta, -1.0f, 1.0f));
+               float thetap = theta * t;
+               float4 qperp = normalize(q2 - q1 * costheta);
+               return q1 * cosf(thetap) + qperp * sinf(thetap);
+       }
+}
+
+__device_inline Transform transform_quick_inverse(Transform M)
+{
+       Transform R;
+       float det = M.x.x*(M.z.z*M.y.y - M.z.y*M.y.z) - M.y.x*(M.z.z*M.x.y - M.z.y*M.x.z) + M.z.x*(M.y.z*M.x.y - M.y.y*M.x.z);
+
+       det = (det != 0.0f)? 1.0f/det: 0.0f;
+
+       float3 Rx = det*make_float3(M.z.z*M.y.y - M.z.y*M.y.z, M.z.y*M.x.z - M.z.z*M.x.y, M.y.z*M.x.y - M.y.y*M.x.z);
+       float3 Ry = det*make_float3(M.z.x*M.y.z - M.z.z*M.y.x, M.z.z*M.x.x - M.z.x*M.x.z, M.y.x*M.x.z - M.y.z*M.x.x);
+       float3 Rz = det*make_float3(M.z.y*M.y.x - M.z.x*M.y.y, M.z.x*M.x.y - M.z.y*M.x.x, M.y.y*M.x.x - M.y.x*M.x.y);
+       float3 T = -make_float3(M.x.w, M.y.w, M.z.w);
+
+       R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T));
+       R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T));
+       R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T));
+       R.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+
+       return R;
+}
+
+__device_inline void transform_compose(Transform *tfm, const Transform *decomp)
+{
+       /* rotation */
+       float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
+
+       q0 = M_SQRT2_F * decomp->x.w;
+       q1 = M_SQRT2_F * decomp->x.x;
+       q2 = M_SQRT2_F * decomp->x.y;
+       q3 = M_SQRT2_F * decomp->x.z;
+
+       qda = q0*q1;
+       qdb = q0*q2;
+       qdc = q0*q3;
+       qaa = q1*q1;
+       qab = q1*q2;
+       qac = q1*q3;
+       qbb = q2*q2;
+       qbc = q2*q3;
+       qcc = q3*q3;
+
+       float3 rotation_x = make_float3(1.0f-qbb-qcc, -qdc+qab, qdb+qac);
+       float3 rotation_y = make_float3(qdc+qab, 1.0f-qaa-qcc, -qda+qbc);
+       float3 rotation_z = make_float3(-qdb+qac, qda+qbc, 1.0f-qaa-qbb);
+
+       /* scale */
+       float3 scale_x = make_float3(decomp->y.w, decomp->z.z, decomp->w.y);
+       float3 scale_y = make_float3(decomp->z.x, decomp->z.w, decomp->w.z);
+       float3 scale_z = make_float3(decomp->z.y, decomp->w.x, decomp->w.w);
+
+       /* compose with translation */
+       tfm->x = make_float4(dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
+       tfm->y = make_float4(dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
+       tfm->z = make_float4(dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
+       tfm->w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
+}
+
+__device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t)
+{
+       Transform decomp;
+
+       decomp.x = quat_interpolate(motion->pre.x, motion->post.x, t);
+       decomp.y = (1.0f - t)*motion->pre.y + t*motion->post.y;
+       decomp.z = (1.0f - t)*motion->pre.z + t*motion->post.z;
+       decomp.w = (1.0f - t)*motion->pre.w + t*motion->post.w;
+
+       transform_compose(tfm, &decomp);
+}
+
+#ifndef __KERNEL_GPU__
+
+__device_inline bool operator==(const MotionTransform& A, const MotionTransform& B)
+{
+       return (A.pre == B.pre && A.post == B.post);
+}
+
+void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion);
+
+#endif
+
 CCL_NAMESPACE_END
 
 #endif /* __UTIL_TRANSFORM_H__ */
index 971320765e9162c42ea83fd549f3b61b644771f6..4fced71d7f2bf0c5d3019a679ab7ea103f4a0673 100644 (file)
@@ -152,6 +152,7 @@ int object_insert_ptcache(struct Object *ob);
 struct KeyBlock *object_insert_shape_key(struct Scene *scene, struct Object *ob, const char *name, int from_mix);
 
 int object_is_modified(struct Scene *scene, struct Object *ob);
+int object_is_deform_modified(struct Scene *scene, struct Object *ob);
 
 void object_relink(struct Object *ob);
 
index 9959edaac16b690a59d6ffa682b157620e552179..830184513d12ae7d8f5d080ac6a515e21bd426ea 100644 (file)
@@ -2982,8 +2982,7 @@ KeyBlock *object_insert_shape_key(Scene *scene, Object *ob, const char *name, in
 }
 
 /* most important if this is modified it should _always_ return True, in certain
- * cases false positives are hard to avoid (shape keys for eg)
- */
+ * cases false positives are hard to avoid (shape keys for example) */
 int object_is_modified(Scene *scene, Object *ob)
 {
        int flag= 0;
@@ -2998,13 +2997,38 @@ int object_is_modified(Scene *scene, Object *ob)
                     md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
                     md=md->next)
                {
-                       if ((flag & eModifierMode_Render) == 0  && modifier_isEnabled(scene, md, eModifierMode_Render)) {
+                       if ((flag & eModifierMode_Render) == 0 && modifier_isEnabled(scene, md, eModifierMode_Render))
                                flag |= eModifierMode_Render;
-                       }
 
-                       if ((flag & eModifierMode_Realtime) == 0        && modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+                       if ((flag & eModifierMode_Realtime) == 0 && modifier_isEnabled(scene, md, eModifierMode_Realtime))
+                               flag |= eModifierMode_Realtime;
+               }
+       }
+
+       return flag;
+}
+
+/* test if object is affected by deforming modifiers (for motion blur). again
+ * most important is to avoid false positives, this is to skip computations
+ * and we can still if there was actual deformation afterwards */
+int object_is_deform_modified(Scene *scene, Object *ob)
+{
+       ModifierData *md;
+       int flag= 0;
+
+       /* cloth */
+       for (md=modifiers_getVirtualModifierList(ob);
+                md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
+                md=md->next)
+       {
+               ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+               if (mti->type == eModifierTypeType_OnlyDeform) {
+                       if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render))
+                               flag |= eModifierMode_Render;
+
+                       if (!(flag & eModifierMode_Realtime) && modifier_isEnabled(scene, md, eModifierMode_Realtime))
                                flag |= eModifierMode_Realtime;
-                       }
                }
        }
 
index d09dedb4f4cdcbc3330ebb2c1e63de093ab96dfb..cb0f1d307aa8733b32466a92f1b0bc452547db1c 100644 (file)
@@ -476,6 +476,11 @@ int rna_Object_is_modified(Object *ob, Scene *scene, int settings)
        return object_is_modified(scene, ob) & settings;
 }
 
+int rna_Object_is_deform_modified(Object *ob, Scene *scene, int settings)
+{
+       return object_is_deform_modified(scene, ob) & settings;
+}
+
 #ifndef NDEBUG
 void rna_Object_dm_info(struct Object *ob, int type, char *result)
 {
@@ -644,6 +649,14 @@ void RNA_api_object(StructRNA *srna)
        parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
        RNA_def_function_return(func, parm);
 
+       func = RNA_def_function(srna, "is_deform_modified", "rna_Object_is_deform_modified");
+       RNA_def_function_ui_description(func, "Determine if this object is modified by a deformation from the base mesh data");
+       parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL);
+       parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
+       RNA_def_function_return(func, parm);
 
 #ifndef NDEBUG
        /* mesh */
index 08ed7625a014bb0a9e533df4d087b3d561285cda..c92a29cec3c51159c9cbb223b26e74bc82dd3f74 100644 (file)
@@ -50,7 +50,7 @@
 
 
 
-static void rna_Scene_frame_set(Scene *scene, int frame, float subframe)
+void rna_Scene_frame_set(Scene *scene, int frame, float subframe)
 {
        scene->r.cfra = frame;
        scene->r.subframe = subframe;