Merge branch 'master' into blender2.8
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 10 Mar 2018 05:55:39 +0000 (06:55 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 10 Mar 2018 05:55:39 +0000 (06:55 +0100)
71 files changed:
intern/cycles/app/cycles_xml.cpp
intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_camera.cpp
intern/cycles/blender/blender_curves.cpp
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_object_cull.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/blender/blender_util.h
intern/cycles/graph/node_type.cpp
intern/cycles/graph/node_xml.cpp
intern/cycles/kernel/CMakeLists.txt
intern/cycles/kernel/bvh/bvh_nodes.h
intern/cycles/kernel/bvh/bvh_shadow_all.h
intern/cycles/kernel/bvh/qbvh_shadow_all.h
intern/cycles/kernel/geom/geom_attribute.h
intern/cycles/kernel/geom/geom_curve_intersect.h
intern/cycles/kernel/geom/geom_object.h
intern/cycles/kernel/geom/geom_primitive.h
intern/cycles/kernel/geom/geom_volume.h
intern/cycles/kernel/kernel_camera.h
intern/cycles/kernel/kernel_compat_cpu.h
intern/cycles/kernel/kernel_compat_cuda.h
intern/cycles/kernel/kernel_compat_opencl.h
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_light.h
intern/cycles/kernel/kernel_math.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_textures.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/kernel_volume.h
intern/cycles/kernel/osl/osl_services.cpp
intern/cycles/kernel/svm/svm_mapping.h
intern/cycles/kernel/svm/svm_tex_coord.h
intern/cycles/kernel/svm/svm_voxel.h
intern/cycles/render/camera.cpp
intern/cycles/render/camera.h
intern/cycles/render/light.cpp
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h
intern/cycles/render/mesh_volume.cpp
intern/cycles/render/nodes.cpp
intern/cycles/render/object.cpp
intern/cycles/render/object.h
intern/cycles/render/osl.cpp
intern/cycles/render/particles.cpp
intern/cycles/render/scene.cpp
intern/cycles/render/scene.h
intern/cycles/render/session.cpp
intern/cycles/render/shader.cpp
intern/cycles/util/CMakeLists.txt
intern/cycles/util/util_projection.h [new file with mode: 0644]
intern/cycles/util/util_transform.cpp
intern/cycles/util/util_transform.h
intern/cycles/util/util_vector.h
intern/ffmpeg/ffmpeg_compat.h
release/datafiles/locale
release/scripts/addons
release/scripts/addons_contrib
release/scripts/startup/bl_ui/space_userpref.py
source/blender/editors/armature/pose_lib.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/imbuf/intern/anim_movie.c
source/blender/imbuf/intern/indexer.c
source/blender/imbuf/intern/openexr/openexr_api.cpp
source/gameengine/VideoTexture/VideoFFmpeg.cpp
source/tools
tests/python/CMakeLists.txt
tests/python/ffmpeg_tests.py [new file with mode: 0755]
tests/python/modules/test_utils.py

index 21ae07e23b846a4ca23be18a969ff178c969c6e1..a46955322e383f79854d8d9b5ecb5bbcb93be90b 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "util/util_foreach.h"
 #include "util/util_path.h"
+#include "util/util_projection.h"
 #include "util/util_transform.h"
 #include "util/util_xml.h"
 
@@ -546,8 +547,10 @@ static void xml_read_transform(xml_node node, Transform& tfm)
 {
        if(node.attribute("matrix")) {
                vector<float> matrix;
-               if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
-                       tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
+               if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16) {
+                       ProjectionTransform projection = *(ProjectionTransform*)&matrix[0];
+                       tfm = tfm * projection_to_transform(projection_transpose(projection));
+               }
        }
 
        if(node.attribute("translate")) {
index fb7530f8663649380a47d5309007de238a26d1a3..6774fdaec6427619c963337d04a979aeca97328c 100644 (file)
@@ -1082,7 +1082,7 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
 
         cls.motion_steps = IntProperty(
                 name="Motion Steps",
-                description="Control accuracy of deformation motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
+                description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
                 min=1, soft_max=8,
                 default=1,
                 )
index 0166b494db77ddd3ccf9cd7365491517e2e091bd..6e4b0373a7a02b730f6b9cca42c137660aaa297c 100644 (file)
@@ -783,7 +783,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
     def poll(cls, context):
         ob = context.object
         if CyclesButtonsPanel.poll(context) and ob:
-            if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}:
+            if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
                 return True
             if ob.dupli_type == 'GROUP' and ob.dupli_group:
                 return True
@@ -815,11 +815,9 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
         layout.active = (rd.use_motion_blur and cob.use_motion_blur)
 
         row = layout.row()
-        row.prop(cob, "use_deform_motion", text="Deformation")
-
-        sub = row.row()
-        sub.active = cob.use_deform_motion
-        sub.prop(cob, "motion_steps", text="Steps")
+        if ob.type != 'CAMERA':
+            row.prop(cob, "use_deform_motion", text="Deformation")
+        row.prop(cob, "motion_steps", text="Steps")
 
 
 class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel):
index 62e950e3befc95734cca0746a6f809cf0ee04fe7..f00ade320e780b6e8a1a1fff2568d13933d08955 100644 (file)
@@ -83,6 +83,8 @@ struct BlenderCamera {
        Transform matrix;
 
        float offscreen_dicing_scale;
+
+       int motion_steps;
 };
 
 static void blender_camera_init(BlenderCamera *bcam,
@@ -226,6 +228,8 @@ static void blender_camera_from_object(BlenderCamera *bcam,
                        bcam->sensor_fit = BlenderCamera::HORIZONTAL;
                else
                        bcam->sensor_fit = BlenderCamera::VERTICAL;
+
+               bcam->motion_steps = object_motion_steps(b_ob, b_ob);
        }
        else {
                /* from lamp not implemented yet */
@@ -246,8 +250,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
                        result = tfm *
                                make_transform(1.0f, 0.0f, 0.0f, 0.0f,
                                               0.0f, 0.0f, 1.0f, 0.0f,
-                                              0.0f, 1.0f, 0.0f, 0.0f,
-                                              0.0f, 0.0f, 0.0f, 1.0f);
+                                              0.0f, 1.0f, 0.0f, 0.0f);
                }
                else {
                        /* Make it so environment camera needs to be pointed in the direction
@@ -257,8 +260,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
                        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);
+                                              -1.0f,  0.0f, 0.0f, 0.0f);
                }
        }
        else {
@@ -455,9 +457,7 @@ static void blender_camera_sync(Camera *cam,
        cam->matrix = blender_camera_matrix(bcam->matrix,
                                            bcam->type,
                                            bcam->panorama_type);
-       cam->motion.pre = cam->matrix;
-       cam->motion.post = cam->matrix;
-       cam->use_motion = false;
+       cam->motion.resize(bcam->motion_steps, cam->matrix);
        cam->use_perspective_motion = false;
        cam->shuttertime = bcam->shuttertime;
        cam->fov_pre = cam->fov;
@@ -566,20 +566,15 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
        Transform tfm = get_transform(b_ob_matrix);
        tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
 
-       if(tfm != cam->matrix) {
-               VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
-               if(motion_time == 0.0f) {
-                       /* When motion blur is not centered in frame, cam->matrix gets reset. */
-                       cam->matrix = tfm;
-               }
-               else if(motion_time == -1.0f) {
-                       cam->motion.pre = tfm;
-                       cam->use_motion = true;
-               }
-               else if(motion_time == 1.0f) {
-                       cam->motion.post = tfm;
-                       cam->use_motion = true;
-               }
+       if(motion_time == 0.0f) {
+               /* When motion blur is not centered in frame, cam->matrix gets reset. */
+               cam->matrix = tfm;
+       }
+
+       /* Set transform in motion array. */
+       int motion_step = cam->motion_step(motion_time);
+       if(motion_step >= 0) {
+               cam->motion[motion_step] = tfm;
        }
 
        if(cam->type == CAMERA_PERSPECTIVE) {
index 6017ea502ed3afbeeb200e1ca93e7215cb11c64b..984442fb08c6e2e2c0ff06bd2726d7608a134227 100644 (file)
@@ -633,10 +633,10 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
        }
 }
 
-static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
+static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step)
 {
        VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
-               << ", time index " << time_index;
+               << ", motion step " << motion_step;
 
        /* find attribute */
        Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@@ -651,7 +651,7 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
 
        /* export motion vectors for curve keys */
        size_t numkeys = mesh->curve_keys.size();
-       float4 *mP = attr_mP->data_float4() + time_index*numkeys;
+       float4 *mP = attr_mP->data_float4() + motion_step*numkeys;
        bool have_motion = false;
        int i = 0;
 
@@ -702,12 +702,12 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
                        }
                        mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
                }
-               else if(time_index > 0) {
-                       VLOG(1) << "Filling in new motion vertex position for time_index "
-                               << time_index;
+               else if(motion_step > 0) {
+                       VLOG(1) << "Filling in new motion vertex position for motion_step "
+                               << motion_step;
                        /* motion, fill up previous steps that we might have skipped because
                         * they had no motion, but we need them anyway now */
-                       for(int step = 0; step < time_index; step++) {
+                       for(int step = 0; step < motion_step; step++) {
                                float4 *mP = attr_mP->data_float4() + step*numkeys;
 
                                for(int key = 0; key < numkeys; key++) {
@@ -889,7 +889,7 @@ void BlenderSync::sync_curves(BL::Depsgraph& b_depsgraph,
                               BL::Mesh& b_mesh,
                               BL::Object& b_ob,
                               bool motion,
-                              int time_index)
+                              int motion_step)
 {
        if(!motion) {
                /* Clear stored curve data */
@@ -954,7 +954,7 @@ void BlenderSync::sync_curves(BL::Depsgraph& b_depsgraph,
        }
        else {
                if(motion)
-                       ExportCurveSegmentsMotion(mesh, &CData, time_index);
+                       ExportCurveSegmentsMotion(mesh, &CData, motion_step);
                else
                        ExportCurveSegments(scene, mesh, &CData);
        }
index 02ede74224aa7058de502fd4236bc3cebb322457..afcfe3d434e5b95f3998fc4f989f05c8c8594f18 100644 (file)
@@ -1252,36 +1252,10 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
        if(mesh_synced.find(mesh) == mesh_synced.end())
                return;
 
-       /* for motion pass always compute, for motion blur it can be disabled */
-       int time_index = 0;
-
-       if(scene->need_motion() == Scene::MOTION_BLUR) {
-               if(!mesh->use_motion_blur)
-                       return;
-
-               /* see if this mesh needs motion data at this time */
-               vector<float> object_times = object->motion_times();
-               bool found = false;
-
-               foreach(float object_time, object_times) {
-                       if(motion_time == object_time) {
-                               found = true;
-                               break;
-                       }
-                       else
-                               time_index++;
-               }
-
-               if(!found)
-                       return;
-       }
-       else {
-               if(motion_time == -1.0f)
-                       time_index = 0;
-               else if(motion_time == 1.0f)
-                       time_index = 1;
-               else
-                       return;
+       /* Find time matching motion step required by mesh. */
+       int motion_step = mesh->motion_step(motion_time);
+       if(motion_step < 0) {
+               return;
        }
 
        /* skip empty meshes */
@@ -1324,9 +1298,9 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
                                float3 *P = &mesh->verts[0];
                                float3 *N = (attr_N)? attr_N->data_float3(): NULL;
 
-                               memcpy(attr_mP->data_float3() + time_index*numverts, P, sizeof(float3)*numverts);
+                               memcpy(attr_mP->data_float3() + motion_step*numverts, P, sizeof(float3)*numverts);
                                if(attr_mN)
-                                       memcpy(attr_mN->data_float3() + time_index*numverts, N, sizeof(float3)*numverts);
+                                       memcpy(attr_mN->data_float3() + motion_step*numverts, N, sizeof(float3)*numverts);
                        }
                }
 
@@ -1336,7 +1310,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
 
                        if(attr_mP) {
                                float3 *keys = &mesh->curve_keys[0];
-                               memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys);
+                               memcpy(attr_mP->data_float3() + motion_step*numkeys, keys, sizeof(float3)*numkeys);
                        }
                }
 
@@ -1359,8 +1333,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
                        new_attribute = true;
                }
                /* Load vertex data from mesh. */
-               float3 *mP = attr_mP->data_float3() + time_index*numverts;
-               float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
+               float3 *mP = attr_mP->data_float3() + motion_step*numverts;
+               float3 *mN = (attr_mN)? attr_mN->data_float3() + motion_step*numverts: NULL;
                /* NOTE: We don't copy more that existing amount of vertices to prevent
                 * possible memory corruption.
                 */
@@ -1389,13 +1363,13 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
                                if(attr_mN)
                                        mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
                        }
-                       else if(time_index > 0) {
+                       else if(motion_step > 0) {
                                VLOG(1) << "Filling deformation motion for object " << b_ob.name();
                                /* motion, fill up previous steps that we might have skipped because
                                 * they had no motion, but we need them anyway now */
                                float3 *P = &mesh->verts[0];
                                float3 *N = (attr_N)? attr_N->data_float3(): NULL;
-                               for(int step = 0; step < time_index; step++) {
+                               for(int step = 0; step < motion_step; step++) {
                                        memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
                                        if(attr_mN)
                                                memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
@@ -1405,7 +1379,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
                else {
                        if(b_mesh.vertices.length() != numverts) {
                                VLOG(1) << "Topology differs, discarding motion blur for object "
-                                       << b_ob.name() << " at time " << time_index;
+                                       << b_ob.name() << " at time " << motion_step;
                                memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts);
                                if(mN != NULL) {
                                        memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts);
@@ -1416,7 +1390,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
 
        /* hair motion */
        if(numkeys)
-               sync_curves(b_depsgraph, mesh, b_mesh, b_ob, true, time_index);
+               sync_curves(b_depsgraph, mesh, b_mesh, b_ob, true, motion_step);
 
        /* free derived mesh */
        b_data.meshes.remove(b_mesh, false, true, false);
index 03c5ecddc441c4623c562627640f909c2731da20..d949eaf30093fa9a34804287e717b2f7a616849c 100644 (file)
@@ -347,22 +347,11 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph,
        if(motion) {
                object = object_map.find(key);
 
-               if(object && (scene->need_motion() == Scene::MOTION_PASS ||
-                             object_use_motion(b_parent, b_ob)))
-               {
-                       /* object transformation */
-                       if(tfm != object->tfm) {
-                               VLOG(1) << "Object " << b_ob.name() << " motion detected.";
-                               if(motion_time == -1.0f || motion_time == 1.0f) {
-                                       object->use_motion = true;
-                               }
-                       }
-
-                       if(motion_time == -1.0f) {
-                               object->motion.pre = tfm;
-                       }
-                       else if(motion_time == 1.0f) {
-                               object->motion.post = tfm;
+               if(object && object->use_motion()) {
+                       /* Set transform at matching motion time step. */
+                       int time_index = object->motion_step(motion_time);
+                       if(time_index >= 0) {
+                               object->motion[time_index] = tfm;
                        }
 
                        /* mesh deformation */
@@ -409,25 +398,34 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph,
                object->name = b_ob.name().c_str();
                object->pass_id = b_ob.pass_index();
                object->tfm = tfm;
-               object->motion.pre = transform_empty();
-               object->motion.post = transform_empty();
-               object->use_motion = false;
+               object->motion.clear();
 
                /* motion blur */
-               if(scene->need_motion() == Scene::MOTION_BLUR && object->mesh) {
+               Scene::MotionType need_motion = scene->need_motion();
+               if(need_motion != Scene::MOTION_NONE && object->mesh) {
                        Mesh *mesh = object->mesh;
-
                        mesh->use_motion_blur = false;
+                       mesh->motion_steps = 0;
+
+                       uint motion_steps;
 
-                       if(object_use_motion(b_parent, b_ob)) {
+                       if(scene->need_motion() == Scene::MOTION_BLUR) {
+                               motion_steps = object_motion_steps(b_parent, b_ob);
                                if(object_use_deform_motion(b_parent, b_ob)) {
-                                       mesh->motion_steps = object_motion_steps(b_ob);
+                                       mesh->motion_steps = motion_steps;
                                        mesh->use_motion_blur = true;
                                }
+                       }
+                       else {
+                               motion_steps = 3;
+                               mesh->motion_steps = motion_steps;
+                       }
+
+                       object->motion.resize(motion_steps, transform_empty());
+                       object->motion[motion_steps/2] = tfm;
 
-                               vector<float> times = object->motion_times();
-                               foreach(float time, times)
-                                       motion_times.insert(time);
+                       for(size_t step = 0; step < motion_steps; step++) {
+                               motion_times.insert(object->motion_time(step));
                        }
                }
 
@@ -646,6 +644,11 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
 
        /* note iteration over motion_times set happens in sorted order */
        foreach(float relative_time, motion_times) {
+               /* center time is already handled. */
+               if(relative_time == 0.0f) {
+                       continue;
+               }
+
                VLOG(1) << "Synchronizing motion for the relative time "
                        << relative_time << ".";
 
index 1d747de647aa821cf1705def42e2e01d93c0056e..bdf7dc469b256ecf33bead5b677243778b82ff48 100644 (file)
@@ -96,7 +96,7 @@ bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm)
 bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
 {
        Camera *cam = scene->camera;
-       Transform& worldtondc = cam->worldtondc;
+       const ProjectionTransform& worldtondc = cam->worldtondc;
        float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
               bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
        bool all_behind = true;
index 9e8d494f83b542aa9c54afd617d0867e0324b8e0..2ea86ba11332eed310a2f2072d19c66475277d08 100644 (file)
@@ -125,7 +125,7 @@ private:
                         BL::Mesh& b_mesh,
                         BL::Object& b_ob,
                         bool motion,
-                        int time_index = 0);
+                        int motion_step = 0);
        Object *sync_object(BL::Depsgraph& b_depsgraph,
                            BL::Depsgraph::duplis_iterator& b_dupli_iter,
                            uint layer_flag,
index a813a09f38af77cfb087811dd4d30fbdbfa57580..5b67ff85a9b619564d8e5182e4dd131a1a1f5b09 100644 (file)
@@ -248,14 +248,15 @@ static inline float *image_get_float_pixels_for_frame(BL::Image& image,
 
 static inline Transform get_transform(const BL::Array<float, 16>& array)
 {
-       Transform tfm;
+       ProjectionTransform projection;
 
-       /* we assume both types to be just 16 floats, and transpose because blender
-        * use column major matrix order while we use row major */
-       memcpy(&tfm, &array, sizeof(float)*16);
-       tfm = transform_transpose(tfm);
+       /* We assume both types to be just 16 floats, and transpose because blender
+        * use column major matrix order while we use row major. */
+       memcpy(&projection, &array, sizeof(float)*16);
+       projection = projection_transpose(projection);
 
-       return tfm;
+       /* Drop last row, matrix is assumed to be affine transform. */
+       return projection_to_transform(projection);
 }
 
 static inline float2 get_float2(const BL::Array<float, 2>& array)
@@ -484,33 +485,34 @@ static inline void mesh_texture_space(BL::Mesh& b_mesh,
        loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
 }
 
-/* object used for motion blur */
-static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
+/* Object motion steps, returns 0 if no motion blur needed. */
+static inline uint object_motion_steps(BL::Object& b_parent, BL::Object& b_ob)
 {
+       /* Get motion enabled and steps from object itself. */
        PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
        bool use_motion = get_boolean(cobject, "use_motion_blur");
-       /* If motion blur is enabled for the object we also check
-        * whether it's enabled for the parent object as well.
-        *
-        * This way we can control motion blur from the dupligroup
-        * duplicator much easier.
-        */
-       if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
+       if(!use_motion) {
+               return 0;
+       }
+
+       uint steps = max(1, get_int(cobject, "motion_steps"));
+
+       /* Also check parent object, so motion blur and steps can be
+        * controlled by dupligroup duplicator for linked groups. */
+       if(b_parent.ptr.data != b_ob.ptr.data) {
                PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
                use_motion &= get_boolean(parent_cobject, "use_motion_blur");
-       }
-       return use_motion;
-}
 
-/* object motion steps */
-static inline uint object_motion_steps(BL::Object& b_ob)
-{
-       PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
-       uint steps = get_int(cobject, "motion_steps");
+               if(!use_motion) {
+                       return 0;
+               }
+
+               steps = max(steps, get_int(parent_cobject, "motion_steps"));
+       }
 
-       /* use uneven number of steps so we get one keyframe at the current frame,
-        * and ue 2^(steps - 1) so objects with more/fewer steps still have samples
-        * at the same times, to avoid sampling at many different times */
+       /* Use uneven number of steps so we get one keyframe at the current frame,
+        * and use 2^(steps - 1) so objects with more/fewer steps still have samples
+        * at the same times, to avoid sampling at many different times. */
        return (2 << (steps - 1)) + 1;
 }
 
index a3a8fa5f382dcbf807c5ac120e2f2c1668f94136..37aae211e93e692b2c36ec708b2c5333cc474904 100644 (file)
@@ -77,7 +77,7 @@ size_t SocketType::max_size()
 
 void *SocketType::zero_default_value()
 {
-       static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+       static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
        return &zero_transform;
 }
 
index d26b3b2c2c885dc66984bb94e5dd5ad0e7b332be..f4599e22d40f16887b20904d4d5c4adecc607d61 100644 (file)
@@ -196,7 +196,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
                        case SocketType::TRANSFORM:
                        {
                                array<Transform> value;
-                               xml_read_float_array<16>(value, attr);
+                               xml_read_float_array<12>(value, attr);
                                if(value.size() == 1) {
                                        node->set(socket, value[0]);
                                }
@@ -205,7 +205,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
                        case SocketType::TRANSFORM_ARRAY:
                        {
                                array<Transform> value;
-                               xml_read_float_array<16>(value, attr);
+                               xml_read_float_array<12>(value, attr);
                                node->set(socket, value);
                                break;
                        }
@@ -400,12 +400,10 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
                        {
                                Transform tfm = node->get_transform(socket);
                                std::stringstream ss;
-                               for(int i = 0; i < 4; i++) {
-                                       ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
-                                       if(i != 3) {
-                                               ss << " ";
-                                       }
+                               for(int i = 0; i < 3; i++) {
+                                       ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
                                }
+                               ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
                                attr = ss.str().c_str();
                                break;
                        }
@@ -416,11 +414,12 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
                                for(size_t j = 0; j < value.size(); j++) {
                                        const Transform& tfm = value[j];
 
-                                       for(int i = 0; i < 4; i++) {
-                                               ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
-                                               if(j != value.size() - 1 || i != 3) {
-                                                       ss << " ";
-                                               }
+                                       for(int i = 0; i < 3; i++) {
+                                               ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
+                                       }
+                                       ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
+                                       if(j != value.size() - 1) {
+                                               ss << " ";
                                        }
                                }
                                attr = ss.str().c_str();
index 50ea03a1f8f48a78a7c2a6ab3ea00270a5f5cd06..9b7f4e00084e62c5e44f7eafa86801b89e6cf924 100644 (file)
@@ -254,6 +254,7 @@ set(SRC_UTIL_HEADERS
        ../util/util_math_int3.h
        ../util/util_math_int4.h
        ../util/util_math_matrix.h
+       ../util/util_projection.h
        ../util/util_rect.h
        ../util/util_static_assert.h
        ../util/util_transform.h
index 6c33dad5426e96da948993a173260137d447b09f..060b3934a41c26ee1a730e13bed87951d5002203 100644 (file)
@@ -25,7 +25,6 @@ ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *k
        space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1);
        space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2);
        space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3);
-       space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
        return space;
 }
 
index efd6798ca5180d27a6bca3c977ae8db763e93a9d..cfc567ff9ca47db729e6fbf979071acf4c84e5b4 100644 (file)
@@ -276,7 +276,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
                                                                shader = __float_as_int(str.z);
                                                        }
 #endif
-                                                       int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+                                                       int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
 
                                                        /* if no transparent shadows, all light is blocked */
                                                        if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
index 522213f30ca4151e3fa94af5c07c7b2a1342e296..46fd178aed6bd32ef6bafd138b8cce977d0e794c 100644 (file)
@@ -358,7 +358,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
                                                                shader = __float_as_int(str.z);
                                                        }
 #endif
-                                                       int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+                                                       int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
 
                                                        /* if no transparent shadows, all light is blocked */
                                                        if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
index c72595eed10f8f0083add53990ece92884069147..42c053704d546c8ded41011ca8e0df866388f90c 100644 (file)
@@ -53,9 +53,7 @@ ccl_device_inline AttributeDescriptor attribute_not_found()
 
 ccl_device_inline uint object_attribute_map_offset(KernelGlobals *kg, int object)
 {
-       int offset = object*OBJECT_SIZE + 15;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return __float_as_uint(f.y);
+       return kernel_tex_fetch(__objects, object).attribute_map_offset;
 }
 
 ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
@@ -105,7 +103,6 @@ ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderD
        tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
        tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
        tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
-       tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
 
        return tfm;
 }
index faf3e3cdf2b50d23f33e33a4b322a726b300b64c..46c3f408f0b2763869bf84f331ab9cd11dcb2a81 100644 (file)
@@ -170,8 +170,7 @@ ccl_device_forceinline bool cardinal_curve_intersect(
                htfm = make_transform(
                        dir.z / d, 0, -dir.x /d, 0,
                        -dir.x * dir.y /d, d, -dir.y * dir.z /d, 0,
-                       dir.x, dir.y, dir.z, 0,
-                       0, 0, 0, 1);
+                       dir.x, dir.y, dir.z, 0);
 
                float4 v00 = kernel_tex_fetch(__curves, prim);
 
index 32aa2007f5d977675d658db98aad6919dd49a3c3..800649abf38a66e677c8d706e19abadc98a00590 100644 (file)
@@ -28,62 +28,44 @@ CCL_NAMESPACE_BEGIN
 
 enum ObjectTransform {
        OBJECT_TRANSFORM = 0,
-       OBJECT_INVERSE_TRANSFORM = 4,
-       OBJECT_TRANSFORM_MOTION_PRE = 0,
-       OBJECT_TRANSFORM_MOTION_MID = 4,
-       OBJECT_TRANSFORM_MOTION_POST = 8,
-       OBJECT_PROPERTIES = 12,
-       OBJECT_DUPLI = 13
+       OBJECT_INVERSE_TRANSFORM = 1,
 };
 
 enum ObjectVectorTransform {
-       OBJECT_VECTOR_MOTION_PRE = 0,
-       OBJECT_VECTOR_MOTION_POST = 3
+       OBJECT_PASS_MOTION_PRE = 0,
+       OBJECT_PASS_MOTION_POST = 1
 };
 
 /* Object to world space transformation */
 
 ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
 {
-       int offset = object*OBJECT_SIZE + (int)type;
-
-       Transform tfm;
-       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 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
-       return tfm;
+       if(type == OBJECT_INVERSE_TRANSFORM) {
+               return kernel_tex_fetch(__objects, object).itfm;
+       }
+       else {
+               return kernel_tex_fetch(__objects, object).tfm;
+       }
 }
 
 /* Lamp to world space transformation */
 
 ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse)
 {
-       int offset = lamp*LIGHT_SIZE + (inverse? 8 : 5);
-
-       Transform tfm;
-       tfm.x = kernel_tex_fetch(__light_data, offset + 0);
-       tfm.y = kernel_tex_fetch(__light_data, offset + 1);
-       tfm.z = kernel_tex_fetch(__light_data, offset + 2);
-       tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
-       return tfm;
+       if(inverse) {
+               return kernel_tex_fetch(__lights, lamp).itfm;
+       }
+       else {
+               return kernel_tex_fetch(__lights, lamp).tfm;
+       }
 }
 
 /* Object to world space transformation for motion vectors */
 
-ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
+ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
 {
-       int offset = object*OBJECT_VECTOR_SIZE + (int)type;
-
-       Transform tfm;
-       tfm.x = kernel_tex_fetch(__objects_vector, offset + 0);
-       tfm.y = kernel_tex_fetch(__objects_vector, offset + 1);
-       tfm.z = kernel_tex_fetch(__objects_vector, offset + 2);
-       tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
-       return tfm;
+       int offset = object*OBJECT_MOTION_PASS_SIZE + (int)type;
+       return kernel_tex_fetch(__object_motion_pass, offset);
 }
 
 /* Motion blurred object transformations */
@@ -91,27 +73,12 @@ ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int
 #ifdef __OBJECT_MOTION__
 ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int object, float time)
 {
-       MotionTransform motion;
-
-       int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE;
-
-       motion.pre.x = kernel_tex_fetch(__objects, offset + 0);
-       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.mid.x = kernel_tex_fetch(__objects, offset + 4);
-       motion.mid.y = kernel_tex_fetch(__objects, offset + 5);
-       motion.mid.z = kernel_tex_fetch(__objects, offset + 6);
-       motion.mid.w = kernel_tex_fetch(__objects, offset + 7);
-
-       motion.post.x = kernel_tex_fetch(__objects, offset + 8);
-       motion.post.y = kernel_tex_fetch(__objects, offset + 9);
-       motion.post.z = kernel_tex_fetch(__objects, offset + 10);
-       motion.post.w = kernel_tex_fetch(__objects, offset + 11);
+       const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
+       const ccl_global DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
+       const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
 
        Transform tfm;
-       transform_motion_interpolate(&tfm, &motion, time);
+       transform_motion_array_interpolate(&tfm, motion, num_steps, time);
 
        return tfm;
 }
@@ -237,9 +204,7 @@ ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd
 
 ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
 {
-       int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return f.x;
+       return kernel_tex_fetch(__objects, object).surface_area;
 }
 
 /* Pass ID number of object */
@@ -249,9 +214,7 @@ ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
        if(object == OBJECT_NONE)
                return 0.0f;
 
-       int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return f.y;
+       return kernel_tex_fetch(__objects, object).pass_id;
 }
 
 /* Per lamp random number for shader variation */
@@ -261,8 +224,7 @@ ccl_device_inline float lamp_random_number(KernelGlobals *kg, int lamp)
        if(lamp == LAMP_NONE)
                return 0.0f;
 
-       float4 f = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 4);
-       return f.y;
+       return kernel_tex_fetch(__lights, lamp).random;
 }
 
 /* Per object random number for shader variation */
@@ -272,9 +234,7 @@ ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
        if(object == OBJECT_NONE)
                return 0.0f;
 
-       int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return f.z;
+       return kernel_tex_fetch(__objects, object).random_number;
 }
 
 /* Particle ID from which this object was generated */
@@ -284,9 +244,7 @@ ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
        if(object == OBJECT_NONE)
                return 0;
 
-       int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return __float_as_uint(f.w);
+       return kernel_tex_fetch(__objects, object).particle_index;
 }
 
 /* Generated texture coordinate on surface from where object was instanced */
@@ -296,9 +254,10 @@ ccl_device_inline float3 object_dupli_generated(KernelGlobals *kg, int object)
        if(object == OBJECT_NONE)
                return make_float3(0.0f, 0.0f, 0.0f);
 
-       int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return make_float3(f.x, f.y, f.z);
+       const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+       return make_float3(kobject->dupli_generated[0],
+                          kobject->dupli_generated[1],
+                          kobject->dupli_generated[2]);
 }
 
 /* UV texture coordinate on surface from where object was instanced */
@@ -308,27 +267,24 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
        if(object == OBJECT_NONE)
                return make_float3(0.0f, 0.0f, 0.0f);
 
-       int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-       float4 f = kernel_tex_fetch(__objects, offset + 1);
-       return make_float3(f.x, f.y, 0.0f);
+       const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+       return make_float3(kobject->dupli_uv[0],
+                          kobject->dupli_uv[1],
+                          0.0f);
 }
 
 /* Information about mesh for motion blurred triangles and curves */
 
 ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
 {
-       int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-
        if(numkeys) {
-               float4 f = kernel_tex_fetch(__objects, offset);
-               *numkeys = __float_as_int(f.w);
+               *numkeys = kernel_tex_fetch(__objects, object).numkeys;
        }
 
-       float4 f = kernel_tex_fetch(__objects, offset + 1);
        if(numsteps)
-               *numsteps = __float_as_int(f.z);
+               *numsteps = kernel_tex_fetch(__objects, object).numsteps;
        if(numverts)
-               *numverts = __float_as_int(f.w);
+               *numverts = kernel_tex_fetch(__objects, object).numverts;
 }
 
 /* Offset to an objects patch map */
@@ -338,76 +294,56 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
        if(object == OBJECT_NONE)
                return 0;
 
-       int offset = object*OBJECT_SIZE + 15;
-       float4 f = kernel_tex_fetch(__objects, offset);
-       return __float_as_uint(f.x);
+       return kernel_tex_fetch(__objects, object).patch_map_offset;
 }
 
 /* Pass ID for shader */
 
 ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
 {
-       return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE + 1);
+       return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
 }
 
 /* Particle data from which object was instanced */
 
 ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f = kernel_tex_fetch(__particles, offset + 0);
-       return __float_as_uint(f.x);
+       return kernel_tex_fetch(__particles, particle).index;
 }
 
 ccl_device float particle_age(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f = kernel_tex_fetch(__particles, offset + 0);
-       return f.y;
+       return kernel_tex_fetch(__particles, particle).age;
 }
 
 ccl_device float particle_lifetime(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f = kernel_tex_fetch(__particles, offset + 0);
-       return f.z;
+       return kernel_tex_fetch(__particles, particle).lifetime;
 }
 
 ccl_device float particle_size(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f = kernel_tex_fetch(__particles, offset + 0);
-       return f.w;
+       return kernel_tex_fetch(__particles, particle).size;
 }
 
 ccl_device float4 particle_rotation(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f = kernel_tex_fetch(__particles, offset + 1);
-       return f;
+       return kernel_tex_fetch(__particles, particle).rotation;
 }
 
 ccl_device float3 particle_location(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f = kernel_tex_fetch(__particles, offset + 2);
-       return make_float3(f.x, f.y, f.z);
+       return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
 }
 
 ccl_device float3 particle_velocity(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f2 = kernel_tex_fetch(__particles, offset + 2);
-       float4 f3 = kernel_tex_fetch(__particles, offset + 3);
-       return make_float3(f2.w, f3.x, f3.y);
+       return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
 }
 
 ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
 {
-       int offset = particle*PARTICLE_SIZE;
-       float4 f3 = kernel_tex_fetch(__particles, offset + 3);
-       float4 f4 = kernel_tex_fetch(__particles, offset + 4);
-       return make_float3(f3.z, f3.w, f4.x);
+       return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
 }
 
 /* Object intersection in BVH */
index 60a1e483b847056ba968a697af07e10df02e96ef..c159be928856c211d051ef15fc1d2426f7ef88f8 100644 (file)
@@ -193,10 +193,10 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
         * transformation was set match the world/object space of motion_pre/post */
        Transform tfm;
        
-       tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
+       tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
        motion_pre = transform_point(&tfm, motion_pre);
 
-       tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
+       tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
        motion_post = transform_point(&tfm, motion_post);
 
        float3 motion_center;
@@ -204,14 +204,14 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
        /* camera motion, for perspective/orthographic motion.pre/post will be a
         * world-to-raster matrix, for panorama it's world-to-camera */
        if(kernel_data.cam.type != CAMERA_PANORAMA) {
-               tfm = kernel_data.cam.worldtoraster;
-               motion_center = transform_perspective(&tfm, center);
+               ProjectionTransform projection = kernel_data.cam.worldtoraster;
+               motion_center = transform_perspective(&projection, center);
 
-               tfm = kernel_data.cam.motion.pre;
-               motion_pre = transform_perspective(&tfm, motion_pre);
+               projection = kernel_data.cam.perspective_pre;
+               motion_pre = transform_perspective(&projection, motion_pre);
 
-               tfm = kernel_data.cam.motion.post;
-               motion_post = transform_perspective(&tfm, motion_post);
+               projection = kernel_data.cam.perspective_post;
+               motion_post = transform_perspective(&projection, motion_post);
        }
        else {
                tfm = kernel_data.cam.worldtocamera;
@@ -220,13 +220,13 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
                motion_center.x *= kernel_data.cam.width;
                motion_center.y *= kernel_data.cam.height;
 
-               tfm = kernel_data.cam.motion.pre;
+               tfm = kernel_data.cam.motion_pass_pre;
                motion_pre = normalize(transform_point(&tfm, motion_pre));
                motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
                motion_pre.x *= kernel_data.cam.width;
                motion_pre.y *= kernel_data.cam.height;
 
-               tfm = kernel_data.cam.motion.post;
+               tfm = kernel_data.cam.motion_pass_post;
                motion_post = normalize(transform_point(&tfm, motion_post));
                motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
                motion_post.x *= kernel_data.cam.width;
index 286d898992e658b251f507c1ce9d7e6bc59b1176..a4e47384b25cbda9cf1fe43cceb0fd539720ef22 100644 (file)
@@ -68,7 +68,7 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
        if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
        if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
 
-       if(r.w != 0.0f && r.w != 1.0f) {
+       if(r.w > 1e-8f && r.w != 1.0f) {
                /* For RGBA colors, unpremultiply after interpolation. */
                return float4_to_float3(r) / r.w;
        }
index 96cdb04d95548e43cf62f30223d6b82386717f98..b73ad47dad37b2c8e9c01c8c5d951239fbfa5ce9 100644 (file)
@@ -42,7 +42,7 @@ ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u
 ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
 {
        /* create ray form raster position */
-       Transform rastertocamera = kernel_data.cam.rastertocamera;
+       ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
        float3 raster = make_float3(raster_x, raster_y, 0.0f);
        float3 Pcamera = transform_perspective(&rastertocamera, raster);
 
@@ -54,13 +54,13 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
                 * interpolated field of view.
                 */
                if(ray->time < 0.5f) {
-                       Transform rastertocamera_pre = kernel_data.cam.perspective_motion.pre;
+                       ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
                        float3 Pcamera_pre =
                                transform_perspective(&rastertocamera_pre, raster);
                        Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
                }
                else {
-                       Transform rastertocamera_post = kernel_data.cam.perspective_motion.post;
+                       ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
                        float3 Pcamera_post =
                                transform_perspective(&rastertocamera_post, raster);
                        Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
@@ -91,17 +91,12 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
        Transform cameratoworld = kernel_data.cam.cameratoworld;
 
 #ifdef __CAMERA_MOTION__
-       if(kernel_data.cam.have_motion) {
-#  ifdef __KERNEL_OPENCL__
-               const MotionTransform tfm = kernel_data.cam.motion;
-               transform_motion_interpolate(&cameratoworld,
-                                                                        &tfm,
-                                            ray->time);
-#  else
-               transform_motion_interpolate(&cameratoworld,
-                                            &kernel_data.cam.motion,
-                                            ray->time);
-#  endif
+       if(kernel_data.cam.num_motion_steps) {
+               transform_motion_array_interpolate(
+                       &cameratoworld,
+                       kernel_tex_array(__camera_motion),
+                       kernel_data.cam.num_motion_steps,
+                       ray->time);
        }
 #endif
 
@@ -175,7 +170,7 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
 ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
 {
        /* create ray form raster position */
-       Transform rastertocamera = kernel_data.cam.rastertocamera;
+       ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
        float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
 
        float3 P;
@@ -203,17 +198,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
        Transform cameratoworld = kernel_data.cam.cameratoworld;
 
 #ifdef __CAMERA_MOTION__
-       if(kernel_data.cam.have_motion) {
-#  ifdef __KERNEL_OPENCL__
-               const MotionTransform tfm = kernel_data.cam.motion;
-               transform_motion_interpolate(&cameratoworld,
-                                            &tfm,
-                                            ray->time);
-#  else
-               transform_motion_interpolate(&cameratoworld,
-                                            &kernel_data.cam.motion,
-                                            ray->time);
-#  endif
+       if(kernel_data.cam.num_motion_steps) {
+               transform_motion_array_interpolate(
+                       &cameratoworld,
+                       kernel_tex_array(__camera_motion),
+                       kernel_data.cam.num_motion_steps,
+                       ray->time);
        }
 #endif
 
@@ -239,11 +229,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
 /* Panorama Camera */
 
 ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
+                                              const ccl_global DecomposedTransform *cam_motion,
                                               float raster_x, float raster_y,
                                               float lens_u, float lens_v,
                                               ccl_addr_space Ray *ray)
 {
-       Transform rastertocamera = cam->rastertocamera;
+       ProjectionTransform rastertocamera = cam->rastertocamera;
        float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
 
        /* create ray form raster position */
@@ -281,17 +272,12 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
        Transform cameratoworld = cam->cameratoworld;
 
 #ifdef __CAMERA_MOTION__
-       if(cam->have_motion) {
-#  ifdef __KERNEL_OPENCL__
-               const MotionTransform tfm = cam->motion;
-               transform_motion_interpolate(&cameratoworld,
-                                            &tfm,
-                                            ray->time);
-#  else
-               transform_motion_interpolate(&cameratoworld,
-                                            &cam->motion,
-                                            ray->time);
-#  endif
+       if(cam->num_motion_steps) {
+               transform_motion_array_interpolate(
+                       &cameratoworld,
+                       cam_motion,
+                       cam->num_motion_steps,
+                       ray->time);
        }
 #endif
 
@@ -410,12 +396,16 @@ ccl_device_inline void camera_sample(KernelGlobals *kg,
 #endif
 
        /* sample */
-       if(kernel_data.cam.type == CAMERA_PERSPECTIVE)
+       if(kernel_data.cam.type == CAMERA_PERSPECTIVE) {
                camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
-       else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+       }
+       else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
                camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
-       else
-               camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
+       }
+       else {
+               const ccl_global DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
+               camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
+       }
 }
 
 /* Utilities */
@@ -460,7 +450,7 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
                if(sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
                        P += camera_position(kg);
 
-               Transform tfm = kernel_data.cam.worldtondc;
+               ProjectionTransform tfm = kernel_data.cam.worldtondc;
                return transform_perspective(&tfm, P);
        }
        else {
index 61cd90e9d2af8e15a20344fb7d97682e38430e2f..d26b668cb11248062b29e1d9a281c15169b2e674 100644 (file)
@@ -118,6 +118,7 @@ template<typename T> struct texture  {
 #define kernel_tex_fetch_ssef(tex, index) (kg->tex.fetch_ssef(index))
 #define kernel_tex_fetch_ssei(tex, index) (kg->tex.fetch_ssei(index))
 #define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
+#define kernel_tex_array(tex) (kg->tex.data)
 
 #define kernel_data (kg->__data)
 
index 9bd7a572f5fdd48659a46b7851bf0f3566accf28..ac63bcf7ac9657a1398cb0dc83ec0dc482c748fe 100644 (file)
@@ -137,6 +137,7 @@ ccl_device_inline uint ccl_num_groups(uint d)
 
 /* Use arrays for regular data. */
 #define kernel_tex_fetch(t, index) t[(index)]
+#define kernel_tex_array(t) (t)
 
 #define kernel_data __data
 
index b02e3bc576d8e3018f3a596a8fea36e304c66301..671c47e2225fa2001aa89d2ed0b4c94f3b29acba 100644 (file)
 
 /* data lookup defines */
 #define kernel_data (*kg->data)
-#define kernel_tex_fetch(tex, index) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))[(index)]
+#define kernel_tex_array(tex) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))
+#define kernel_tex_fetch(tex, index) kernel_tex_array(tex)[(index)]
 
 /* define NULL */
 #define NULL 0
index 5875249b4049469451a8701bb6bdc9c7c0719de0..a5556c3be8fbe3d51164c94708e245a703dd69e0 100644 (file)
@@ -29,7 +29,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
        /* setup shading at emitter */
        float3 eval;
 
-       int shader_flag = kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE);
+       int shader_flag = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).flags;
 
 #ifdef __BACKGROUND_MIS__
        if(ls->type == LIGHT_BACKGROUND) {
@@ -51,9 +51,9 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
 #endif
        if(shader_flag & SD_HAS_CONSTANT_EMISSION)
        {
-               eval.x = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 2));
-               eval.y = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 3));
-               eval.z = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 4));
+               eval.x = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[0];
+               eval.y = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[1];
+               eval.z = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[2];
                if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
                        ls->Ng = -ls->Ng;
                }
index dfa3150dc920fb3a96f703de14e929de1366b17e..efab69ee37dfdf29bd39f2da64051ba14e58b1ea 100644 (file)
@@ -255,11 +255,11 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals
                                                                    float3 *lightpos,
                                                                    float3 *dir)
 {
-       float4 data0 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
-       float4 data3 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
+       int portal = kernel_data.integrator.portal_offset + index;
+       const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
 
-       *lightpos = make_float3(data0.y, data0.z, data0.w);
-       *dir = make_float3(data3.y, data3.z, data3.w);
+       *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+       *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
 
        /* Check whether portal is on the right side. */
        if(dot(*dir, P - *lightpos) > 1e-4f)
@@ -291,11 +291,10 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg,
                }
                num_possible++;
 
-               float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
-               float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
-
-               float3 axisu = make_float3(data1.y, data1.z, data1.w);
-               float3 axisv = make_float3(data2.y, data2.z, data2.w);
+               int portal = kernel_data.integrator.portal_offset + p;
+               const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+               float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+               float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
 
                if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL))
                        continue;
@@ -346,10 +345,10 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg,
 
                if(portal == 0) {
                        /* p is the portal to be sampled. */
-                       float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
-                       float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
-                       float3 axisu = make_float3(data1.y, data1.z, data1.w);
-                       float3 axisv = make_float3(data2.y, data2.z, data2.w);
+                       int portal = kernel_data.integrator.portal_offset + p;
+                       const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+                       float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+                       float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
 
                        *pdf = area_light_sample(P, &lightpos,
                                                 axisu, axisv,
@@ -479,14 +478,10 @@ ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, flo
        return disk_light_sample(normalize(P - center), randu, randv)*radius;
 }
 
-ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
+ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls)
 {
-       float3 dir = make_float3(data2.y, data2.z, data2.w);
        float3 I = ls->Ng;
 
-       float spot_angle = data1.w;
-       float spot_smooth = data2.x;
-
        float attenuation = dot(dir, I);
 
        if(attenuation <= spot_angle) {
@@ -518,12 +513,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
                                          float3 P,
                                          LightSample *ls)
 {
-       float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
-       float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
-
-       LightType type = (LightType)__float_as_int(data0.x);
+       const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+       LightType type = (LightType)klight->type;
        ls->type = type;
-       ls->shader = __float_as_int(data1.x);
+       ls->shader = klight->shader_id;
        ls->object = PRIM_NONE;
        ls->prim = PRIM_NONE;
        ls->lamp = lamp;
@@ -532,10 +525,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 
        if(type == LIGHT_DISTANT) {
                /* distant light */
-               float3 lightD = make_float3(data0.y, data0.z, data0.w);
+               float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
                float3 D = lightD;
-               float radius = data1.y;
-               float invarea = data1.w;
+               float radius = klight->distant.radius;
+               float invarea = klight->distant.invarea;
 
                if(radius > 0.0f)
                        D = distant_light_sample(D, radius, randu, randv);
@@ -562,10 +555,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
        }
 #endif
        else {
-               ls->P = make_float3(data0.y, data0.z, data0.w);
+               ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 
                if(type == LIGHT_POINT || type == LIGHT_SPOT) {
-                       float radius = data1.y;
+                       float radius = klight->spot.radius;
 
                        if(radius > 0.0f)
                                /* sphere light */
@@ -574,14 +567,19 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
                        ls->D = normalize_len(ls->P - P, &ls->t);
                        ls->Ng = -ls->D;
 
-                       float invarea = data1.z;
+                       float invarea = klight->spot.invarea;
                        ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
                        ls->pdf = invarea;
 
                        if(type == LIGHT_SPOT) {
                                /* spot light attenuation */
-                               float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-                               ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+                               float3 dir = make_float3(klight->spot.dir[0],
+                                         klight->spot.dir[1],
+                                                        klight->spot.dir[2]);
+                               ls->eval_fac *= spot_light_attenuation(dir,
+                                                                      klight->spot.spot_angle,
+                                                                      klight->spot.spot_smooth,
+                                                                      ls);
                                if(ls->eval_fac == 0.0f) {
                                        return false;
                                }
@@ -594,12 +592,15 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
                }
                else {
                        /* area light */
-                       float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-                       float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
-
-                       float3 axisu = make_float3(data1.y, data1.z, data1.w);
-                       float3 axisv = make_float3(data2.y, data2.z, data2.w);
-                       float3 D = make_float3(data3.y, data3.z, data3.w);
+                       float3 axisu = make_float3(klight->area.axisu[0],
+                                                  klight->area.axisu[1],
+                                                  klight->area.axisu[2]);
+                       float3 axisv = make_float3(klight->area.axisv[0],
+                                                  klight->area.axisv[1],
+                                                  klight->area.axisv[2]);
+                       float3 D = make_float3(klight->area.dir[0],
+                                              klight->area.dir[1],
+                                              klight->area.dir[2]);
 
                        if(dot(ls->P - P, D) > 0.0f) {
                                return false;
@@ -618,7 +619,7 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
                        ls->Ng = D;
                        ls->D = normalize_len(ls->P - P, &ls->t);
 
-                       float invarea = data2.x;
+                       float invarea = klight->area.invarea;
                        ls->eval_fac = 0.25f*invarea;
                }
        }
@@ -630,12 +631,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 
 ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
 {
-       float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
-       float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
-
-       LightType type = (LightType)__float_as_int(data0.x);
+       const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+       LightType type = (LightType)klight->type;
        ls->type = type;
-       ls->shader = __float_as_int(data1.x);
+       ls->shader = klight->shader_id;
        ls->object = PRIM_NONE;
        ls->prim = PRIM_NONE;
        ls->lamp = lamp;
@@ -648,7 +647,7 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 
        if(type == LIGHT_DISTANT) {
                /* distant light */
-               float radius = data1.y;
+               float radius = klight->distant.radius;
 
                if(radius == 0.0f)
                        return false;
@@ -670,9 +669,9 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
                 *             P
                 */
 
-               float3 lightD = make_float3(data0.y, data0.z, data0.w);
+               float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
                float costheta = dot(-lightD, D);
-               float cosangle = data1.z;
+               float cosangle = klight->distant.cosangle;
 
                if(costheta < cosangle)
                        return false;
@@ -683,13 +682,14 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
                ls->t = FLT_MAX;
 
                /* compute pdf */
-               float invarea = data1.w;
+               float invarea = klight->distant.invarea;
                ls->pdf = invarea/(costheta*costheta*costheta);
                ls->eval_fac = ls->pdf;
        }
        else if(type == LIGHT_POINT || type == LIGHT_SPOT) {
-               float3 lightP = make_float3(data0.y, data0.z, data0.w);
-               float radius = data1.y;
+               float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+               float radius = klight->spot.radius;
 
                /* sphere light */
                if(radius == 0.0f)
@@ -704,14 +704,19 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
                ls->Ng = -D;
                ls->D = D;
 
-               float invarea = data1.z;
+               float invarea = klight->spot.invarea;
                ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
                ls->pdf = invarea;
 
                if(type == LIGHT_SPOT) {
                        /* spot light attenuation */
-                       float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-                       ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+                       float3 dir = make_float3(klight->spot.dir[0],
+                                                klight->spot.dir[1],
+                                                klight->spot.dir[2]);
+                       ls->eval_fac *= spot_light_attenuation(dir,
+                                                              klight->spot.spot_angle,
+                                                              klight->spot.spot_smooth,
+                                                              ls);
 
                        if(ls->eval_fac == 0.0f)
                                return false;
@@ -726,22 +731,25 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
        }
        else if(type == LIGHT_AREA) {
                /* area light */
-               float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-               float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
-
-               float invarea = data2.x;
+               float invarea = klight->area.invarea;
                if(invarea == 0.0f)
                        return false;
 
-               float3 axisu = make_float3(data1.y, data1.z, data1.w);
-               float3 axisv = make_float3(data2.y, data2.z, data2.w);
-               float3 Ng = make_float3(data3.y, data3.z, data3.w);
+               float3 axisu = make_float3(klight->area.axisu[0],
+                                          klight->area.axisu[1],
+                                          klight->area.axisu[2]);
+               float3 axisv = make_float3(klight->area.axisv[0],
+                                          klight->area.axisv[1],
+                                          klight->area.axisv[2]);
+               float3 Ng = make_float3(klight->area.dir[0],
+                                       klight->area.dir[1],
+                                       klight->area.dir[2]);
 
                /* one sided */
                if(dot(D, Ng) >= 0.0f)
                        return false;
 
-               float3 light_P = make_float3(data0.y, data0.z, data0.w);
+               float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 
                if(!ray_quad_intersect(P, D, 0.0f, t, light_P,
                                       axisu, axisv, Ng,
@@ -784,7 +792,8 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
 #ifdef __INSTANCING__
        if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
 #  ifdef __OBJECT_MOTION__
-               Transform tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
+               float object_time = (time >= 0.0f) ? time : 0.5f;
+               Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
 #  else
                Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
 #  endif
@@ -1040,7 +1049,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
                int half_len = len >> 1;
                int middle = first + half_len;
 
-               if(r < kernel_tex_fetch(__light_distribution, middle).x) {
+               if(r < kernel_tex_fetch(__light_distribution, middle).totarea) {
                        len = half_len;
                }
                else {
@@ -1055,8 +1064,8 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
 
        /* Rescale to reuse random number. this helps the 2D samples within
         * each area light be stratified as well. */
-       float distr_min = kernel_tex_fetch(__light_distribution, index).x;
-       float distr_max = kernel_tex_fetch(__light_distribution, index+1).x;
+       float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
+       float distr_max = kernel_tex_fetch(__light_distribution, index+1).totarea;
        *randu = (r - distr_min)/(distr_max - distr_min);
 
        return index;
@@ -1066,8 +1075,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
 
 ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, int bounce)
 {
-       float4 data4 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 4);
-       return (bounce > __float_as_int(data4.x));
+       return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
 }
 
 ccl_device_noinline bool light_sample(KernelGlobals *kg,
@@ -1082,12 +1090,12 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
        int index = light_distribution_sample(kg, &randu);
 
        /* fetch light data */
-       float4 l = kernel_tex_fetch(__light_distribution, index);
-       int prim = __float_as_int(l.y);
+       const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
+       int prim = kdistribution->prim;
 
        if(prim >= 0) {
-               int object = __float_as_int(l.w);
-               int shader_flag = __float_as_int(l.z);
+               int object = kdistribution->mesh_light.object_id;
+               int shader_flag = kdistribution->mesh_light.shader_flag;
 
                triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
                ls->shader |= shader_flag;
@@ -1106,8 +1114,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
 
 ccl_device int light_select_num_samples(KernelGlobals *kg, int index)
 {
-       float4 data3 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 3);
-       return __float_as_int(data3.x);
+       return kernel_tex_fetch(__lights, index).samples;
 }
 
 CCL_NAMESPACE_END
index bd0e23b77057fb22ba96841b3f1b35eba548387a..96391db7649eb0115d34a097fa02708603b20162 100644 (file)
@@ -21,6 +21,7 @@
 #include "util/util_math.h"
 #include "util/util_math_fast.h"
 #include "util/util_math_intersect.h"
+#include "util/util_projection.h"
 #include "util/util_texture.h"
 #include "util/util_transform.h"
 
index b1f66852b7f1029c6942ac189dd81ed3a91cba62..fc8d06fc33d3054b14c3ab7c61e7715871b86848 100644 (file)
@@ -114,7 +114,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
 
        sd->I = -ray->D;
 
-       sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+       sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 
 #ifdef __INSTANCING__
        if(isect->object != OBJECT_NONE) {
@@ -199,7 +199,7 @@ void shader_setup_from_subsurface(
                motion_triangle_shader_setup(kg, sd, isect, ray, true);
        }
 
-       sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+       sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 
 #  ifdef __INSTANCING__
        if(isect->object != OBJECT_NONE) {
@@ -276,7 +276,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
        sd->time = time;
        sd->ray_length = t;
 
-       sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+       sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
        sd->object_flag = 0;
        if(sd->object != OBJECT_NONE) {
                sd->object_flag |= kernel_tex_fetch(__object_flag,
@@ -386,7 +386,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
        sd->Ng = -ray->D;
        sd->I = -ray->D;
        sd->shader = kernel_data.background.surface_shader;
-       sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+       sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
        sd->object_flag = 0;
        sd->time = ray->time;
        sd->ray_length = 0.0f;
@@ -1181,7 +1181,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
                sd->shader = stack[i].shader;
 
                sd->flag &= ~SD_SHADER_FLAGS;
-               sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+               sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
                sd->object_flag &= ~SD_OBJECT_FLAGS;
 
                if(sd->object != OBJECT_NONE) {
@@ -1254,7 +1254,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
                shader = __float_as_int(str.z);
        }
 #endif
-       int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+       int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
 
        return (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
 }
index 74b659557e5c29c2bc1ec742206b87e67e234c34..9047b93a0b2281cb5751b840541657f88e818776 100644 (file)
@@ -31,8 +31,13 @@ KERNEL_TEX(uint, __object_node)
 KERNEL_TEX(float2, __prim_time)
 
 /* objects */
-KERNEL_TEX(float4, __objects)
-KERNEL_TEX(float4, __objects_vector)
+KERNEL_TEX(KernelObject, __objects)
+KERNEL_TEX(Transform, __object_motion_pass)
+KERNEL_TEX(DecomposedTransform, __object_motion)
+KERNEL_TEX(uint, __object_flag)
+
+/* cameras */
+KERNEL_TEX(DecomposedTransform, __camera_motion)
 
 /* triangles */
 KERNEL_TEX(uint, __tri_shader)
@@ -55,18 +60,17 @@ KERNEL_TEX(float4, __attributes_float3)
 KERNEL_TEX(uchar4, __attributes_uchar4)
 
 /* lights */
-KERNEL_TEX(float4, __light_distribution)
-KERNEL_TEX(float4, __light_data)
+KERNEL_TEX(KernelLightDistribution, __light_distribution)
+KERNEL_TEX(KernelLight, __lights)
 KERNEL_TEX(float2, __light_background_marginal_cdf)
 KERNEL_TEX(float2, __light_background_conditional_cdf)
 
 /* particles */
-KERNEL_TEX(float4, __particles)
+KERNEL_TEX(KernelParticle, __particles)
 
 /* shaders */
 KERNEL_TEX(uint4, __svm_nodes)
-KERNEL_TEX(uint, __shader_flag)
-KERNEL_TEX(uint, __object_flag)
+KERNEL_TEX(KernelShader, __shaders)
 
 /* lookup tables */
 KERNEL_TEX(float, __lookup_table)
index 2a437cdbdc61d6a70c19a19e573f0f52c9eeeee5..977ceac12eaacf7cd556f14578d7c019d3a28956 100644 (file)
 CCL_NAMESPACE_BEGIN
 
 /* Constants */
-#define OBJECT_SIZE            16
-#define OBJECT_VECTOR_SIZE     6
-#define LIGHT_SIZE             11
-#define FILTER_TABLE_SIZE      1024
-#define RAMP_TABLE_SIZE                256
-#define SHUTTER_TABLE_SIZE             256
-#define PARTICLE_SIZE          5
-#define SHADER_SIZE            5
+#define OBJECT_MOTION_PASS_SIZE 2
+#define FILTER_TABLE_SIZE       1024
+#define RAMP_TABLE_SIZE         256
+#define SHUTTER_TABLE_SIZE      256
 
 #define BSSRDF_MIN_RADIUS                      1e-8f
 #define BSSRDF_MAX_HITS                                4
@@ -925,7 +921,7 @@ enum ShaderDataFlag {
        SD_HAS_BUMP               = (1 << 25),
        /* Has true displacement. */
        SD_HAS_DISPLACEMENT       = (1 << 26),
-       /* Has constant emission (value stored in __shader_flag) */
+       /* Has constant emission (value stored in __shaders) */
        SD_HAS_CONSTANT_EMISSION  = (1 << 27),
        /* Needs to access attributes */
        SD_NEED_ATTRIBUTES        = (1 << 28),
@@ -1163,7 +1159,7 @@ typedef struct KernelCamera {
 
        /* matrices */
        Transform cameratoworld;
-       Transform rastertocamera;
+       ProjectionTransform rastertocamera;
 
        /* differentials */
        float4 dx;
@@ -1177,7 +1173,7 @@ typedef struct KernelCamera {
 
        /* motion blur */
        float shuttertime;
-       int have_motion, have_perspective_motion;
+       int num_motion_steps, have_perspective_motion;
 
        /* clipping */
        float nearclip;
@@ -1197,22 +1193,22 @@ typedef struct KernelCamera {
        int is_inside_volume;
 
        /* more matrices */
-       Transform screentoworld;
-       Transform rastertoworld;
-       /* work around cuda sm 2.0 crash, this seems to
-        * cross some limit in combination with motion 
-        * Transform ndctoworld; */
-       Transform worldtoscreen;
-       Transform worldtoraster;
-       Transform worldtondc;
+       ProjectionTransform screentoworld;
+       ProjectionTransform rastertoworld;
+       ProjectionTransform ndctoworld;
+       ProjectionTransform worldtoscreen;
+       ProjectionTransform worldtoraster;
+       ProjectionTransform worldtondc;
        Transform worldtocamera;
 
-       MotionTransform motion;
+       /* Stores changes in the projeciton matrix. Use for camera zoom motion
+        * blur and motion pass output for perspective camera. */
+       ProjectionTransform perspective_pre;
+       ProjectionTransform perspective_post;
 
-       /* Denotes changes in the projective matrix, namely in rastertocamera.
-        * Used for camera zoom motion blur,
-        */
-       PerspectiveMotionTransform perspective_motion;
+       /* Transforms for motion pass. */
+       Transform motion_pass_pre;
+       Transform motion_pass_post;
 
        int shutter_table_offset;
 
@@ -1434,6 +1430,110 @@ typedef struct KernelData {
 } KernelData;
 static_assert_align(KernelData, 16);
 
+/* Kernel data structures. */
+
+typedef struct KernelObject {
+       Transform tfm;
+       Transform itfm;
+
+       float surface_area;
+       float pass_id;
+       float random_number;
+       int particle_index;
+
+       float dupli_generated[3];
+       float dupli_uv[2];
+
+       int numkeys;
+       int numsteps;
+       int numverts;
+
+       uint patch_map_offset;
+       uint attribute_map_offset;
+       uint motion_offset;
+       uint pad;
+} KernelObject;;
+static_assert_align(KernelObject, 16);
+
+typedef struct KernelSpotLight {
+       float radius;
+       float invarea;
+       float spot_angle;
+       float spot_smooth;
+       float dir[3];
+} KernelSpotLight;
+
+/* PointLight is SpotLight with only radius and invarea being used. */
+
+typedef struct KernelAreaLight {
+       float axisu[3];
+       float invarea;
+       float axisv[3];
+       float dir[3];
+} KernelAreaLight;
+
+typedef struct KernelDistantLight {
+       float radius;
+       float cosangle;
+       float invarea;
+} KernelDistantLight;
+
+typedef struct KernelLight {
+       int type;
+       float co[3];
+       int shader_id;
+       int samples;
+       float max_bounces;
+       float random;
+       Transform tfm;
+       Transform itfm;
+       union {
+               KernelSpotLight spot;
+               KernelAreaLight area;
+               KernelDistantLight distant;
+       };
+} KernelLight;
+static_assert_align(KernelLight, 16);
+
+typedef struct KernelLightDistribution {
+       float totarea;
+       int prim;
+       union {
+               struct {
+                       int shader_flag;
+                       int object_id;
+               } mesh_light;
+               struct {
+                       float pad;
+                       float size;
+               } lamp;
+       };
+} KernelLightDistribution;
+static_assert_align(KernelLightDistribution, 16);
+
+typedef struct KernelParticle {
+       int index;
+       float age;
+       float lifetime;
+       float size;
+       float4 rotation;
+       /* Only xyz are used of the following. float4 instead of float3 are used
+        * to ensure consistent padding/alignment across devices. */
+       float4 location;
+       float4 velocity;
+       float4 angular_velocity;
+} KernelParticle;
+static_assert_align(KernelParticle, 16);
+
+typedef struct KernelShader {
+       float constant_emission[3];
+       float pad1;
+       int flags;
+       int pass_id;
+       int pad2, pad3;
+} KernelShader;
+static_assert_align(KernelShader, 16);
+
 /* Declarations required for split kernel */
 
 /* Macro for queues */
index 058e7dccafdb0251a5f27b4da6b9b1e0bba0566e..88360e5f1ae5afde85cdcd4b4cd8789f1c6e8612 100644 (file)
@@ -104,7 +104,7 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel)
 ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space VolumeStack *stack)
 {
        for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
-               int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
+               int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
 
                if(shader_flag & SD_HETEROGENEOUS_VOLUME) {
                        return true;
@@ -134,7 +134,7 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
        int method = -1;
 
        for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
-               int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
+               int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
 
                if(shader_flag & SD_VOLUME_MIS) {
                        return SD_VOLUME_MIS;
index ae4c521659c7c17c781e79d67fe79f16a436a843..0c5e5e30e479168a3fc366fe9c4033a12f088451 100644 (file)
@@ -62,11 +62,17 @@ CCL_NAMESPACE_BEGIN
 
 /* RenderServices implementation */
 
-#define COPY_MATRIX44(m1, m2)  { \
-       CHECK_TYPE(m1, OSL::Matrix44*); \
-       CHECK_TYPE(m2, Transform*); \
-       memcpy(m1, m2, sizeof(*m2)); \
-} (void)0
+static void copy_matrix(OSL::Matrix44& m, const Transform& tfm)
+{
+       ProjectionTransform t = projection_transpose(ProjectionTransform(tfm));
+       memcpy(&m, &t, sizeof(m));
+}
+
+static void copy_matrix(OSL::Matrix44& m, const ProjectionTransform& tfm)
+{
+       ProjectionTransform t = projection_transpose(tfm);
+       memcpy(&m, &t, sizeof(m));
+}
 
 /* static ustrings */
 ustring OSLRenderServices::u_distance("distance");
@@ -167,14 +173,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
 #else
                        Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
 #endif
-                       tfm = transform_transpose(tfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, tfm);
 
                        return true;
                }
                else if(sd->type == PRIMITIVE_LAMP) {
-                       Transform tfm = transform_transpose(sd->ob_tfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, sd->ob_tfm);
 
                        return true;
                }
@@ -203,14 +207,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
 #else
                        Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
 #endif
-                       itfm = transform_transpose(itfm);
-                       COPY_MATRIX44(&result, &itfm);
+                       copy_matrix(result, itfm);
 
                        return true;
                }
                else if(sd->type == PRIMITIVE_LAMP) {
-                       Transform tfm = transform_transpose(sd->ob_itfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, sd->ob_itfm);
 
                        return true;
                }
@@ -224,23 +226,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
        KernelGlobals *kg = kernel_globals;
 
        if(from == u_ndc) {
-               Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.ndctoworld);
                return true;
        }
        else if(from == u_raster) {
-               Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.rastertoworld);
                return true;
        }
        else if(from == u_screen) {
-               Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.screentoworld);
                return true;
        }
        else if(from == u_camera) {
-               Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.cameratoworld);
                return true;
        }
        else if(from == u_world) {
@@ -256,23 +254,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
        KernelGlobals *kg = kernel_globals;
 
        if(to == u_ndc) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtondc);
                return true;
        }
        else if(to == u_raster) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtoraster);
                return true;
        }
        else if(to == u_screen) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtoscreen);
                return true;
        }
        else if(to == u_camera) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtocamera);
                return true;
        }
        else if(to == u_world) {
@@ -298,14 +292,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
                        KernelGlobals *kg = sd->osl_globals;
                        Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
 #endif
-                       tfm = transform_transpose(tfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, tfm);
 
                        return true;
                }
                else if(sd->type == PRIMITIVE_LAMP) {
-                       Transform tfm = transform_transpose(sd->ob_tfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, sd->ob_tfm);
 
                        return true;
                }
@@ -329,14 +321,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
                        KernelGlobals *kg = sd->osl_globals;
                        Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
 #endif
-                       tfm = transform_transpose(tfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, tfm);
 
                        return true;
                }
                else if(sd->type == PRIMITIVE_LAMP) {
-                       Transform tfm = transform_transpose(sd->ob_itfm);
-                       COPY_MATRIX44(&result, &tfm);
+                       copy_matrix(result, sd->ob_itfm);
 
                        return true;
                }
@@ -350,23 +340,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
        KernelGlobals *kg = kernel_globals;
 
        if(from == u_ndc) {
-               Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.ndctoworld);
                return true;
        }
        else if(from == u_raster) {
-               Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.rastertoworld);
                return true;
        }
        else if(from == u_screen) {
-               Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.screentoworld);
                return true;
        }
        else if(from == u_camera) {
-               Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.cameratoworld);
                return true;
        }
 
@@ -378,23 +364,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
        KernelGlobals *kg = kernel_globals;
        
        if(to == u_ndc) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtondc);
                return true;
        }
        else if(to == u_raster) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtoraster);
                return true;
        }
        else if(to == u_screen) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtoscreen);
                return true;
        }
        else if(to == u_camera) {
-               Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
-               COPY_MATRIX44(&result, &tfm);
+               copy_matrix(result, kernel_data.cam.worldtocamera);
                return true;
        }
        
@@ -570,8 +552,7 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
 static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
 {
        if(type == TypeDesc::TypeMatrix) {
-               Transform transpose = transform_transpose(tfm);
-               memcpy(val, &transpose, sizeof(Transform));
+               copy_matrix(*(OSL::Matrix44*)val, tfm);
                return true;
        }
 
index 0a890545af45db3286e1cf9b7d4d6c1ba5638d93..42a7ae9946f401b967fc9b6f3c421d8dfab86a24 100644 (file)
@@ -26,7 +26,6 @@ ccl_device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack
        tfm.x = read_node_float(kg, offset);
        tfm.y = read_node_float(kg, offset);
        tfm.z = read_node_float(kg, offset);
-       tfm.w = read_node_float(kg, offset);
 
        float3 r = transform_point(&tfm, v);
        stack_store_float3(stack, out_offset, r);
index c94327401f52c8a65d64819874c79c2cfa54ae5a..6ff39e5f587ad23151a8972c4c58564d7fdc5144 100644 (file)
@@ -42,7 +42,6 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
                                tfm.x = read_node_float(kg, offset);
                                tfm.y = read_node_float(kg, offset);
                                tfm.z = read_node_float(kg, offset);
-                               tfm.w = read_node_float(kg, offset);
                                data = transform_point(&tfm, data);
                        }
                        break;
@@ -123,7 +122,6 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
                                tfm.x = read_node_float(kg, offset);
                                tfm.y = read_node_float(kg, offset);
                                tfm.z = read_node_float(kg, offset);
-                               tfm.w = read_node_float(kg, offset);
                                data = transform_point(&tfm, data);
                        }
                        break;
@@ -207,7 +205,6 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
                                tfm.x = read_node_float(kg, offset);
                                tfm.y = read_node_float(kg, offset);
                                tfm.z = read_node_float(kg, offset);
-                               tfm.w = read_node_float(kg, offset);
                                data = transform_point(&tfm, data);
                        }
                        break;
index d967516a5c9b4546e494173a87f60ccff0b81e89..43b433683e06d7c07dca12317730de2e423cc3de 100644 (file)
@@ -39,7 +39,6 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
                tfm.x = read_node_float(kg, offset);
                tfm.y = read_node_float(kg, offset);
                tfm.z = read_node_float(kg, offset);
-               tfm.w = read_node_float(kg, offset);
                co = transform_point(&tfm, co);
        }
 
index a2fda12ec8506c500cbe35b811bab306bea9d299..38936ffc094f35e72ea3be9eb0f672e54db2c080 100644 (file)
@@ -82,6 +82,7 @@ NODE_DEFINE(Camera)
        SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
 
        SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
+       SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
 
        SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
 
@@ -151,9 +152,6 @@ Camera::Camera()
        height = 512;
        resolution = 1;
 
-       motion.pre = transform_identity();
-       motion.post = transform_identity();
-       use_motion = false;
        use_perspective_motion = false;
 
        shutter_curve.resize(RAMP_TABLE_SIZE);
@@ -163,12 +161,12 @@ Camera::Camera()
 
        compute_auto_viewplane();
 
-       screentoworld = transform_identity();
-       rastertoworld = transform_identity();
-       ndctoworld = transform_identity();
-       rastertocamera = transform_identity();
+       screentoworld = projection_identity();
+       rastertoworld = projection_identity();
+       ndctoworld = projection_identity();
+       rastertocamera = projection_identity();
        cameratoworld = transform_identity();
-       worldtoraster = transform_identity();
+       worldtoraster = projection_identity();
 
        dx = make_float3(0.0f, 0.0f, 0.0f);
        dy = make_float3(0.0f, 0.0f, 0.0f);
@@ -241,18 +239,18 @@ void Camera::update(Scene *scene)
        Transform full_rastertoscreen = transform_inverse(full_screentoraster);
 
        /* screen to camera */
-       Transform cameratoscreen;
+       ProjectionTransform cameratoscreen;
        if(type == CAMERA_PERSPECTIVE)
-               cameratoscreen = transform_perspective(fov, nearclip, farclip);
+               cameratoscreen = projection_perspective(fov, nearclip, farclip);
        else if(type == CAMERA_ORTHOGRAPHIC)
-               cameratoscreen = transform_orthographic(nearclip, farclip);
+               cameratoscreen = projection_orthographic(nearclip, farclip);
        else
-               cameratoscreen = transform_identity();
+               cameratoscreen = projection_identity();
        
-       Transform screentocamera = transform_inverse(cameratoscreen);
+       ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
 
        rastertocamera = screentocamera * rastertoscreen;
-       Transform full_rastertocamera = screentocamera * full_rastertoscreen;
+       ProjectionTransform full_rastertocamera = screentocamera * full_rastertoscreen;
        cameratoraster = screentoraster * cameratoscreen;
 
        cameratoworld = matrix;
@@ -270,10 +268,10 @@ void Camera::update(Scene *scene)
 
        /* differentials */
        if(type == CAMERA_ORTHOGRAPHIC) {
-               dx = transform_direction(&rastertocamera, make_float3(1, 0, 0));
-               dy = transform_direction(&rastertocamera, make_float3(0, 1, 0));
-               full_dx = transform_direction(&full_rastertocamera, make_float3(1, 0, 0));
-               full_dy = transform_direction(&full_rastertocamera, make_float3(0, 1, 0));
+               dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
+               dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
+               full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
+               full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
        }
        else if(type == CAMERA_PERSPECTIVE) {
                dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
@@ -302,23 +300,6 @@ void Camera::update(Scene *scene)
                frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
        }
 
-       /* TODO(sergey): Support other types of camera. */
-       if(type == CAMERA_PERSPECTIVE) {
-               /* TODO(sergey): Move to an utility function and de-duplicate with
-                * calculation above.
-                */
-               Transform screentocamera_pre =
-                       transform_inverse(transform_perspective(fov_pre,
-                                                               nearclip,
-                                                               farclip));
-               Transform screentocamera_post =
-                       transform_inverse(transform_perspective(fov_post,
-                                                               nearclip,
-                                                               farclip));
-               perspective_motion.pre = screentocamera_pre * rastertoscreen;
-               perspective_motion.post = screentocamera_post * rastertoscreen;
-       }
-
        /* Compute kernel camera data. */
        KernelCamera *kcam = &kernel_camera;
 
@@ -331,41 +312,65 @@ void Camera::update(Scene *scene)
        kcam->worldtoscreen = worldtoscreen;
        kcam->worldtoraster = worldtoraster;
        kcam->worldtondc = worldtondc;
+       kcam->ndctoworld = ndctoworld;
 
        /* camera motion */
-       kcam->have_motion = 0;
+       kcam->num_motion_steps = 0;
        kcam->have_perspective_motion = 0;
+       kernel_camera_motion.clear();
+
+       /* Test if any of the transforms are actually different. */
+       bool have_motion = false;
+       for(size_t i = 0; i < motion.size(); i++) {
+               have_motion = have_motion || motion[i] != matrix;
+       }
 
        if(need_motion == Scene::MOTION_PASS) {
                /* TODO(sergey): Support perspective (zoom, fov) motion. */
                if(type == CAMERA_PANORAMA) {
-                       if(use_motion) {
-                               kcam->motion.pre = transform_inverse(motion.pre);
-                               kcam->motion.post = transform_inverse(motion.post);
+                       if(have_motion) {
+                               kcam->motion_pass_pre = transform_inverse(motion[0]);
+                               kcam->motion_pass_post = transform_inverse(motion[motion.size()-1]);
                        }
                        else {
-                               kcam->motion.pre = kcam->worldtocamera;
-                               kcam->motion.post = kcam->worldtocamera;
+                               kcam->motion_pass_pre = kcam->worldtocamera;
+                               kcam->motion_pass_post = kcam->worldtocamera;
                        }
                }
                else {
-                       if(use_motion) {
-                               kcam->motion.pre = cameratoraster * transform_inverse(motion.pre);
-                               kcam->motion.post = cameratoraster * transform_inverse(motion.post);
+                       if(have_motion) {
+                               kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
+                               kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size()-1]);
                        }
                        else {
-                               kcam->motion.pre = worldtoraster;
-                               kcam->motion.post = worldtoraster;
+                               kcam->perspective_pre = worldtoraster;
+                               kcam->perspective_post = worldtoraster;
                        }
                }
        }
        else if(need_motion == Scene::MOTION_BLUR) {
-               if(use_motion) {
-                       transform_motion_decompose(&kcam->motion, &motion, &matrix);
-                       kcam->have_motion = 1;
+               if(have_motion) {
+                       kernel_camera_motion.resize(motion.size());
+                       transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
+                       kcam->num_motion_steps = motion.size();
                }
-               if(use_perspective_motion) {
-                       kcam->perspective_motion = perspective_motion;
+
+               /* TODO(sergey): Support other types of camera. */
+               if(use_perspective_motion && type == CAMERA_PERSPECTIVE) {
+                       /* TODO(sergey): Move to an utility function and de-duplicate with
+                        * calculation above.
+                        */
+                       ProjectionTransform screentocamera_pre =
+                                       projection_inverse(projection_perspective(fov_pre,
+                                                                                 nearclip,
+                                                                                 farclip));
+                       ProjectionTransform screentocamera_post =
+                                       projection_inverse(projection_perspective(fov_post,
+                                                                                 nearclip,
+                                                                                 farclip));
+
+                       kcam->perspective_pre = screentocamera_pre * rastertoscreen;
+                       kcam->perspective_post = screentocamera_post * rastertoscreen;
                        kcam->have_perspective_motion = 1;
                }
        }
@@ -470,6 +475,16 @@ void Camera::device_update(Device * /* device */,
        }
 
        dscene->data.cam = kernel_camera;
+
+       size_t num_motion_steps = kernel_camera_motion.size();
+       if(num_motion_steps) {
+               DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
+               memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
+               dscene->camera_motion.copy_to_device();
+       }
+       else {
+               dscene->camera_motion.free();
+       }
 }
 
 void Camera::device_update_volume(Device * /*device*/,
@@ -496,10 +511,11 @@ void Camera::device_update_volume(Device * /*device*/,
 }
 
 void Camera::device_free(Device * /*device*/,
-                         DeviceScene * /*dscene*/,
+                         DeviceScene *dscene,
                          Scene *scene)
 {
        scene->lookup_tables->remove_table(&shutter_table_offset);
+       dscene->camera_motion.free();
 }
 
 bool Camera::modified(const Camera& cam)
@@ -510,7 +526,6 @@ bool Camera::modified(const Camera& cam)
 bool Camera::motion_modified(const Camera& cam)
 {
        return !((motion == cam.motion) &&
-                (use_motion == cam.use_motion) &&
                 (use_perspective_motion == cam.use_perspective_motion));
 }
 
@@ -606,7 +621,7 @@ float Camera::world_to_raster_size(float3 P)
                res = min(len(full_dx), len(full_dy));
 
                if(offscreen_dicing_scale > 1.0f) {
-                       float3 p = transform_perspective(&worldtocamera, P);
+                       float3 p = transform_point(&worldtocamera, P);
                        float3 v = transform_perspective(&rastertocamera, make_float3(width, height, 0.0f));
 
                        /* Create point clamped to frustum */
@@ -707,17 +722,17 @@ float Camera::world_to_raster_size(float3 P)
                 * may be a better way to do this, but calculating differentials from the
                 * point directly ahead seems to produce good enough results. */
 #if 0
-               float2 dir = direction_to_panorama(&kernel_camera, normalize(D));
+               float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
                float3 raster = transform_perspective(&cameratoraster, make_float3(dir.x, dir.y, 0.0f));
 
                ray.t = 1.0f;
-               camera_sample_panorama(&kernel_camera, raster.x, raster.y, 0.0f, 0.0f, &ray);
+               camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
                if(ray.t == 0.0f) {
                        /* No differentials, just use from directly ahead. */
-                       camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
+                       camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
                }
 #else
-               camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
+               camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
 #endif
 
                differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist);
@@ -729,4 +744,27 @@ float Camera::world_to_raster_size(float3 P)
        return res;
 }
 
+bool Camera::use_motion() const
+{
+       return motion.size() > 1;
+}
+
+float Camera::motion_time(int step) const
+{
+       return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
+
+int Camera::motion_step(float time) const
+{
+       if(use_motion()) {
+               for(int step = 0; step < motion.size(); step++) {
+                       if(time == motion_time(step)) {
+                               return step;
+                       }
+               }
+       }
+
+       return -1;
+}
+
 CCL_NAMESPACE_END
index 4ec0fe3bc6ebfd74deffd2e1f999bc38f5d9ce6e..37d05c01bd935ccde1428da529bec86220b4615e 100644 (file)
@@ -22,6 +22,7 @@
 #include "graph/node.h"
 
 #include "util/util_boundbox.h"
+#include "util/util_projection.h"
 #include "util/util_transform.h"
 #include "util/util_types.h"
 
@@ -140,24 +141,23 @@ public:
        Transform matrix;
 
        /* motion */
-       MotionTransform motion;
-       bool use_motion, use_perspective_motion;
+       array<Transform> motion;
+       bool use_perspective_motion;
        float fov_pre, fov_post;
-       PerspectiveMotionTransform perspective_motion;
 
        /* computed camera parameters */
-       Transform screentoworld;
-       Transform rastertoworld;
-       Transform ndctoworld;
+       ProjectionTransform screentoworld;
+       ProjectionTransform rastertoworld;
+       ProjectionTransform ndctoworld;
        Transform cameratoworld;
 
-       Transform worldtoraster;
-       Transform worldtoscreen;
-       Transform worldtondc;
+       ProjectionTransform worldtoraster;
+       ProjectionTransform worldtoscreen;
+       ProjectionTransform worldtondc;
        Transform worldtocamera;
 
-       Transform rastertocamera;
-       Transform cameratoraster;
+       ProjectionTransform rastertocamera;
+       ProjectionTransform cameratoraster;
 
        float3 dx;
        float3 dy;
@@ -176,6 +176,7 @@ public:
 
        /* Kernel camera data, copied here for dicing. */
        KernelCamera kernel_camera;
+       array<DecomposedTransform> kernel_camera_motion;
 
        /* functions */
        Camera();
@@ -199,6 +200,11 @@ public:
        /* Calculates the width of a pixel at point in world space. */
        float world_to_raster_size(float3 P);
 
+       /* Motion blur. */
+       float motion_time(int step) const;
+       int motion_step(float time) const;
+       bool use_motion() const;
+
 private:
        /* Private utility functions. */
        float3 transform_raster_to_world(float raster_x, float raster_y);
index b62453cf5fc9a0241bd00a9c11559adeccfed747..8dec7e4ea643b78f28aefd5907a6fcb35e1b538e 100644 (file)
@@ -288,7 +288,7 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
        VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
 
        /* emission area */
-       float4 *distribution = dscene->light_distribution.alloc(num_distribution + 1);
+       KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
        float totarea = 0.0f;
 
        /* triangles */
@@ -334,10 +334,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
                                                 : scene->default_surface;
 
                        if(shader->use_mis && shader->has_surface_emission) {
-                               distribution[offset].x = totarea;
-                               distribution[offset].y = __int_as_float(i + mesh->tri_offset);
-                               distribution[offset].z = __int_as_float(shader_flag);
-                               distribution[offset].w = __int_as_float(object_id);
+                               distribution[offset].totarea = totarea;
+                               distribution[offset].prim = i + mesh->tri_offset;
+                               distribution[offset].mesh_light.shader_flag = shader_flag;
+                               distribution[offset].mesh_light.object_id = object_id;
                                offset++;
 
                                Mesh::Triangle t = mesh->get_triangle(i);
@@ -372,10 +372,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
                if(!light->is_enabled)
                        continue;
 
-               distribution[offset].x = totarea;
-               distribution[offset].y = __int_as_float(~light_index);
-               distribution[offset].z = 1.0f;
-               distribution[offset].w = light->size;
+               distribution[offset].totarea = totarea;
+               distribution[offset].prim = ~light_index;
+               distribution[offset].lamp.pad = 1.0f;
+               distribution[offset].lamp.size = light->size;
                totarea += lightarea;
 
                if(light->size > 0.0f && light->use_mis)
@@ -390,15 +390,15 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
        }
 
        /* normalize cumulative distribution functions */
-       distribution[num_distribution].x = totarea;
-       distribution[num_distribution].y = 0.0f;
-       distribution[num_distribution].z = 0.0f;
-       distribution[num_distribution].w = 0.0f;
+       distribution[num_distribution].totarea = totarea;
+       distribution[num_distribution].prim = 0.0f;
+       distribution[num_distribution].lamp.pad = 0.0f;
+       distribution[num_distribution].lamp.size = 0.0f;
 
        if(totarea > 0.0f) {
                for(size_t i = 0; i < num_distribution; i++)
-                       distribution[i].x /= totarea;
-               distribution[num_distribution].x = 1.0f;
+                       distribution[i].totarea /= totarea;
+               distribution[num_distribution].totarea = 1.0f;
        }
 
        if(progress.get_cancel()) return;
@@ -620,7 +620,7 @@ void LightManager::device_update_points(Device *,
                }
        }
 
-       float4 *light_data = dscene->light_data.alloc(num_lights*LIGHT_SIZE);
+       KernelLight *klights = dscene->lights.alloc(num_lights);
 
        if(num_lights == 0) {
                VLOG(1) << "No effective light, ignoring points update.";
@@ -637,8 +637,8 @@ void LightManager::device_update_points(Device *,
                float3 co = light->co;
                Shader *shader = (light->shader) ? light->shader : scene->default_light;
                int shader_id = scene->shader_manager->get_shader_id(shader);
-               float samples = __int_as_float(light->samples);
-               float max_bounces = __int_as_float(light->max_bounces);
+               int samples = light->samples;
+               int max_bounces = light->max_bounces;
                float random = (float)light->random_id * (1.0f/(float)0xFFFFFFFF);
 
                if(!light->cast_shadow)
@@ -661,6 +661,9 @@ void LightManager::device_update_points(Device *,
                        use_light_visibility = true;
                }
 
+               klights[light_index].type = light->type;
+               klights[light_index].samples = samples;
+
                if(light->type == LIGHT_POINT) {
                        shader_id &= ~SHADER_AREA_LIGHT;
 
@@ -670,10 +673,12 @@ void LightManager::device_update_points(Device *,
                        if(light->use_mis && radius > 0.0f)
                                shader_id |= SHADER_USE_MIS;
 
-                       light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-                       light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
-                       light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-                       light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+                       klights[light_index].co[0] = co.x;
+                       klights[light_index].co[1] = co.y;
+                       klights[light_index].co[2] = co.z;
+
+                       klights[light_index].spot.radius = radius;
+                       klights[light_index].spot.invarea = invarea;
                }
                else if(light->type == LIGHT_DISTANT) {
                        shader_id &= ~SHADER_AREA_LIGHT;
@@ -690,10 +695,13 @@ void LightManager::device_update_points(Device *,
                        if(light->use_mis && area > 0.0f)
                                shader_id |= SHADER_USE_MIS;
 
-                       light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
-                       light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
-                       light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-                       light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+                       klights[light_index].co[0] = dir.x;
+                       klights[light_index].co[1] = dir.y;
+                       klights[light_index].co[2] = dir.z;
+
+                       klights[light_index].distant.invarea = invarea;
+                       klights[light_index].distant.radius = radius;
+                       klights[light_index].distant.cosangle = cosangle;
                }
                else if(light->type == LIGHT_BACKGROUND) {
                        uint visibility = scene->background->visibility;
@@ -717,11 +725,6 @@ void LightManager::device_update_points(Device *,
                                shader_id |= SHADER_EXCLUDE_SCATTER;
                                use_light_visibility = true;
                        }
-
-                       light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
-                       light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
-                       light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-                       light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
                }
                else if(light->type == LIGHT_AREA) {
                        float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -735,10 +738,20 @@ void LightManager::device_update_points(Device *,
                        if(light->use_mis && area > 0.0f)
                                shader_id |= SHADER_USE_MIS;
 
-                       light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-                       light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
-                       light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
-                       light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
+                       klights[light_index].co[0] = co.x;
+                       klights[light_index].co[1] = co.y;
+                       klights[light_index].co[2] = co.z;
+
+                       klights[light_index].area.axisu[0] = axisu.x;
+                       klights[light_index].area.axisu[1] = axisu.y;
+                       klights[light_index].area.axisu[2] = axisu.z;
+                       klights[light_index].area.axisv[0] = axisv.x;
+                       klights[light_index].area.axisv[1] = axisv.y;
+                       klights[light_index].area.axisv[2] = axisv.z;
+                       klights[light_index].area.invarea = invarea;
+                       klights[light_index].area.dir[0] = dir.x;
+                       klights[light_index].area.dir[1] = dir.y;
+                       klights[light_index].area.dir[2] = dir.z;
                }
                else if(light->type == LIGHT_SPOT) {
                        shader_id &= ~SHADER_AREA_LIGHT;
@@ -754,18 +767,26 @@ void LightManager::device_update_points(Device *,
                        if(light->use_mis && radius > 0.0f)
                                shader_id |= SHADER_USE_MIS;
 
-                       light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-                       light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
-                       light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
-                       light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+                       klights[light_index].co[0] = co.x;
+                       klights[light_index].co[1] = co.y;
+                       klights[light_index].co[2] = co.z;
+
+                       klights[light_index].spot.radius = radius;
+                       klights[light_index].spot.invarea = invarea;
+                       klights[light_index].spot.spot_angle = spot_angle;
+                       klights[light_index].spot.spot_smooth = spot_smooth;
+                       klights[light_index].spot.dir[0] = dir.x;
+                       klights[light_index].spot.dir[1] = dir.y;
+                       klights[light_index].spot.dir[2] = dir.z;
                }
 
-               light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, random, 0.0f, 0.0f);
+               klights[light_index].shader_id = shader_id;
+
+               klights[light_index].max_bounces = max_bounces;
+               klights[light_index].random = random;
 
-               Transform tfm = light->tfm;
-               Transform itfm = transform_inverse(tfm);
-               memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
-               memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+               klights[light_index].tfm = light->tfm;
+               klights[light_index].itfm = transform_inverse(light->tfm);
 
                light_index++;
        }
@@ -782,21 +803,27 @@ void LightManager::device_update_points(Device *,
                float3 axisu = light->axisu*(light->sizeu*light->size);
                float3 axisv = light->axisv*(light->sizev*light->size);
                float area = len(axisu)*len(axisv);
-               float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+               float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
                float3 dir = light->dir;
 
                dir = safe_normalize(dir);
 
-               light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-               light_data[light_index*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
-               light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
-               light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
-               light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
-
-               Transform tfm = light->tfm;
-               Transform itfm = transform_inverse(tfm);
-               memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
-               memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+               klights[light_index].co[0] = co.x;
+               klights[light_index].co[1] = co.y;
+               klights[light_index].co[2] = co.z;
+
+               klights[light_index].area.axisu[0] = axisu.x;
+               klights[light_index].area.axisu[1] = axisu.y;
+               klights[light_index].area.axisu[2] = axisu.z;
+               klights[light_index].area.axisv[0] = axisv.x;
+               klights[light_index].area.axisv[1] = axisv.y;
+               klights[light_index].area.axisv[2] = axisv.z;
+               klights[light_index].area.invarea = invarea;
+               klights[light_index].area.dir[0] = dir.x;
+               klights[light_index].area.dir[1] = dir.y;
+               klights[light_index].area.dir[2] = dir.z;
+               klights[light_index].tfm = light->tfm;
+               klights[light_index].itfm = transform_inverse(light->tfm);
 
                light_index++;
        }
@@ -806,7 +833,7 @@ void LightManager::device_update_points(Device *,
        VLOG(1) << "Number of lights without contribution: "
                << num_scene_lights - light_index;
 
-       dscene->light_data.copy_to_device();
+       dscene->lights.copy_to_device();
 }
 
 void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -842,7 +869,7 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
 void LightManager::device_free(Device *, DeviceScene *dscene)
 {
        dscene->light_distribution.free();
-       dscene->light_data.free();
+       dscene->lights.free();
        dscene->light_background_marginal_cdf.free();
        dscene->light_background_conditional_cdf.free();
 }
index 47d24970949eeef220f4df29d71565f62957239b..7cfbb7b7c7dbde06fc8e8a95753b27bd0b9cc397 100644 (file)
@@ -877,15 +877,8 @@ void Mesh::add_undisplaced()
        }
 }
 
-void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
+void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
 {
-       Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
-       if(attr_vN == NULL) {
-               /* Happens on objects with just hair. */
-               return;
-       }
-
-       float3 *vN = attr_vN->data_float3();
        uint shader_id = 0;
        uint last_shader = -1;
        bool last_smooth = false;
@@ -893,10 +886,6 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
        size_t triangles_size = num_triangles();
        int *shader_ptr = shader.data();
 
-       bool do_transform = transform_applied;
-       Transform ntfm = transform_normal;
-
-       /* save shader */
        for(size_t i = 0; i < triangles_size; i++) {
                if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
                        last_shader = shader_ptr[i];
@@ -908,7 +897,20 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
 
                tri_shader[i] = shader_id;
        }
+}
+
+void Mesh::pack_normals(float4 *vnormal)
+{
+       Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+       if(attr_vN == NULL) {
+               /* Happens on objects with just hair. */
+               return;
+       }
 
+       bool do_transform = transform_applied;
+       Transform ntfm = transform_normal;
+
+       float3 *vN = attr_vN->data_float3();
        size_t verts_size = verts.size();
 
        for(size_t i = 0; i < verts_size; i++) {
@@ -1117,6 +1119,32 @@ bool Mesh::has_true_displacement() const
        return false;
 }
 
+float Mesh::motion_time(int step) const
+{
+       return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
+}
+
+int Mesh::motion_step(float time) const
+{
+       if(motion_steps > 1) {
+               int attr_step = 0;
+
+               for(int step = 0; step < motion_steps; step++) {
+                       float step_time = motion_time(step);
+                       if(step_time == time) {
+                               return attr_step;
+                       }
+
+                       /* Center step is stored in a separate attribute. */
+                       if(step != motion_steps / 2) {
+                               attr_step++;
+                       }
+               }
+       }
+
+       return -1;
+}
+
 bool Mesh::need_build_bvh() const
 {
        return !transform_applied || has_surface_bssrdf;
@@ -1445,11 +1473,11 @@ static void update_attribute_element_offset(Mesh *mesh,
                        Transform *tfm = mattr->data_transform();
                        offset = attr_float3_offset;
 
-                       assert(attr_float3.size() >= offset + size * 4);
-                       for(size_t k = 0; k < size*4; k++) {
+                       assert(attr_float3.size() >= offset + size * 3);
+                       for(size_t k = 0; k < size*3; k++) {
                                attr_float3[offset+k] = (&tfm->x)[k];
                        }
-                       attr_float3_offset += size * 4;
+                       attr_float3_offset += size * 3;
                }
                else {
                        float4 *data = mattr->data_float4();
@@ -1747,9 +1775,9 @@ void MeshManager::device_update_mesh(Device *,
                float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
 
                foreach(Mesh *mesh, scene->meshes) {
-                       mesh->pack_normals(scene,
-                                          &tri_shader[mesh->tri_offset],
-                                          &vnormal[mesh->vert_offset]);
+                       mesh->pack_shaders(scene,
+                                          &tri_shader[mesh->tri_offset]);
+                       mesh->pack_normals(&vnormal[mesh->vert_offset]);
                        mesh->pack_verts(tri_prim_index,
                                         &tri_vindex[mesh->tri_offset],
                                         &tri_patch[mesh->tri_offset],
@@ -2031,7 +2059,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 
        VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
 
-       /* Update normals. */
+       bool true_displacement_used = false;
+       size_t total_tess_needed = 0;
+
        foreach(Mesh *mesh, scene->meshes) {
                foreach(Shader *shader, mesh->used_shaders) {
                        if(shader->need_update_mesh)
@@ -2039,6 +2069,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
                }
 
                if(mesh->need_update) {
+                       /* Update normals. */
                        mesh->add_face_normals();
                        mesh->add_vertex_normals();
 
@@ -2046,57 +2077,53 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
                                mesh->add_undisplaced();
                        }
 
+                       /* Test if we need tesselation. */
+                       if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+                          mesh->num_subd_verts == 0 &&
+                          mesh->subd_params)
+                       {
+                               total_tess_needed++;
+                       }
+
+                       /* Test if we need displacement. */
+                       if(mesh->has_true_displacement()) {
+                               true_displacement_used = true;
+                       }
+
                        if(progress.get_cancel()) return;
                }
        }
 
        /* Tessellate meshes that are using subdivision */
-       size_t total_tess_needed = 0;
-       foreach(Mesh *mesh, scene->meshes) {
-               if(mesh->need_update &&
-                  mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
-                  mesh->num_subd_verts == 0 &&
-                  mesh->subd_params)
-               {
-                       total_tess_needed++;
-               }
-       }
+       if(total_tess_needed) {
+               size_t i = 0;
+               foreach(Mesh *mesh, scene->meshes) {
+                       if(mesh->need_update &&
+                          mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+                          mesh->num_subd_verts == 0 &&
+                          mesh->subd_params)
+                       {
+                               string msg = "Tessellating ";
+                               if(mesh->name == "")
+                                       msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
+                               else
+                                       msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
 
-       size_t i = 0;
-       foreach(Mesh *mesh, scene->meshes) {
-               if(mesh->need_update &&
-                  mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
-                  mesh->num_subd_verts == 0 &&
-                  mesh->subd_params)
-               {
-                       string msg = "Tessellating ";
-                       if(mesh->name == "")
-                               msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
-                       else
-                               msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
+                               progress.set_status("Updating Mesh", msg);
 
-                       progress.set_status("Updating Mesh", msg);
+                               DiagSplit dsplit(*mesh->subd_params);
+                               mesh->tessellate(&dsplit);
 
-                       DiagSplit dsplit(*mesh->subd_params);
-                       mesh->tessellate(&dsplit);
+                               i++;
 
-                       i++;
+                               if(progress.get_cancel()) return;
+                       }
 
-                       if(progress.get_cancel()) return;
                }
        }
 
        /* Update images needed for true displacement. */
-       bool true_displacement_used = false;
        bool old_need_object_flags_update = false;
-       foreach(Mesh *mesh, scene->meshes) {
-               if(mesh->need_update &&
-                  mesh->has_true_displacement())
-               {
-                       true_displacement_used = true;
-                       break;
-               }
-       }
        if(true_displacement_used) {
                VLOG(1) << "Updating images used for true displacement.";
                device_update_displacement_images(device, scene, progress);
@@ -2122,11 +2149,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 
        /* Update displacement. */
        bool displacement_done = false;
+       size_t num_bvh = 0;
+
        foreach(Mesh *mesh, scene->meshes) {
-               if(mesh->need_update &&
-                  displace(device, dscene, scene, mesh, progress))
-               {
-                       displacement_done = true;
+               if(mesh->need_update) {
+                       if(displace(device, dscene, scene, mesh, progress)) {
+                               displacement_done = true;
+                       }
+
+                       if(mesh->need_build_bvh()) {
+                               num_bvh++;
+                       }
                }
        }
 
@@ -2141,17 +2174,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
                if(progress.get_cancel()) return;
        }
 
-       /* Update bvh. */
-       size_t num_bvh = 0;
-       foreach(Mesh *mesh, scene->meshes) {
-               if(mesh->need_update && mesh->need_build_bvh()) {
-                       num_bvh++;
-               }
-       }
-
        TaskPool pool;
 
-       i = 0;
+       size_t i = 0;
        foreach(Mesh *mesh, scene->meshes) {
                if(mesh->need_update) {
                        pool.push(function_bind(&Mesh::compute_bvh,
index c0d1513bee0d740997e799e5f1ff0ea6f6552e2c..e370f8a2021fccb040f09c465b3872b033ab7c50 100644 (file)
@@ -279,7 +279,8 @@ public:
        void add_vertex_normals();
        void add_undisplaced();
 
-       void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
+       void pack_shaders(Scene *scene, uint *shader);
+       void pack_normals(float4 *vnormal);
        void pack_verts(const vector<uint>& tri_prim_index,
                        uint4 *tri_vindex,
                        uint *tri_patch,
@@ -304,6 +305,11 @@ public:
        bool has_motion_blur() const;
        bool has_true_displacement() const;
 
+       /* Convert between normalized -1..1 motion time and index
+        * in the VERTEX_MOTION attribute. */
+       float motion_time(int step) const;
+       int motion_step(float time) const;
+
        /* Check whether the mesh should have own BVH built separately. Briefly,
         * own BVH is needed for mesh, if:
         *
index f2347c7961094d331555bca7ce9f2b49f3c3b231..3571beb40d66df53b44e52f7e30d07b5f9d543ea 100644 (file)
@@ -152,22 +152,22 @@ public:
        void add_node_with_padding(int x, int y, int z);
 
        void create_mesh(vector<float3> &vertices,
-                                        vector<int> &indices,
-                                        vector<float3> &face_normals);
+                        vector<int> &indices,
+                        vector<float3> &face_normals);
 
 private:
        void generate_vertices_and_quads(vector<int3> &vertices_is,
-                                                                        vector<QuadData> &quads);
+                                        vector<QuadData> &quads);
 
        void deduplicate_vertices(vector<int3> &vertices,
-                                                         vector<QuadData> &quads);
+                                 vector<QuadData> &quads);
 
        void convert_object_space(const vector<int3> &vertices,
-                                                         vector<float3> &out_vertices);
+                                 vector<float3> &out_vertices);
 
        void convert_quads_to_tris(const vector<QuadData> &quads,
-                                                          vector<int> &tris,
-                                                          vector<float3> &face_normals);
+                                  vector<int> &tris,
+                                  vector<float3> &face_normals);
 };
 
 VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
@@ -224,8 +224,8 @@ void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z)
 }
 
 void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
-                                                                       vector<int> &indices,
-                                                                       vector<float3> &face_normals)
+                                    vector<int> &indices,
+                                    vector<float3> &face_normals)
 {
        /* We create vertices in index space (is), and only convert them to object
         * space when done. */
@@ -260,8 +260,8 @@ void VolumeMeshBuilder::generate_vertices_and_quads(
 
                                /* Compute min and max coords of the node in index space. */
                                int3 min = make_int3((x - pad_offset.x)*CUBE_SIZE,
-                                                                        (y - pad_offset.y)*CUBE_SIZE,
-                                                                        (z - pad_offset.z)*CUBE_SIZE);
+                                                    (y - pad_offset.y)*CUBE_SIZE,
+                                                    (z - pad_offset.z)*CUBE_SIZE);
 
                                /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
                                int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
@@ -316,7 +316,7 @@ void VolumeMeshBuilder::generate_vertices_and_quads(
 }
 
 void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
-                                                                                        vector<QuadData> &quads)
+                                             vector<QuadData> &quads)
 {
        vector<int3> sorted_vertices = vertices;
        std::sort(sorted_vertices.begin(), sorted_vertices.end());
@@ -355,7 +355,7 @@ void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
 }
 
 void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
-                                                                                        vector<float3> &out_vertices)
+                                                vector<float3> &out_vertices)
 {
        out_vertices.reserve(vertices.size());
 
@@ -369,8 +369,8 @@ void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
 }
 
 void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
-                                                                                         vector<int> &tris,
-                                                                                         vector<float3> &face_normals)
+                                              vector<int> &tris,
+                                              vector<float3> &face_normals)
 {
        int index_offset = 0;
        tris.resize(quads.size()*6);
@@ -399,8 +399,8 @@ struct VoxelAttributeGrid {
 };
 
 void MeshManager::create_volume_mesh(Scene *scene,
-                                                                        Mesh *mesh,
-                                                                        Progress& progress)
+                                     Mesh *mesh,
+                                     Progress& progress)
 {
        string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
        progress.set_status("Updating Mesh", msg);
@@ -470,8 +470,8 @@ void MeshManager::create_volume_mesh(Scene *scene,
        const int3 resolution = volume_params.resolution;
        float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
        float3 cell_size = make_float3(1.0f/resolution.x,
-                                                                  1.0f/resolution.y,
-                                                                  1.0f/resolution.z);
+                                      1.0f/resolution.y,
+                                      1.0f/resolution.z);
 
        if(attr) {
                const Transform *tfm = attr->data_transform();
@@ -575,12 +575,12 @@ void MeshManager::create_volume_mesh(Scene *scene,
 
        /* Print stats. */
        VLOG(1) << "Memory usage volume mesh: "
-                       << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
-                       << "Mb.";
+               << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
+               << "Mb.";
 
        VLOG(1) << "Memory usage volume grid: "
-                       << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
-                       << "Mb.";
+               << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
+               << "Mb.";
 }
 
 CCL_NAMESPACE_END
index 41c9730e6fb18092fe5dabebdebcd330020ce7ab..f117962a2ea5a8ba207f275f52ca2bf1bed031a3 100644 (file)
@@ -117,8 +117,7 @@ Transform TextureMapping::compute_transform()
                case NORMAL:
                        /* no translation for normals, and inverse transpose */
                        mat = rmat*smat;
-                       mat = transform_inverse(mat);
-                       mat = transform_transpose(mat);
+                       mat = transform_transposed_inverse(mat);
                        break;
        }
 
@@ -153,7 +152,6 @@ void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_ou
        compiler.add_node(tfm.x);
        compiler.add_node(tfm.y);
        compiler.add_node(tfm.z);
-       compiler.add_node(tfm.w);
 
        if(use_minmax) {
                compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
@@ -193,9 +191,7 @@ void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in,
 void TextureMapping::compile(OSLCompiler &compiler)
 {
        if(!skip()) {
-               Transform tfm = transform_transpose(compute_transform());
-
-               compiler.parameter("mapping", tfm);
+               compiler.parameter("mapping", compute_transform());
                compiler.parameter("use_mapping", 1);
        }
 }
@@ -1434,7 +1430,6 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
                                compiler.add_node(tfm.x);
                                compiler.add_node(tfm.y);
                                compiler.add_node(tfm.z);
-                               compiler.add_node(tfm.w);
                        }
                }
                else {
@@ -1478,7 +1473,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
                        compiler.parameter("filename", string_printf("@%d", slot).c_str());
                }
                if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
-                       compiler.parameter("mapping", transform_transpose(tfm));
+                       compiler.parameter("mapping", tfm);
                        compiler.parameter("use_mapping", 1);
                }
                compiler.parameter(this, "interpolation");
@@ -1558,8 +1553,7 @@ void MappingNode::compile(SVMCompiler& compiler)
 
 void MappingNode::compile(OSLCompiler& compiler)
 {
-       Transform tfm = transform_transpose(tex_mapping.compute_transform());
-       compiler.parameter("Matrix", tfm);
+       compiler.parameter("Matrix", tex_mapping.compute_transform());
        compiler.parameter_point("mapping_min", tex_mapping.min);
        compiler.parameter_point("mapping_max", tex_mapping.max);
        compiler.parameter("use_minmax", tex_mapping.use_minmax);
@@ -3220,7 +3214,6 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
                        compiler.add_node(ob_itfm.x);
                        compiler.add_node(ob_itfm.y);
                        compiler.add_node(ob_itfm.z);
-                       compiler.add_node(ob_itfm.w);
                }
        }
 
@@ -3259,7 +3252,7 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
        if(compiler.output_type() == SHADER_TYPE_VOLUME)
                compiler.parameter("is_volume", true);
        compiler.parameter(this, "use_transform");
-       Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
+       Transform ob_itfm = transform_transposed_inverse(ob_tfm);
        compiler.parameter("object_itfm", ob_itfm);
 
        compiler.parameter(this, "from_dupli");
index b981d2b88496682f3fc68b3cedfd61dd32f6c8a8..138de250c5f55a39305b3dd89723172ed575a61a 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
+/* Global state of object transform update. */
+
+struct UpdateObjectTransformState {
+       /* Global state used by device_update_object_transform().
+        * Common for both threaded and non-threaded update.
+        */
+
+       /* Type of the motion required by the scene settings. */
+       Scene::MotionType need_motion;
+
+       /* Mapping from particle system to a index in packed particle array.
+        * Only used for read.
+        */
+       map<ParticleSystem*, int> particle_offset;
+
+       /* Mesh area.
+        * Used to avoid calculation of mesh area multiple times. Used for both
+        * read and write. Acquire surface_area_lock to keep it all thread safe.
+        */
+       map<Mesh*, float> surface_area_map;
+
+       /* Motion offsets for each object. */
+       array<uint> motion_offset;
+
+       /* Packed object arrays. Those will be filled in. */
+       uint *object_flag;
+       KernelObject *objects;
+       Transform *object_motion_pass;
+       DecomposedTransform *object_motion;
+
+       /* Flags which will be synchronized to Integrator. */
+       bool have_motion;
+       bool have_curves;
+
+       /* ** Scheduling queue. ** */
+
+       Scene *scene;
+
+       /* Some locks to keep everything thread-safe. */
+       thread_spin_lock queue_lock;
+       thread_spin_lock surface_area_lock;
+
+       /* First unused object index in the queue. */
+       int queue_start_object;
+};
+
 /* Object */
 
 NODE_DEFINE(Object)
@@ -48,6 +94,7 @@ NODE_DEFINE(Object)
        SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
        SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
        SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
+       SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
 
        SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
 
@@ -60,45 +107,54 @@ Object::Object()
        particle_system = NULL;
        particle_index = 0;
        bounds = BoundBox::empty;
-       motion.pre = transform_empty();
-       motion.mid = transform_empty();
-       motion.post = transform_empty();
-       use_motion = false;
 }
 
 Object::~Object()
 {
 }
 
-void Object::compute_bounds(bool motion_blur)
+void Object::update_motion()
 {
-       BoundBox mbounds = mesh->bounds;
+       if(!use_motion()) {
+               return;
+       }
 
-       if(motion_blur && use_motion) {
-               MotionTransform mtfm = motion;
+       bool have_motion = false;
 
-               if(hide_on_missing_motion) {
-                       /* Hide objects that have no valid previous or next transform, for
-                        * example particle that stop existing. TODO: add support for this
-                        * case in the kernel so we don't get render artifacts. */
-                       if(mtfm.pre == transform_empty() ||
-                          mtfm.post == transform_empty()) {
-                               bounds = BoundBox::empty;
+       for(size_t i = 0; i < motion.size(); i++) {
+               if(motion[i] == transform_empty()) {
+                       if(hide_on_missing_motion) {
+                               /* Hide objects that have no valid previous or next
+                                * transform, for example particle that stop existing. It
+                                * would be better to handle this in the kernel and make
+                                * objects invisible outside certain motion steps. */
+                               tfm = transform_empty();
+                               motion.clear();
                                return;
                        }
+                       else {
+                               /* Otherwise just copy center motion. */
+                               motion[i] = tfm;
+                       }
                }
 
-               /* In case of missing motion information for previous/next frame,
-                * assume there is no motion. */
-               if(mtfm.pre == transform_empty()) {
-                       mtfm.pre = tfm;
-               }
-               if(mtfm.post == transform_empty()) {
-                       mtfm.post = tfm;
-               }
+               /* Test if any of the transforms are actually different. */
+               have_motion = have_motion || motion[i] != tfm;
+       }
 
-               MotionTransform decomp;
-               transform_motion_decompose(&decomp, &mtfm, &tfm);
+       /* Clear motion array if there is no actual motion. */
+       if(!have_motion) {
+               motion.clear();
+       }
+}
+
+void Object::compute_bounds(bool motion_blur)
+{
+       BoundBox mbounds = mesh->bounds;
+
+       if(motion_blur && use_motion()) {
+               array<DecomposedTransform> decomp(motion.size());
+               transform_motion_decompose(decomp.data(), motion.data(), motion.size());
 
                bounds = BoundBox::empty;
 
@@ -108,11 +164,12 @@ void Object::compute_bounds(bool motion_blur)
                for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
                        Transform ttfm;
 
-                       transform_motion_interpolate(&ttfm, &decomp, t);
+                       transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
                        bounds.grow(mbounds.transformed(&ttfm));
                }
        }
        else {
+               /* No motion blur case. */
                if(mesh->transform_applied) {
                        bounds = mbounds;
                }
@@ -132,7 +189,7 @@ void Object::apply_transform(bool apply_to_motion)
                /* store matrix to transform later. when accessing these as attributes we
                 * do not want the transform to be applied for consistency between static
                 * and dynamic BVH, so we do it on packing. */
-               mesh->transform_normal = transform_transpose(transform_inverse(tfm));
+               mesh->transform_normal = transform_transposed_inverse(tfm);
 
                /* apply to mesh vertices */
                for(size_t i = 0; i < mesh->verts.size(); i++)
@@ -232,27 +289,30 @@ void Object::tag_update(Scene *scene)
        scene->object_manager->need_update = true;
 }
 
-vector<float> Object::motion_times()
+bool Object::use_motion() const
 {
-       /* compute times at which we sample motion for this object */
-       vector<float> times;
-
-       if(!mesh || mesh->motion_steps == 1)
-               return times;
+       return (motion.size() > 1);
+}
 
-       int motion_steps = mesh->motion_steps;
+float Object::motion_time(int step) const
+{
+       return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
 
-       for(int step = 0; step < motion_steps; step++) {
-               if(step != motion_steps / 2) {
-                       float time = 2.0f * step / (motion_steps - 1) - 1.0f;
-                       times.push_back(time);
+int Object::motion_step(float time) const
+{
+       if(use_motion()) {
+               for(size_t step = 0; step < motion.size(); step++) {
+                       if(time == motion_time(step)) {
+                               return step;
+                       }
                }
        }
 
-       return times;
+       return -1;
 }
 
-bool Object::is_traceable()
+bool Object::is_traceable() const
 {
        /* Mesh itself can be empty,can skip all such objects. */
        if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
@@ -289,8 +349,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
                                                    Object *ob,
                                                    int object_index)
 {
-       float4 *objects = state->objects;
-       float4 *objects_vector = state->objects_vector;
+       KernelObject& kobject = state->objects[object_index];
+       Transform *object_motion_pass = state->object_motion_pass;
 
        Mesh *mesh = ob->mesh;
        uint flag = 0;
@@ -357,15 +417,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
                }
        }
 
-       /* Pack in texture. */
-       int offset = object_index*OBJECT_SIZE;
-
-       /* OBJECT_TRANSFORM */
-       memcpy(&objects[offset], &tfm, sizeof(float4)*3);
-       /* OBJECT_INVERSE_TRANSFORM */
-       memcpy(&objects[offset+4], &itfm, sizeof(float4)*3);
-       /* OBJECT_PROPERTIES */
-       objects[offset+12] = make_float4(surface_area, pass_id, random_number, __int_as_float(particle_index));
+       kobject.tfm = tfm;
+       kobject.itfm = itfm;
+       kobject.surface_area = surface_area;
+       kobject.pass_id = pass_id;
+       kobject.random_number = random_number;
+       kobject.particle_index = particle_index;
+       kobject.motion_offset = 0;
 
        if(mesh->use_motion_blur) {
                state->have_motion = true;
@@ -375,50 +433,56 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
        }
 
        if(state->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.
-                */
-               MotionTransform mtfm = ob->motion;
+               /* Clear motion array if there is no actual motion. */
+               ob->update_motion();
 
-               /* In case of missing motion information for previous/next frame,
-                * assume there is no motion. */
-               if(!ob->use_motion || mtfm.pre == transform_empty()) {
-                       mtfm.pre = ob->tfm;
+               /* Compute motion transforms. */
+               Transform tfm_pre, tfm_post;
+               if(ob->use_motion()) {
+                       tfm_pre = ob->motion[0];
+                       tfm_post = ob->motion[ob->motion.size() - 1];
                }
-               if(!ob->use_motion || mtfm.post == transform_empty()) {
-                       mtfm.post = ob->tfm;
+               else {
+                       tfm_pre = tfm;
+                       tfm_post = tfm;
                }
 
+               /* 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. */
                if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
-                       mtfm.pre = mtfm.pre * itfm;
-                       mtfm.post = mtfm.post * itfm;
+                       tfm_pre = tfm_pre * itfm;
+                       tfm_post = tfm_post * itfm;
                }
 
-               memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3);
-               memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3);
+               int motion_pass_offset = object_index*OBJECT_MOTION_PASS_SIZE;
+               object_motion_pass[motion_pass_offset + 0] = tfm_pre;
+               object_motion_pass[motion_pass_offset + 1] = tfm_post;
        }
        else if(state->need_motion == Scene::MOTION_BLUR) {
-               if(ob->use_motion) {
-                       /* decompose transformations for interpolation. */
-                       MotionTransform decomp;
+               if(ob->use_motion()) {
+                       kobject.motion_offset = state->motion_offset[object_index];
 
-                       transform_motion_decompose(&decomp, &ob->motion, &ob->tfm);
-                       memcpy(&objects[offset], &decomp, sizeof(float4)*12);
+                       /* Decompose transforms for interpolation. */
+                       DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
+                       transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
                        flag |= SD_OBJECT_MOTION;
                        state->have_motion = true;
                }
        }
 
        /* Dupli object coords and motion info. */
+       kobject.dupli_generated[0] = ob->dupli_generated[0];
+       kobject.dupli_generated[1] = ob->dupli_generated[1];
+       kobject.dupli_generated[2] = ob->dupli_generated[2];
+       kobject.numkeys = mesh->curve_keys.size();
+       kobject.dupli_uv[0] = ob->dupli_uv[0];
+       kobject.dupli_uv[1] = ob->dupli_uv[1];
        int totalsteps = mesh->motion_steps;
-       int numsteps = (totalsteps - 1)/2;
-       int numverts = mesh->verts.size();
-       int numkeys = mesh->curve_keys.size();
-
-       objects[offset+13] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], __int_as_float(numkeys));
-       objects[offset+14] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], __int_as_float(numsteps), __int_as_float(numverts));
-       objects[offset+15] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+       kobject.numsteps = (totalsteps - 1)/2;
+       kobject.numverts = mesh->verts.size();;
+       kobject.patch_map_offset = 0;
+       kobject.attribute_map_offset = 0;
 
        /* Object flag. */
        if(ob->use_holdout) {
@@ -475,7 +539,6 @@ void ObjectManager::device_update_object_transform_task(
 
 void ObjectManager::device_update_transforms(DeviceScene *dscene,
                                              Scene *scene,
-                                             uint *object_flag,
                                              Progress& progress)
 {
        UpdateObjectTransformState state;
@@ -485,13 +548,29 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
        state.scene = scene;
        state.queue_start_object = 0;
 
-       state.object_flag = object_flag;
-       state.objects = dscene->objects.alloc(OBJECT_SIZE*scene->objects.size());
+       state.objects = dscene->objects.alloc(scene->objects.size());
+       state.object_flag = dscene->object_flag.alloc(scene->objects.size());
+       state.object_motion = NULL;
+       state.object_motion_pass = NULL;
+
        if(state.need_motion == Scene::MOTION_PASS) {
-               state.objects_vector = dscene->objects_vector.alloc(OBJECT_VECTOR_SIZE*scene->objects.size());
+               state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size());
        }
-       else {
-               state.objects_vector = NULL;
+       else if(state.need_motion == Scene::MOTION_BLUR) {
+               /* Set object offsets into global object motion array. */
+               uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
+               uint motion_offset = 0;
+
+               foreach(Object *ob, scene->objects) {
+                       *motion_offsets = motion_offset;
+                       motion_offsets++;
+
+                       /* Clear motion array if there is no actual motion. */
+                       ob->update_motion();
+                       motion_offset += ob->motion.size();
+               }
+
+               state.object_motion = dscene->object_motion.alloc(motion_offset);
        }
 
        /* Particle system device offsets
@@ -534,7 +613,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
 
        dscene->objects.copy_to_device();
        if(state.need_motion == Scene::MOTION_PASS) {
-               dscene->objects_vector.copy_to_device();
+               dscene->object_motion_pass.copy_to_device();
+       }
+       else if(state.need_motion == Scene::MOTION_BLUR) {
+               dscene->object_motion.copy_to_device();
        }
 
        dscene->data.bvh.have_motion = state.have_motion;
@@ -554,12 +636,9 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
        if(scene->objects.size() == 0)
                return;
 
-       /* object info flag */
-       uint *object_flag = dscene->object_flag.alloc(scene->objects.size());
-
        /* set object transform matrices, before applying static transforms */
        progress.set_status("Updating Objects", "Copying Transformations to device");
-       device_update_transforms(dscene, scene, object_flag, progress);
+       device_update_transforms(dscene, scene, progress);
 
        if(progress.get_cancel()) return;
 
@@ -567,7 +646,7 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
        /* todo: do before to support getting object level coords? */
        if(scene->params.bvh_type == SceneParams::BVH_STATIC) {
                progress.set_status("Updating Objects", "Applying Static Transformations");
-               apply_static_transforms(dscene, scene, object_flag, progress);
+               apply_static_transforms(dscene, scene, progress);
        }
 }
 
@@ -586,9 +665,10 @@ void ObjectManager::device_update_flags(Device *,
        if(scene->objects.size() == 0)
                return;
 
-       /* object info flag */
+       /* Object info flag. */
        uint *object_flag = dscene->object_flag.data();
 
+       /* Object volume intersection. */
        vector<Object *> volume_objects;
        bool has_volume_objects = false;
        foreach(Object *object, scene->objects) {
@@ -642,7 +722,7 @@ void ObjectManager::device_update_flags(Device *,
                ++object_index;
        }
 
-       /* allocate object flag */
+       /* Copy object flag. */
        dscene->object_flag.copy_to_device();
 }
 
@@ -652,27 +732,26 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
                return;
        }
 
-       uint4* objects = (uint4*)dscene->objects.data();
+       KernelObject *kobjects = dscene->objects.data();
 
        bool update = false;
        int object_index = 0;
 
        foreach(Object *object, scene->objects) {
                Mesh* mesh = object->mesh;
-               int offset = object_index*OBJECT_SIZE + 15;
 
                if(mesh->patch_table) {
                        uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
                                                   mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
 
-                       if(objects[offset].x != patch_map_offset) {
-                               objects[offset].x = patch_map_offset;
+                       if(kobjects[object_index].patch_map_offset != patch_map_offset) {
+                               kobjects[object_index].patch_map_offset = patch_map_offset;
                                update = true;
                        }
                }
 
-               if(objects[offset].y != mesh->attr_map_offset) {
-                       objects[offset].y = mesh->attr_map_offset;
+               if(kobjects[object_index].attribute_map_offset != mesh->attr_map_offset) {
+                       kobjects[object_index].attribute_map_offset = mesh->attr_map_offset;
                        update = true;
                }
 
@@ -687,11 +766,12 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
 void ObjectManager::device_free(Device *, DeviceScene *dscene)
 {
        dscene->objects.free();
-       dscene->objects_vector.free();
+       dscene->object_motion_pass.free();
+       dscene->object_motion.free();
        dscene->object_flag.free();
 }
 
-void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress)
+void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress)
 {
        /* todo: normals and displacement should be done before applying transform! */
        /* todo: create objects/meshes in right order! */
@@ -715,6 +795,8 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
 
        if(progress.get_cancel()) return;
 
+       uint *object_flag = dscene->object_flag.data();
+
        /* apply transforms for objects with single user meshes */
        foreach(Object *object, scene->objects) {
                /* Annoying feedback loop here: we can't use is_instanced() because
@@ -725,7 +807,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
                if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
                   !object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
                {
-                       if(!(motion_blur && object->use_motion)) {
+                       if(!(motion_blur && object->use_motion())) {
                                if(!object->mesh->transform_applied) {
                                        object->apply_transform(apply_to_motion);
                                        object->mesh->transform_applied = true;
index acdb1b641238441ed4c2b7b03bf81a74129d1282..c7212ae25f915baefc538af9760b1f887ce084cf 100644 (file)
@@ -35,6 +35,7 @@ class ParticleSystem;
 class Progress;
 class Scene;
 struct Transform;
+struct UpdateObjectTransformState;
 
 /* Object */
 
@@ -49,8 +50,7 @@ public:
        int pass_id;
        vector<ParamValue> attributes;
        uint visibility;
-       MotionTransform motion;
-       bool use_motion;
+       array<Transform> motion;
        bool hide_on_missing_motion;
        bool use_holdout;
        bool is_shadow_catcher;
@@ -69,12 +69,17 @@ public:
        void compute_bounds(bool motion_blur);
        void apply_transform(bool apply_to_motion);
 
-       vector<float> motion_times();
+       /* Convert between normalized -1..1 motion time and index
+        * in the motion array. */
+       bool use_motion() const;
+       float motion_time(int step) const;
+       int motion_step(float time) const;
+       void update_motion();
 
        /* Check whether object is traceable and it worth adding it to
         * kernel scene.
         */
-       bool is_traceable();
+       bool is_traceable() const;
 
        /* Combine object's visibility with all possible internal run-time
         * determined flags which denotes trace-time visibility.
@@ -95,7 +100,6 @@ public:
        void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
        void device_update_transforms(DeviceScene *dscene,
                                      Scene *scene,
-                                     uint *object_flag,
                                      Progress& progress);
 
        void device_update_flags(Device *device,
@@ -109,49 +113,9 @@ public:
 
        void tag_update(Scene *scene);
 
-       void apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
+       void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress);
 
 protected:
-       /* Global state of object transform update. */
-       struct UpdateObjectTransformState {
-               /* Global state used by device_update_object_transform().
-                * Common for both threaded and non-threaded update.
-                */
-
-               /* Type of the motion required by the scene settings. */
-               Scene::MotionType need_motion;
-
-               /* Mapping from particle system to a index in packed particle array.
-                * Only used for read.
-                */
-               map<ParticleSystem*, int> particle_offset;
-
-               /* Mesh area.
-                * Used to avoid calculation of mesh area multiple times. Used for both
-                * read and write. Acquire surface_area_lock to keep it all thread safe.
-                */
-               map<Mesh*, float> surface_area_map;
-
-               /* Packed object arrays. Those will be filled in. */
-               uint *object_flag;
-               float4 *objects;
-               float4 *objects_vector;
-
-               /* Flags which will be synchronized to Integrator. */
-               bool have_motion;
-               bool have_curves;
-
-               /* ** Scheduling queue. ** */
-
-               Scene *scene;
-
-               /* Some locks to keep everything thread-safe. */
-               thread_spin_lock queue_lock;
-               thread_spin_lock surface_area_lock;
-
-               /* First unused object index in the queue. */
-               int queue_start_object;
-       };
        void device_update_object_transform(UpdateObjectTransformState *state,
                                            Object *ob,
                                            const int object_index);
index 9e931280691d79a25f19617f93b6df7bdca9d86c..f1a22350060b547735508edf0e4a552d508bbf86 100644 (file)
@@ -34,6 +34,7 @@
 #include "util/util_md5.h"
 #include "util/util_path.h"
 #include "util/util_progress.h"
+#include "util/util_projection.h"
 
 #endif
 
@@ -832,7 +833,9 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
                case SocketType::TRANSFORM:
                {
                        Transform value = node->get_transform(socket);
-                       ss->Parameter(uname, TypeDesc::TypeMatrix, &value);
+                       ProjectionTransform projection(value);
+                       projection = projection_transpose(projection);
+                       ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
                        break;
                }
                case SocketType::BOOLEAN_ARRAY:
@@ -900,7 +903,11 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
                case SocketType::TRANSFORM_ARRAY:
                {
                        const array<Transform>& value = node->get_transform_array(socket);
-                       ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data());
+                       array<ProjectionTransform> fvalue(value.size());
+                       for(size_t i = 0; i < value.size(); i++) {
+                               fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
+                       }
+                       ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
                        break;
                }
                case SocketType::CLOSURE:
@@ -967,7 +974,9 @@ void OSLCompiler::parameter(const char *name, ustring s)
 void OSLCompiler::parameter(const char *name, const Transform& tfm)
 {
        OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
-       ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&tfm);
+       ProjectionTransform projection(tfm);
+       projection = projection_transpose(projection);
+       ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&projection);
 }
 
 void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
index 3ee620c9d0120672c8626edf04138a2ef4cb5857..e4be3306d7e472dd32130791807a4ab37d3bb798 100644 (file)
@@ -62,14 +62,10 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
        for(size_t j = 0; j < scene->particle_systems.size(); j++)
                num_particles += scene->particle_systems[j]->particles.size();
        
-       float4 *particles = dscene->particles.alloc(PARTICLE_SIZE*num_particles);
+       KernelParticle *kparticles = dscene->particles.alloc(num_particles);
        
        /* dummy particle */
-       particles[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-       particles[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-       particles[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-       particles[3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-       particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+       memset(kparticles, 0, sizeof(KernelParticle));
        
        int i = 1;
        for(size_t j = 0; j < scene->particle_systems.size(); j++) {
@@ -78,13 +74,15 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
                for(size_t k = 0; k < psys->particles.size(); k++) {
                        /* pack in texture */
                        Particle& pa = psys->particles[k];
-                       int offset = i*PARTICLE_SIZE;
                        
-                       particles[offset] = make_float4(__uint_as_float(pa.index), pa.age, pa.lifetime, pa.size);
-                       particles[offset+1] = pa.rotation;
-                       particles[offset+2] = make_float4(pa.location.x, pa.location.y, pa.location.z, pa.velocity.x);
-                       particles[offset+3] = make_float4(pa.velocity.y, pa.velocity.z, pa.angular_velocity.x, pa.angular_velocity.y);
-                       particles[offset+4] = make_float4(pa.angular_velocity.z, 0.0f, 0.0f, 0.0f);
+                       kparticles[i].index = pa.index;
+                       kparticles[i].age = pa.age;
+                       kparticles[i].lifetime = pa.lifetime;
+                       kparticles[i].size = pa.size;
+                       kparticles[i].rotation = pa.rotation;
+                       kparticles[i].location = float3_to_float4(pa.location);
+                       kparticles[i].velocity = float3_to_float4(pa.velocity);
+                       kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity);
                        
                        i++;
                        
index 24923b650e374db454a33cfe8c69ede9d33c3aa3..ba47e3ab6f81dfa9eb65799ee9767d58724ff2ce 100644 (file)
@@ -60,19 +60,21 @@ DeviceScene::DeviceScene(Device *device)
   curve_keys(device, "__curve_keys", MEM_TEXTURE),
   patches(device, "__patches", MEM_TEXTURE),
   objects(device, "__objects", MEM_TEXTURE),
-  objects_vector(device, "__objects_vector", MEM_TEXTURE),
+  object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE),
+  object_motion(device, "__object_motion", MEM_TEXTURE),
+  object_flag(device, "__object_flag", MEM_TEXTURE),
+  camera_motion(device, "__camera_motion", MEM_TEXTURE),
   attributes_map(device, "__attributes_map", MEM_TEXTURE),
   attributes_float(device, "__attributes_float", MEM_TEXTURE),
   attributes_float3(device, "__attributes_float3", MEM_TEXTURE),
   attributes_uchar4(device, "__attributes_uchar4", MEM_TEXTURE),
   light_distribution(device, "__light_distribution", MEM_TEXTURE),
-  light_data(device, "__light_data", MEM_TEXTURE),
+  lights(device, "__lights", MEM_TEXTURE),
   light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_TEXTURE),
   light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_TEXTURE),
   particles(device, "__particles", MEM_TEXTURE),
   svm_nodes(device, "__svm_nodes", MEM_TEXTURE),
-  shader_flag(device, "__shader_flag", MEM_TEXTURE),
-  object_flag(device, "__object_flag", MEM_TEXTURE),
+  shaders(device, "__shaders", MEM_TEXTURE),
   lookup_table(device, "__lookup_table", MEM_TEXTURE),
   sobol_directions(device, "__sobol_directions", MEM_TEXTURE)
 {
index ea9485ff23064fd73660378117f654d2be98d5e7..04bd4735a86b8251ad8830fb47c7cacdd7b2cea6 100644 (file)
@@ -86,8 +86,13 @@ public:
        device_vector<uint> patches;
 
        /* objects */
-       device_vector<float4> objects;
-       device_vector<float4> objects_vector;
+       device_vector<KernelObject> objects;
+       device_vector<Transform> object_motion_pass;
+       device_vector<DecomposedTransform> object_motion;
+       device_vector<uint> object_flag;
+
+       /* cameras */
+       device_vector<DecomposedTransform> camera_motion;
 
        /* attributes */
        device_vector<uint4> attributes_map;
@@ -96,18 +101,17 @@ public:
        device_vector<uchar4> attributes_uchar4;
 
        /* lights */
-       device_vector<float4> light_distribution;
-       device_vector<float4> light_data;
+       device_vector<KernelLightDistribution> light_distribution;
+       device_vector<KernelLight> lights;
        device_vector<float2> light_background_marginal_cdf;
        device_vector<float2> light_background_conditional_cdf;
 
        /* particles */
-       device_vector<float4> particles;
+       device_vector<KernelParticle> particles;
 
        /* shaders */
        device_vector<int4> svm_nodes;
-       device_vector<uint> shader_flag;
-       device_vector<uint> object_flag;
+       device_vector<KernelShader> shaders;
 
        /* lookup tables */
        device_vector<float> lookup_table;
index e8d9558c38df25c61b12ab394b1de50161840464..4115603855840dbf5d4af04bec7dcf7410393538 100644 (file)
@@ -656,13 +656,13 @@ DeviceRequestedFeatures Session::get_requested_device_features()
         */
        requested_features.use_hair = false;
        requested_features.use_object_motion = false;
-       requested_features.use_camera_motion = scene->camera->use_motion;
+       requested_features.use_camera_motion = scene->camera->use_motion();
        foreach(Object *object, scene->objects) {
                Mesh *mesh = object->mesh;
                if(mesh->num_curves()) {
                        requested_features.use_hair = true;
                }
-               requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
+               requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur;
                requested_features.use_camera_motion |= mesh->use_motion_blur;
 #ifdef WITH_OPENSUBDIV
                if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
index 578c61a3e7958f6b761e473620fd077fa7d8479d..ec52c51e337f16112f37040541685542b15d0aae 100644 (file)
@@ -432,14 +432,12 @@ void ShaderManager::device_update_common(Device *device,
                                          Scene *scene,
                                          Progress& /*progress*/)
 {
-       dscene->shader_flag.free();
+       dscene->shaders.free();
 
        if(scene->shaders.size() == 0)
                return;
 
-       uint shader_flag_size = scene->shaders.size()*SHADER_SIZE;
-       uint *shader_flag = dscene->shader_flag.alloc(shader_flag_size);
-       uint i = 0;
+       KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
        bool has_volumes = false;
        bool has_transparent_shadow = false;
 
@@ -487,16 +485,17 @@ void ShaderManager::device_update_common(Device *device,
                        flag |= SD_HAS_CONSTANT_EMISSION;
 
                /* regular shader */
-               shader_flag[i++] = flag;
-               shader_flag[i++] = shader->pass_id;
-               shader_flag[i++] = __float_as_int(constant_emission.x);
-               shader_flag[i++] = __float_as_int(constant_emission.y);
-               shader_flag[i++] = __float_as_int(constant_emission.z);
+               kshader->flags = flag;
+               kshader->pass_id = shader->pass_id;
+               kshader->constant_emission[0] = constant_emission.x;
+               kshader->constant_emission[1] = constant_emission.y;
+               kshader->constant_emission[2] = constant_emission.z;
+               kshader++;
 
                has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
        }
 
-       dscene->shader_flag.copy_to_device();
+       dscene->shaders.copy_to_device();
 
        /* lookup tables */
        KernelTables *ktables = &dscene->data.tables;
@@ -525,7 +524,7 @@ void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *sce
 {
        scene->lookup_tables->remove_table(&beckmann_table_offset);
 
-       dscene->shader_flag.free();
+       dscene->shaders.free();
 }
 
 void ShaderManager::add_default(Scene *scene)
index 66c4f22a7e2fcaf5b44174a7368405307d967f8f..24043e2231bc6c121c55126da62d6d3549c45bc9 100644 (file)
@@ -67,6 +67,7 @@ set(SRC_HEADERS
        util_param.h
        util_path.h
        util_progress.h
+       util_projection.h
        util_queue.h
        util_rect.h
        util_set.h
diff --git a/intern/cycles/util/util_projection.h b/intern/cycles/util/util_projection.h
new file mode 100644 (file)
index 0000000..dbcb987
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PROJECTION_H__
+#define __UTIL_PROJECTION_H__
+
+#include "util/util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* 4x4 projection matrix, perspective or orthographic. */
+
+typedef struct ProjectionTransform {
+       float4 x, y, z, w; /* rows */
+
+#ifndef __KERNEL_GPU__
+       ProjectionTransform()
+       {
+       }
+
+       explicit ProjectionTransform(const Transform& tfm)
+       : x(tfm.x),
+         y(tfm.y),
+         z(tfm.z),
+         w(make_float4(0.0f, 0.0f, 0.0f, 1.0f))
+       {
+       }
+#endif
+} ProjectionTransform;
+
+typedef struct PerspectiveMotionTransform {
+       ProjectionTransform pre;
+       ProjectionTransform post;
+} PerspectiveMotionTransform;
+
+/* Functions */
+
+ccl_device_inline float3 transform_perspective(const ProjectionTransform *t, const float3 a)
+{
+       float4 b = make_float4(a.x, a.y, a.z, 1.0f);
+       float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
+       float w = dot(t->w, b);
+
+       return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device_inline float3 transform_perspective_direction(const ProjectionTransform *t, const float3 a)
+{
+       float3 c = make_float3(
+               a.x*t->x.x + a.y*t->x.y + a.z*t->x.z,
+               a.x*t->y.x + a.y*t->y.y + a.z*t->y.z,
+               a.x*t->z.x + a.y*t->z.y + a.z*t->z.z);
+
+       return c;
+}
+
+#ifndef __KERNEL_GPU__
+
+ccl_device_inline Transform projection_to_transform(const ProjectionTransform& a)
+{
+       Transform tfm = {a.x, a.y, a.z};
+       return tfm;
+}
+
+ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform& a)
+{
+       ProjectionTransform t;
+
+       t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
+       t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
+       t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
+       t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
+
+       return t;
+}
+
+ProjectionTransform projection_inverse(const ProjectionTransform& a);
+
+ccl_device_inline ProjectionTransform make_projection(
+       float a, float b, float c, float d,
+       float e, float f, float g, float h,
+       float i, float j, float k, float l,
+       float m, float n, float o, float p)
+{
+       ProjectionTransform t;
+
+       t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
+       t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
+       t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
+       t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
+
+       return t;
+}
+ccl_device_inline ProjectionTransform projection_identity()
+{
+       return make_projection(
+               1.0f, 0.0f, 0.0f, 0.0f,
+               0.0f, 1.0f, 0.0f, 0.0f,
+               0.0f, 0.0f, 1.0f, 0.0f,
+               0.0f, 0.0f, 0.0f, 1.0f);
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const ProjectionTransform& b)
+{
+       ProjectionTransform c = projection_transpose(b);
+       ProjectionTransform t;
+
+       t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
+       t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
+       t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
+       t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+
+       return t;
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const Transform& b)
+{
+       return a * ProjectionTransform(b);
+}
+
+ccl_device_inline ProjectionTransform operator*(const Transform& a, const ProjectionTransform& b)
+{
+       return ProjectionTransform(a) * b;
+}
+
+ccl_device_inline void print_projection(const char *label, const ProjectionTransform& t)
+{
+       print_float4(label, t.x);
+       print_float4(label, t.y);
+       print_float4(label, t.z);
+       print_float4(label, t.w);
+       printf("\n");
+}
+
+ccl_device_inline ProjectionTransform projection_perspective(float fov, float n, float f)
+{
+       ProjectionTransform persp = make_projection(
+               1, 0, 0, 0,
+               0, 1, 0, 0,
+               0, 0, f / (f - n), -f*n / (f - n),
+               0, 0, 1, 0);
+
+       float inv_angle = 1.0f/tanf(0.5f*fov);
+
+       Transform scale = transform_scale(inv_angle, inv_angle, 1);
+
+       return scale * persp;
+}
+
+ccl_device_inline ProjectionTransform projection_orthographic(float znear, float zfar)
+{
+       Transform t =
+               transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
+               transform_translate(0.0f, 0.0f, -znear);
+
+       return ProjectionTransform(t);
+}
+
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_PROJECTION_H__ */
+
index c127054533999a4b3585a9ca7d5e156002d778bc..206c3da23ebd013c236ffbef14fc7458b283d037 100644 (file)
@@ -46,6 +46,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "util/util_projection.h"
 #include "util/util_transform.h"
 
 #include "util/util_boundbox.h"
@@ -129,9 +130,9 @@ static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
        return true;
 }
 
-Transform transform_inverse(const Transform& tfm)
+ProjectionTransform projection_inverse(const ProjectionTransform& tfm)
 {
-       Transform tfmR = transform_identity();
+       ProjectionTransform tfmR = projection_identity();
        float M[4][4], R[4][4];
 
        memcpy(R, &tfmR, sizeof(R));
@@ -145,7 +146,7 @@ Transform transform_inverse(const Transform& tfm)
                M[2][2] += 1e-8f;
 
                if(UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
-                       return transform_identity();
+                       return projection_identity();
                }
        }
 
@@ -154,6 +155,19 @@ Transform transform_inverse(const Transform& tfm)
        return tfmR;
 }
 
+Transform transform_inverse(const Transform& tfm)
+{
+       ProjectionTransform projection(tfm);
+       return projection_to_transform(projection_inverse(projection));
+}
+
+Transform transform_transposed_inverse(const Transform& tfm)
+{
+       ProjectionTransform projection(tfm);
+       ProjectionTransform iprojection = projection_inverse(projection);
+       return projection_to_transform(projection_transpose(iprojection));
+}
+
 /* Motion Transform */
 
 float4 transform_to_quat(const Transform& tfm)
@@ -202,14 +216,14 @@ float4 transform_to_quat(const Transform& tfm)
        return qt;
 }
 
-static void transform_decompose(Transform *decomp, const Transform *tfm)
+static void transform_decompose(DecomposedTransform *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;
+       M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f;
 
        Transform R = M;
        float norm;
@@ -217,9 +231,9 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
 
        do {
                Transform Rnext;
-               Transform Rit = transform_inverse(transform_transpose(R));
+               Transform Rit = transform_transposed_inverse(R);
 
-               for(int i = 0; i < 4; i++)
+               for(int i = 0; i < 3; i++)
                        for(int j = 0; j < 4; j++)
                                Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
                
@@ -247,18 +261,18 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
        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, const Transform *mid)
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
 {
-       transform_decompose(&decomp->pre, &motion->pre);
-       transform_decompose(&decomp->mid, mid);
-       transform_decompose(&decomp->post, &motion->post);
-
-       /* ensure rotation around shortest angle, negated quaternions are the same
-        * but this means we don't have to do the check in quat_interpolate */
-       if(dot(decomp->pre.x, decomp->mid.x) < 0.0f)
-               decomp->pre.x = -decomp->pre.x;
-       if(dot(decomp->mid.x, decomp->post.x) < 0.0f)
-               decomp->mid.x = -decomp->mid.x;
+       for(size_t i = 0; i < size; i++) {
+               transform_decompose(decomp + i, motion + i);
+
+               if(i > 0) {
+                       /* Ensure rotation around shortest angle, negated quaternions are the same
+                        * but this means we don't have to do the check in quat_interpolate */
+                       if(dot(decomp[i-1].x, decomp[i].x) < 0.0f)
+                               decomp[i-1].x = -decomp[i-1].x;
+               }
+       }
 }
 
 Transform transform_from_viewplane(BoundBox2D& viewplane)
index ac0804a722722831cbf720a20075e88ca55cb159..987f4dac77792e862a7f718bce75ec4e90828d7b 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
-/* Data Types */
+/* Affine transformation, stored as 4x3 matrix. */
 
 typedef struct Transform {
-       float4 x, y, z, w; /* rows */
+       float4 x, y, z;
 
 #ifndef __KERNEL_GPU__
        float4 operator[](int i) const { return *(&x + i); }
@@ -37,32 +37,16 @@ typedef struct Transform {
 #endif
 } Transform;
 
-/* transform decomposed in rotation/translation/scale. we use the same data
+/* 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). */
 
-typedef struct ccl_may_alias MotionTransform {
-       Transform pre;
-       Transform mid;
-       Transform post;
-} MotionTransform;
-
-typedef struct PerspectiveMotionTransform {
-       Transform pre;
-       Transform post;
-} PerspectiveMotionTransform;
+typedef struct DecomposedTransform {
+       float4 x, y, z, w;
+} DecomposedTransform;
 
 /* Functions */
 
-ccl_device_inline float3 transform_perspective(const Transform *t, const float3 a)
-{
-       float4 b = make_float4(a.x, a.y, a.z, 1.0f);
-       float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
-       float w = dot(t->w, b);
-
-       return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
-}
-
 ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
 {
        /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
@@ -73,7 +57,7 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
        x = _mm_loadu_ps(&t->x.x);
        y = _mm_loadu_ps(&t->y.x);
        z = _mm_loadu_ps(&t->z.x);
-       w = _mm_loadu_ps(&t->w.x);
+       w = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
 
        _MM_TRANSPOSE4_PS(x, y, z, w);
 
@@ -129,29 +113,15 @@ ccl_device_inline float3 transform_direction_transposed(const Transform *t, cons
        return make_float3(dot(x, a), dot(y, a), dot(z, a));
 }
 
-ccl_device_inline Transform transform_transpose(const Transform a)
-{
-       Transform t;
-
-       t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
-       t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
-       t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
-       t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
-
-       return t;
-}
-
 ccl_device_inline Transform make_transform(float a, float b, float c, float d,
                                            float e, float f, float g, float h,
-                                           float i, float j, float k, float l,
-                                           float m, float n, float o, float p)
+                                           float i, float j, float k, float l)
 {
        Transform t;
 
        t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
        t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
        t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
-       t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
 
        return t;
 }
@@ -165,21 +135,22 @@ ccl_device_inline Transform make_transform_frame(float3 N)
        const float3 dy = normalize(cross(N, dx));
        return make_transform(dx.x, dx.y, dx.z, 0.0f,
                              dy.x, dy.y, dy.z, 0.0f,
-                             N.x , N.y,  N.z,  0.0f,
-                             0.0f, 0.0f, 0.0f, 1.0f);
+                             N.x , N.y,  N.z,  0.0f);
 }
 
 #ifndef __KERNEL_GPU__
 
 ccl_device_inline Transform operator*(const Transform a, const Transform b)
 {
-       Transform c = transform_transpose(b);
-       Transform t;
+       float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
+       float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
+       float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
+       float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
 
-       t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
-       t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
-       t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
-       t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+       Transform t;
+       t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
+       t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
+       t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
 
        return t;
 }
@@ -189,7 +160,6 @@ ccl_device_inline void print_transform(const char *label, const Transform& t)
        print_float4(label, t.x);
        print_float4(label, t.y);
        print_float4(label, t.z);
-       print_float4(label, t.w);
        printf("\n");
 }
 
@@ -198,8 +168,7 @@ ccl_device_inline Transform transform_translate(float3 t)
        return make_transform(
                1, 0, 0, t.x,
                0, 1, 0, t.y,
-               0, 0, 1, t.z,
-               0, 0, 0, 1);
+               0, 0, 1, t.z);
 }
 
 ccl_device_inline Transform transform_translate(float x, float y, float z)
@@ -212,8 +181,7 @@ ccl_device_inline Transform transform_scale(float3 s)
        return make_transform(
                s.x, 0, 0, 0,
                0, s.y, 0, 0,
-               0, 0, s.z, 0,
-               0, 0, 0, 1);
+               0, 0, s.z, 0);
 }
 
 ccl_device_inline Transform transform_scale(float x, float y, float z)
@@ -221,21 +189,6 @@ ccl_device_inline Transform transform_scale(float x, float y, float z)
        return transform_scale(make_float3(x, y, z));
 }
 
-ccl_device_inline Transform transform_perspective(float fov, float n, float f)
-{
-       Transform persp = make_transform(
-               1, 0, 0, 0,
-               0, 1, 0, 0,
-               0, 0, f / (f - n), -f*n / (f - n),
-               0, 0, 1, 0);
-
-       float inv_angle = 1.0f/tanf(0.5f*fov);
-
-       Transform scale = transform_scale(inv_angle, inv_angle, 1);
-
-       return scale * persp;
-}
-
 ccl_device_inline Transform transform_rotate(float angle, float3 axis)
 {
        float s = sinf(angle);
@@ -258,9 +211,7 @@ ccl_device_inline Transform transform_rotate(float angle, float3 axis)
                axis.z*axis.x*t - s*axis.y,
                axis.z*axis.y*t + s*axis.x,
                axis.z*axis.z*t + c,
-               0.0f,
-
-               0.0f, 0.0f, 0.0f, 1.0f);
+               0.0f);
 }
 
 /* Euler is assumed to be in XYZ order. */
@@ -272,12 +223,6 @@ ccl_device_inline Transform transform_euler(float3 euler)
                transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
 }
 
-ccl_device_inline Transform transform_orthographic(float znear, float zfar)
-{
-       return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
-               transform_translate(0.0f, 0.0f, -znear);
-}
-
 ccl_device_inline Transform transform_identity()
 {
        return transform_scale(1.0f, 1.0f, 1.0f);
@@ -306,20 +251,20 @@ ccl_device_inline void transform_set_column(Transform *t, int column, float3 val
 }
 
 Transform transform_inverse(const Transform& a);
+Transform transform_transposed_inverse(const Transform& a);
 
 ccl_device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
 {
        /* the epsilon here is quite arbitrary, but this function is only used for
-        * surface area and bump, where we except it to not be so sensitive */
-       Transform ttfm = transform_transpose(tfm);
+        * surface area and bump, where we expect it to not be so sensitive */
        float eps = 1e-6f;
        
        float sx = len_squared(float4_to_float3(tfm.x));
        float sy = len_squared(float4_to_float3(tfm.y));
        float sz = len_squared(float4_to_float3(tfm.z));
-       float stx = len_squared(float4_to_float3(ttfm.x));
-       float sty = len_squared(float4_to_float3(ttfm.y));
-       float stz = len_squared(float4_to_float3(ttfm.z));
+       float stx = len_squared(transform_get_column(&tfm, 0));
+       float sty = len_squared(transform_get_column(&tfm, 1));
+       float stz = len_squared(transform_get_column(&tfm, 2));
 
        if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
           fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
@@ -355,7 +300,6 @@ ccl_device_inline Transform transform_clear_scale(const Transform& tfm)
 ccl_device_inline Transform transform_empty()
 {
        return make_transform(
-               0, 0, 0, 0,
                0, 0, 0, 0,
                0, 0, 0, 0,
                0, 0, 0, 0);
@@ -414,12 +358,11 @@ ccl_device_inline Transform transform_quick_inverse(Transform M)
        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;
 }
 
-ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp)
+ccl_device_inline void transform_compose(Transform *tfm, const DecomposedTransform *decomp)
 {
        /* rotation */
        float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
@@ -452,60 +395,30 @@ ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp
        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);
 }
 
-/* Disabled for now, need arc-length parametrization for constant speed motion.
- * #define CURVED_MOTION_INTERPOLATE */
-
-ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t)
+/* Interpolate from array of decomposed transforms. */
+ccl_device void transform_motion_array_interpolate(Transform *tfm,
+                                                   const ccl_global DecomposedTransform *motion,
+                                                   uint numsteps,
+                                                   float time)
 {
-       /* possible optimization: is it worth it adding a check to skip scaling?
-        * it's probably quite uncommon to have scaling objects. or can we skip
-        * just shearing perhaps? */
-       Transform decomp;
-
-#ifdef CURVED_MOTION_INTERPOLATE
-       /* 3 point bezier curve interpolation for position */
-       float3 Ppre = float4_to_float3(motion->pre.y);
-       float3 Pmid = float4_to_float3(motion->mid.y);
-       float3 Ppost = float4_to_float3(motion->post.y);
-
-       float3 Pcontrol = 2.0f*Pmid - 0.5f*(Ppre + Ppost);
-       float3 P = Ppre*t*t + Pcontrol*2.0f*t*(1.0f - t) + Ppost*(1.0f - t)*(1.0f - t);
-
-       decomp.y.x = P.x;
-       decomp.y.y = P.y;
-       decomp.y.z = P.z;
-#endif
-
-       /* linear interpolation for rotation and scale */
-       if(t < 0.5f) {
-               t *= 2.0f;
-
-               decomp.x = quat_interpolate(motion->pre.x, motion->mid.x, t);
-#ifdef CURVED_MOTION_INTERPOLATE
-               decomp.y.w = (1.0f - t)*motion->pre.y.w + t*motion->mid.y.w;
-#else
-               decomp.y = (1.0f - t)*motion->pre.y + t*motion->mid.y;
-#endif
-               decomp.z = (1.0f - t)*motion->pre.z + t*motion->mid.z;
-               decomp.w = (1.0f - t)*motion->pre.w + t*motion->mid.w;
-       }
-       else {
-               t = (t - 0.5f)*2.0f;
-
-               decomp.x = quat_interpolate(motion->mid.x, motion->post.x, t);
-#ifdef CURVED_MOTION_INTERPOLATE
-               decomp.y.w = (1.0f - t)*motion->mid.y.w + t*motion->post.y.w;
-#else
-               decomp.y = (1.0f - t)*motion->mid.y + t*motion->post.y;
-#endif
-               decomp.z = (1.0f - t)*motion->mid.z + t*motion->post.z;
-               decomp.w = (1.0f - t)*motion->mid.w + t*motion->post.w;
-       }
-
-       /* compose rotation, translation, scale into matrix */
+       /* Figure out which steps we need to interpolate. */
+       int maxstep = numsteps-1;
+       int step = min((int)(time*maxstep), maxstep-1);
+       float t = time*maxstep - step;
+
+       const ccl_global DecomposedTransform *a = motion + step;
+       const ccl_global DecomposedTransform *b = motion + step + 1;
+
+       /* Interpolate rotation, translation and scale. */
+       DecomposedTransform decomp;
+       decomp.x = quat_interpolate(a->x, b->x, t);
+       decomp.y = (1.0f - t)*a->y + t*b->y;
+       decomp.z = (1.0f - t)*a->z + t*b->z;
+       decomp.w = (1.0f - t)*a->w + t*b->w;
+
+       /* Compose rotation, translation, scale into matrix. */
        transform_compose(tfm, &decomp);
 }
 
@@ -513,13 +426,13 @@ ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransfo
 
 class BoundBox2D;
 
-ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransform& B)
+ccl_device_inline bool operator==(const DecomposedTransform& A, const DecomposedTransform& B)
 {
-       return (A.pre == B.pre && A.post == B.post);
+       return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
 }
 
 float4 transform_to_quat(const Transform& tfm);
-void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid);
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
 Transform transform_from_viewplane(BoundBox2D& viewplane);
 
 #endif
index 625c19c7c46422c156daddc8e7861058e3fd2cc8..e98e4e3418141a287995a1a8f0e2cc018b19ab1d 100644 (file)
@@ -215,6 +215,18 @@ public:
                return data_;
        }
 
+       T* resize(size_t newsize, const T& value)
+       {
+               size_t oldsize = size();
+               resize(newsize);
+
+               for(size_t i = oldsize; i < size(); i++) {
+                       data_[i] = value;
+               }
+
+               return data_;
+       }
+
        void clear()
        {
                if(data_ != NULL) {
index 9c06c8a6d67ccd44119880f91240b1a781a18ef4..1eb6c3ba2dca1aff0660eae270c7575334850686 100644 (file)
 
 #include <libswscale/swscale.h>
 
+/* Stupid way to distinguish FFmpeg from Libav:
+ * - FFmpeg's MICRO version starts from 100 and goes up, while
+ * - Libav's micro is always below 100.
+ */
+#if LIBAVCODEC_VERSION_MICRO >= 100
+#  define AV_USING_FFMPEG
+#else
+#  define AV_USING_LIBAV
+#endif
+
 #if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
 #  define FFMPEG_HAVE_AVIO 1
 #endif
@@ -428,8 +438,45 @@ void av_frame_free(AVFrame **frame)
 #endif
 
 FFMPEG_INLINE
-AVRational av_get_r_frame_rate_compat(const AVStream *stream)
+const char* av_get_metadata_key_value(AVDictionary *metadata, const char *key)
 {
+       if (metadata == NULL) {
+               return NULL;
+       }
+       AVDictionaryEntry *tag = NULL;
+       while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+               if (!strcmp(tag->key, key)) {
+                       return tag->value;
+               }
+       }
+       return NULL;
+}
+
+FFMPEG_INLINE
+bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
+{
+       const char* encoder = av_get_metadata_key_value(ctx->metadata, "ENCODER");
+       if (encoder != NULL && !strncmp(encoder, "Lavf", 4)) {
+               return true;
+       }
+       return false;
+}
+
+FFMPEG_INLINE
+AVRational av_get_r_frame_rate_compat(AVFormatContext *ctx,
+                                      const AVStream *stream)
+{
+       /* If the video is encoded with FFmpeg and we are decoding with FFmpeg
+        * as well it seems to be more reliable to use r_frame_rate (tbr).
+        *
+        * For other cases we fall back to avg_frame_rate (fps) when possible.
+        */
+#ifdef AV_USING_FFMPEG
+       if (av_check_encoded_with_ffmpeg(ctx)) {
+               return stream->r_frame_rate;
+       }
+#endif
+
 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
        /* For until r_frame_rate was deprecated use it. */
        return stream->r_frame_rate;
index c93ed11a47b3016cf59711ec16de2e2e94c30e99..469c949d1ca882be19daa128842f813b72a944d8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c93ed11a47b3016cf59711ec16de2e2e94c30e99
+Subproject commit 469c949d1ca882be19daa128842f813b72a944d8
index 371960484a38fc64e0a2635170a41a0d8ab2f6bd..c88411ff7776a2db5d6ef6117a1b2faa42a95611 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 371960484a38fc64e0a2635170a41a0d8ab2f6bd
+Subproject commit c88411ff7776a2db5d6ef6117a1b2faa42a95611
index a8515cfdfe9a98127b592f36fcbe51b7e23b969a..310578043dec1aae382eb6a447ae1d103792d7e6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a8515cfdfe9a98127b592f36fcbe51b7e23b969a
+Subproject commit 310578043dec1aae382eb6a447ae1d103792d7e6
index 6db538eacef57cd40b23f73793cb870c0aa9c96b..5ee722f58ed400835fcf73edfb66cfc4af9a2663 100644 (file)
@@ -1521,12 +1521,15 @@ class USERPREF_PT_addons(Panel):
                             split.operator(
                                 "wm.url_open", text="Documentation", icon='HELP',
                             ).url = info["wiki_url"]
-                        split.operator(
-                            "wm.url_open", text="Report a Bug", icon='URL',
-                        ).url = info.get(
-                            "tracker_url",
-                            "https://developer.blender.org/maniphest/task/edit/form/2",
-                        )
+                        # Only add "Report a Bug" button if tracker_url is set
+                        # or the add-on is bundled (use official tracker then).
+                        if info.get("tracker_url") or not user_addon:
+                            split.operator(
+                                "wm.url_open", text="Report a Bug", icon='URL',
+                            ).url = info.get(
+                                "tracker_url",
+                                "https://developer.blender.org/maniphest/task/edit/form/2",
+                            )
                         if user_addon:
                             split.operator(
                                 "wm.addon_remove", text="Remove", icon='CANCEL',
index d89b2fcfe84af39ed40c6bd41c67c47c7730e560..54c40621a146a39d45bcf20298d97742ee876f21 100644 (file)
@@ -834,7 +834,6 @@ typedef struct tPoseLib_PreviewData {
        bAction *act;           /* poselib to use */
        TimeMarker *marker;     /* 'active' pose */
 
-       int selcount;           /* number of selected elements to work on */
        int totcount;           /* total number of elements to work on */
 
        short state;            /* state of main loop */
@@ -867,7 +866,8 @@ enum {
 /* defines for tPoseLib_PreviewData->flag values */
 enum {
        PL_PREVIEW_FIRSTTIME    = (1 << 0),
-       PL_PREVIEW_SHOWORIGINAL = (1 << 1)
+       PL_PREVIEW_SHOWORIGINAL = (1 << 1),
+       PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2),
 };
 
 /* ---------------------------- */
@@ -887,7 +887,20 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
 {
        bActionGroup *agrp;
        bPoseChannel *pchan;
-       
+       bool selected = false;
+
+       /* determine whether any bone is selected. */
+       LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) {
+               selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED;
+               if (selected) {
+                       pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED;
+                       break;
+               }
+       }
+       if (!selected) {
+               pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED;
+       }
+
        /* for each posechannel that has an actionchannel in */
        for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
                /* try to find posechannel */
@@ -909,8 +922,6 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
                        BLI_addtail(&pld->backups, plb);
                        
                        /* mark as being affected */
-                       if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
-                               pld->selcount++;
                        pld->totcount++;
                }
        }
@@ -971,6 +982,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
        KeyframeEditData ked = {{NULL}};
        KeyframeEditFunc group_ok_cb;
        int frame = 1;
+       const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
        
        /* get the frame */
        if (pld->marker)
@@ -983,8 +995,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
        group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
        ked.f1 = ((float)frame) - 0.5f;
        ked.f2 = ((float)frame) + 0.5f;
-       
-       
+
        /* start applying - only those channels which have a key at this point in time! */
        for (agrp = act->groups.first; agrp; agrp = agrp->next) {
                /* check if group has any keyframes */
@@ -996,7 +1007,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
                                bool ok = 0;
                                
                                /* check if this bone should get any animation applied */
-                               if (pld->selcount == 0) {
+                               if (!any_bone_selected) {
                                        /* if no bones are selected, then any bone is ok */
                                        ok = 1;
                                }
@@ -1009,7 +1020,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
                                                ok = 1;
                                        }
                                }
-                               
+
                                if (ok) 
                                        animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame);
                        }
@@ -1028,14 +1039,15 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
        KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
        ListBase dsources = {NULL, NULL};
        bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
-       
+       const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
+
        /* start tagging/keying */
        for (agrp = act->groups.first; agrp; agrp = agrp->next) {
                /* only for selected bones unless there aren't any selected, in which case all are included  */
                pchan = BKE_pose_channel_find_name(pose, agrp->name);
                
                if (pchan) {
-                       if ((pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
+                       if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
                                if (autokey) {
                                        /* add datasource override for the PoseChannel, to be used later */
                                        ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); 
index 02bfc70080a68a6ba3dcf9148bd1e482506c0e3c..bf0e3ca4d96c0bf39b9c45bbc5cfd8d2c1dce082 100644 (file)
@@ -3229,7 +3229,7 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
 
        vec4 value = texture(tex, cos).rgba;
        /* Density is premultiplied for interpolation, divide it out here. */
-       if (value.a > 0.0)
+       if (value.a > 1e-8)
                value.rgb /= value.a;
 
        outvec = value.rgb;
index 5472cae3ef22832adc8fd8372c4e1421dd1c3705..a770b34ecc6ae4d0cb37acd10d54919cd8db3663 100644 (file)
@@ -511,7 +511,7 @@ static int startffmpeg(struct anim *anim)
                return -1;
        }
 
-       frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
+       frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
        if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
                anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
        }
@@ -989,7 +989,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
 
        v_st = anim->pFormatCtx->streams[anim->videoStream];
 
-       frame_rate = av_q2d(av_get_r_frame_rate_compat(v_st));
+       frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
 
        st_time = anim->pFormatCtx->start_time;
        pts_time_base = av_q2d(v_st->time_base);
index 009258079ee7aa3a9f0ff57b580a43eb21e00a0f..eaf4dfd84b4ca58cc6ff8df9e5ece26e0f0b9942 100644 (file)
@@ -909,7 +909,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
 
        stream_size = avio_size(context->iFormatCtx->pb);
 
-       context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iStream));
+       context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
        context->pts_time_base = av_q2d(context->iStream->time_base);
 
        while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
index 4cb1c13a44a98b1c3319f359337f916d65d39250..4e85d70d3829a56dac489ccd6d3a73725c4bd49d 100644 (file)
@@ -1621,14 +1621,13 @@ static bool exr_has_alpha(MultiPartInputFile& file)
 
 static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
 {
-       const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
        const ChannelList& channels = file.header(0).channels();
        std::set <std::string> layerNames;
 
        /* will not include empty layer names */
        channels.layers(layerNames);
 
-       if (comments || layerNames.size() > 1)
+       if (layerNames.size() > 1)
                return true;
 
        if (layerNames.size()) {
@@ -1667,7 +1666,7 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
        }
        else {
                *r_singlelayer = false;
-               *r_multilayer = true;
+               *r_multilayer = (layerNames.size() > 1);
                *r_multiview = false;
                return;
        }
index 10196804656c4cae3e7434b7113aa009df2ba391..11ec97ca5f8e59831132869f0be6f1403433520c 100644 (file)
@@ -228,7 +228,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
                codecCtx->frame_rate_base=1000;
        m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
 #else
-       m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx->streams[videoStream]));
+       m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx, formatCtx->streams[videoStream]));
 #endif
        if (m_baseFrameRate <= 0.0) 
                m_baseFrameRate = defFrameRate;
index b11375e89061303401376f7aeae42ac2fd64692a..7695e14cfc5820ac66546e0e515914d85ab81af3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b11375e89061303401376f7aeae42ac2fd64692a
+Subproject commit 7695e14cfc5820ac66546e0e515914d85ab81af3
index 20b65889c2bf83f7c1f161c753a4f04a9edc60ae..568f66eb27006666e8533cf0d843508dd2562ba4 100644 (file)
@@ -27,6 +27,7 @@
 set(USE_EXPERIMENTAL_TESTS FALSE)
 
 set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
+set(TEST_DATA_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests_data)
 set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
 
 # ugh, any better way to do this on testing only?
@@ -617,5 +618,14 @@ if(WITH_ALEMBIC)
        )
 endif()
 
-add_subdirectory(view_layer)
+if(WITH_CODEC_FFMPEG)
+       add_python_test(
+               ffmpeg_tests
+               ${CMAKE_CURRENT_LIST_DIR}/ffmpeg_tests.py
+               --blender "$<TARGET_FILE:blender>"
+               --testdir "${TEST_DATA_SRC_DIR}/ffmpeg"
+       )
+endif()
+
 add_subdirectory(collada)
+add_subdirectory(view_layer)
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
new file mode 100755 (executable)
index 0000000..9493d6f
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import argparse
+import functools
+import shutil
+import pathlib
+import subprocess
+import sys
+import tempfile
+import unittest
+
+from modules.test_utils import AbstractBlenderRunnerTest
+
+
+class AbstractFFmpegTest(AbstractBlenderRunnerTest):
+    @classmethod
+    def setUpClass(cls):
+        cls.blender = args.blender
+        cls.testdir = pathlib.Path(args.testdir)
+
+
+class AbstractFFmpegSequencerTest(AbstractFFmpegTest):
+    def get_script_for_file(self, filename: pathlib.Path) -> str:
+        movie = self.testdir / filename
+        return \
+            "import bpy; " \
+            "bpy.context.scene.sequence_editor_create(); " \
+            "strip = bpy.context.scene.sequence_editor.sequences.new_movie(" \
+            "'test_movie', %r, channel=1, frame_start=1); " \
+            "print(f'fps:{strip.fps}')" % movie.as_posix()
+
+    def get_movie_file_fps(self, filename: pathlib.Path) -> float:
+        script = self.get_script_for_file(filename)
+        output = self.run_blender('', script)
+        for line in output.splitlines():
+            if line.startswith('fps:'):
+                return float(line.split(':')[1])
+        return 0.0
+
+
+class FPSDetectionTest(AbstractFFmpegSequencerTest):
+    def test_T51153(self):
+        self.assertAlmostEqual(
+            self.get_movie_file_fps('T51153_bad_clip_2.mts'), 
+            29.97,
+            places=2)
+
+    def test_T53857(self):
+        self.assertAlmostEqual(
+            self.get_movie_file_fps('T53857_2018-01-22_15-30-49.mkv'),
+            30.0,
+            places=2)
+
+    def test_T54148(self):
+        self.assertAlmostEqual(
+            self.get_movie_file_fps('T54148_magn_0.mkv'),
+            1.0,
+            places=2)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--blender', required=True)
+    parser.add_argument('--testdir', required=True)
+    args, remaining = parser.parse_known_args()
+
+    unittest.main(argv=sys.argv[0:1] + remaining)
index 6ca498d8cdf6f9ef2b076cc2fd2b490895cb2735..55ef882c49cf013f251debcd0d8fd6310e286bd4 100755 (executable)
@@ -75,18 +75,24 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
         assert self.blender, "Path to Blender binary is to be set in setUpClass()"
         assert self.testdir, "Path to tests binary is to be set in setUpClass()"
 
-        blendfile = self.testdir / filepath
+        blendfile = self.testdir / filepath if filepath else ""
 
-        command = (
+        command = [
             self.blender,
             '--background',
             '-noaudio',
             '--factory-startup',
             '--enable-autoexec',
-            str(blendfile),
+        ]
+
+        if blendfile:
+            command.append(str(blendfile))
+
+        command.extend([
             '-E', 'CYCLES',
             '--python-exit-code', '47',
             '--python-expr', python_script,
+            ]
         )
 
         proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,