From db333d9ea4881d9f48e3cc4b1ec59b4dafb27cc0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 8 Mar 2018 04:04:52 +0100 Subject: Cycles: support arbitrary number of motion blur steps for objects. --- intern/cycles/blender/addon/properties.py | 2 +- intern/cycles/blender/blender_camera.cpp | 4 +- intern/cycles/blender/blender_object.cpp | 49 +++++---- intern/cycles/blender/blender_util.h | 41 ++++---- intern/cycles/kernel/geom/geom_object.h | 16 ++- intern/cycles/kernel/kernel_light.h | 3 +- intern/cycles/kernel/kernel_textures.h | 1 + intern/cycles/kernel/kernel_types.h | 6 +- intern/cycles/render/object.cpp | 167 ++++++++++++++++++++---------- intern/cycles/render/object.h | 10 +- intern/cycles/render/scene.cpp | 1 + intern/cycles/render/scene.h | 1 + intern/cycles/render/session.cpp | 2 +- intern/cycles/util/util_transform.h | 17 --- 14 files changed, 184 insertions(+), 136 deletions(-) (limited to 'intern') diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 62aea8790af..1b95c365616 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1088,7 +1088,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, ) diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 909db8d9449..f00ade320e7 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -229,9 +229,7 @@ static void blender_camera_from_object(BlenderCamera *bcam, else bcam->sensor_fit = BlenderCamera::VERTICAL; - if(object_use_motion(b_ob, b_ob)) { - bcam->motion_steps = object_motion_steps(b_ob); - } + bcam->motion_steps = object_motion_steps(b_ob, b_ob); } else { /* from lamp not implemented yet */ diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 45309292f0b..4b40f4d458b 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -327,22 +327,11 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, 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 */ @@ -389,24 +378,34 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, 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; - if(object_use_motion(b_parent, b_ob)) { + uint motion_steps; + + 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; + } - for(size_t step = 0; step < mesh->motion_steps - 1; step++) { - motion_times.insert(mesh->motion_time(step)); - } + object->motion.resize(motion_steps, transform_empty()); + object->motion[motion_steps/2] = tfm; + + for(size_t step = 0; step < motion_steps; step++) { + motion_times.insert(object->motion_time(step)); } } diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index c4c45035b5a..c418b19a637 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -484,33 +484,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; } diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 67d039e1bc7..800649abf38 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -40,18 +40,12 @@ enum ObjectVectorTransform { ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type) { - Transform tfm; if(type == OBJECT_INVERSE_TRANSFORM) { - tfm.x = kernel_tex_fetch(__objects, object).tfm.mid.x; - tfm.y = kernel_tex_fetch(__objects, object).tfm.mid.y; - tfm.z = kernel_tex_fetch(__objects, object).tfm.mid.z; + return kernel_tex_fetch(__objects, object).itfm; } else { - tfm.x = kernel_tex_fetch(__objects, object).tfm.pre.x; - tfm.y = kernel_tex_fetch(__objects, object).tfm.pre.y; - tfm.z = kernel_tex_fetch(__objects, object).tfm.pre.z; + return kernel_tex_fetch(__objects, object).tfm; } - return tfm; } /* Lamp to world space transformation */ @@ -79,10 +73,12 @@ ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals *kg #ifdef __OBJECT_MOTION__ ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int object, float time) { - const ccl_global DecomposedMotionTransform *motion = &kernel_tex_fetch(__objects, object).tfm; + 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_array_interpolate(&tfm, &motion->pre, 3, time); + transform_motion_array_interpolate(&tfm, motion, num_steps, time); return tfm; } diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index aaf7a7abdd4..efab69ee37d 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -792,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 diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 56de5b27605..9047b93a0b2 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -33,6 +33,7 @@ KERNEL_TEX(float2, __prim_time) /* objects */ KERNEL_TEX(KernelObject, __objects) KERNEL_TEX(Transform, __object_motion_pass) +KERNEL_TEX(DecomposedTransform, __object_motion) KERNEL_TEX(uint, __object_flag) /* cameras */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 2c3b7ba29a4..977ceac12ea 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -1433,7 +1433,8 @@ static_assert_align(KernelData, 16); /* Kernel data structures. */ typedef struct KernelObject { - DecomposedMotionTransform tfm; + Transform tfm; + Transform itfm; float surface_area; float pass_id; @@ -1449,7 +1450,8 @@ typedef struct KernelObject { uint patch_map_offset; uint attribute_map_offset; - uint pad1, pad2; + uint motion_offset; + uint pad; } KernelObject;; static_assert_align(KernelObject, 16); diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index bde340ae928..138de250c5f 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -54,6 +54,9 @@ struct UpdateObjectTransformState { */ map surface_area_map; + /* Motion offsets for each object. */ + array motion_offset; + /* Packed object arrays. Those will be filled in. */ uint *object_flag; KernelObject *objects; @@ -91,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()); SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false); @@ -103,46 +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; - } - mtfm.mid = tfm; + /* Test if any of the transforms are actually different. */ + have_motion = have_motion || motion[i] != 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; - DecomposedMotionTransform decomp; - transform_motion_decompose(&decomp.pre, &mtfm.pre, 3); + if(motion_blur && use_motion()) { + array decomp(motion.size()); + transform_motion_decompose(decomp.data(), motion.data(), motion.size()); bounds = BoundBox::empty; @@ -152,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_array_interpolate(&ttfm, &decomp.pre, 3, 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; } @@ -276,6 +289,29 @@ void Object::tag_update(Scene *scene) scene->object_manager->need_update = true; } +bool Object::use_motion() const +{ + return (motion.size() > 1); +} + +float Object::motion_time(int step) const +{ + return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f; +} + +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 -1; +} + bool Object::is_traceable() const { /* Mesh itself can be empty,can skip all such objects. */ @@ -381,12 +417,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s } } - memcpy(&kobject.tfm.pre, &tfm, sizeof(tfm)); - memcpy(&kobject.tfm.mid, &itfm, sizeof(itfm)); + 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; @@ -396,38 +433,39 @@ 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; - - /* 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; + /* Clear motion array if there is no actual motion. */ + ob->update_motion(); + + /* 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; } - object_motion_pass[object_index*OBJECT_MOTION_PASS_SIZE+0] = mtfm.pre; - object_motion_pass[object_index*OBJECT_MOTION_PASS_SIZE+1] = mtfm.post; + 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. */ - DecomposedMotionTransform decomp; - MotionTransform mtfm = ob->motion; - mtfm.mid = tfm; - - transform_motion_decompose(&decomp.pre, &mtfm.pre, 3); - kobject.tfm = decomp; + if(ob->use_motion()) { + kobject.motion_offset = state->motion_offset[object_index]; + + /* 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; } @@ -512,11 +550,28 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, 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.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size()); } + 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 * 0 is dummy particle, index starts at 1. @@ -560,6 +615,9 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, if(state.need_motion == Scene::MOTION_PASS) { 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; dscene->data.bvh.have_curves = state.have_curves; @@ -709,6 +767,7 @@ void ObjectManager::device_free(Device *, DeviceScene *dscene) { dscene->objects.free(); dscene->object_motion_pass.free(); + dscene->object_motion.free(); dscene->object_flag.free(); } @@ -748,7 +807,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P 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; diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 7cf1528c4a7..c7212ae25f9 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -50,8 +50,7 @@ public: int pass_id; vector attributes; uint visibility; - MotionTransform motion; - bool use_motion; + array motion; bool hide_on_missing_motion; bool use_holdout; bool is_shadow_catcher; @@ -70,6 +69,13 @@ public: void compute_bounds(bool motion_blur); void apply_transform(bool apply_to_motion); + /* 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. */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 6fc6e453aff..ba47e3ab6f8 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -61,6 +61,7 @@ DeviceScene::DeviceScene(Device *device) patches(device, "__patches", MEM_TEXTURE), objects(device, "__objects", 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), diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 74e1df2f1d2..04bd4735a86 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -88,6 +88,7 @@ public: /* objects */ device_vector objects; device_vector object_motion_pass; + device_vector object_motion; device_vector object_flag; /* cameras */ diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 5732faf2a36..41156038558 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -662,7 +662,7 @@ DeviceRequestedFeatures Session::get_requested_device_features() 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) { diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index ade74364876..987f4dac777 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -37,12 +37,6 @@ typedef struct Transform { #endif } Transform; -typedef struct ccl_may_alias MotionTransform { - Transform pre; - Transform mid; - Transform post; -} MotionTransform; - /* Transform decomposed in rotation/translation/scale. we use the same data * structure as Transform, and tightly pack decomposition into it. first the * rotation (4), then translation (3), then 3x3 scale matrix (9). */ @@ -51,12 +45,6 @@ typedef struct DecomposedTransform { float4 x, y, z, w; } DecomposedTransform; -typedef struct ccl_may_alias DecomposedMotionTransform { - DecomposedTransform pre; - DecomposedTransform mid; - DecomposedTransform post; -} DecomposedMotionTransform; - /* Functions */ ccl_device_inline float3 transform_point(const Transform *t, const float3 a) @@ -443,11 +431,6 @@ ccl_device_inline bool operator==(const DecomposedTransform& A, const Decomposed return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0; } -ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransform& B) -{ - return (A.pre == B.pre && A.post == B.post); -} - float4 transform_to_quat(const Transform& tfm); void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size); Transform transform_from_viewplane(BoundBox2D& viewplane); -- cgit v1.2.3