diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index 8d439ceb0d7..01017eabde2 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -290,10 +290,13 @@ ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, f #ifdef __CAMERA_MOTION__ /* motion blur */ - if(kernel_data.cam.shuttertime == -1.0f) + if(kernel_data.cam.shuttertime == -1.0f) { ray->time = TIME_INVALID; - else - ray->time = time; + } + else { + const int shutter_table_offset = kernel_data.cam.shutter_table_offset; + ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE); + } #endif /* sample */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 740a5f1f5d3..1d71e6435db 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -39,6 +39,7 @@ CCL_NAMESPACE_BEGIN #define LIGHT_SIZE 5 #define FILTER_TABLE_SIZE 256 #define RAMP_TABLE_SIZE 256 +#define SHUTTER_TABLE_SIZE 256 #define PARTICLE_SIZE 5 #define TIME_INVALID FLT_MAX @@ -813,6 +814,9 @@ typedef struct KernelCamera { * Used for camera zoom motion blur, */ PerspectiveMotionTransform perspective_motion; + + int shutter_table_offset; + int pad; } KernelCamera; typedef struct KernelFilm { diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 88ff7fbb70a..c59971996bc 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -18,18 +18,36 @@ #include "mesh.h" #include "object.h" #include "scene.h" +#include "tables.h" #include "device.h" #include "util_foreach.h" +#include "util_function.h" +#include "util_math_cdf.h" #include "util_vector.h" CCL_NAMESPACE_BEGIN +static float shutter_curve_eval(float x, + float shutter_curve[RAMP_TABLE_SIZE]) +{ + x *= RAMP_TABLE_SIZE; + int index = (int)x; + float frac = x - index; + if(index < RAMP_TABLE_SIZE - 1) { + return lerp(shutter_curve[index], shutter_curve[index + 1], frac); + } + else { + return shutter_curve[RAMP_TABLE_SIZE - 1]; + } +} + Camera::Camera() { shuttertime = 1.0f; motion_position = MOTION_POSITION_CENTER; + shutter_table_offset = TABLE_OFFSET_INVALID; aperturesize = 0.0f; focaldistance = 10.0f; @@ -85,6 +103,12 @@ Camera::Camera() need_device_update = true; need_flags_update = true; previous_need_motion = -1; + + /* Initialize shutter curve. */ + const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve); + for(int i = 0; i < num_shutter_points; ++i) { + shutter_curve[i] = 1.0f; + } } Camera::~Camera() @@ -279,6 +303,23 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) /* motion blur */ #ifdef __CAMERA_MOTION__ kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: -1.0f; + + if(need_motion == Scene::MOTION_BLUR) { + vector shutter_table; + util_cdf_inverted(SHUTTER_TABLE_SIZE, + 0.0f, + 1.0f, + function_bind(shutter_curve_eval, _1, shutter_curve), + false, + shutter_table); + shutter_table_offset = scene->lookup_tables->add_table(dscene, + shutter_table); + kcam->shutter_table_offset = (int)shutter_table_offset; + } + else if(shutter_table_offset != TABLE_OFFSET_INVALID) { + scene->lookup_tables->remove_table(shutter_table_offset); + shutter_table_offset = TABLE_OFFSET_INVALID; + } #else kcam->shuttertime = -1.0f; #endif @@ -342,9 +383,14 @@ void Camera::device_update_volume(Device * /*device*/, need_flags_update = false; } -void Camera::device_free(Device * /*device*/, DeviceScene * /*dscene*/) +void Camera::device_free(Device * /*device*/, + DeviceScene * /*dscene*/, + Scene *scene) { - /* nothing to free, only writing to constant memory */ + if(shutter_table_offset != TABLE_OFFSET_INVALID) { + scene->lookup_tables->remove_table(shutter_table_offset); + shutter_table_offset = TABLE_OFFSET_INVALID; + } } bool Camera::modified(const Camera& cam) diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 53bd4f0bc14..1c26afafeff 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -50,6 +50,8 @@ public: /* motion blur */ float shuttertime; MotionPosition motion_position; + float shutter_curve[RAMP_TABLE_SIZE]; + size_t shutter_table_offset; /* depth of field */ float focaldistance; @@ -132,7 +134,7 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene); + void device_free(Device *device, DeviceScene *dscene, Scene *scene); bool modified(const Camera& cam); bool motion_modified(const Camera& cam); diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 19d715d834b..25f812221ac 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -97,7 +97,7 @@ void Scene::free_memory(bool final) particle_systems.clear(); if(device) { - camera->device_free(device, &dscene); + camera->device_free(device, &dscene, this); film->device_free(device, &dscene, this); background->device_free(device, &dscene); integrator->device_free(device, &dscene); diff --git a/intern/cycles/util/util_math_cdf.cpp b/intern/cycles/util/util_math_cdf.cpp index cafe4c5abeb..ec78ca15d88 100644 --- a/intern/cycles/util/util_math_cdf.cpp +++ b/intern/cycles/util/util_math_cdf.cpp @@ -37,7 +37,7 @@ void util_cdf_invert(const int resolution, float x = i / (float)half_size; int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin(); float t; - if(index < cdf.size()) { + if(index < cdf.size() - 1) { t = (x - cdf[index])/(cdf[index+1] - cdf[index]); } else { t = 0.0f; @@ -49,11 +49,11 @@ void util_cdf_invert(const int resolution, } } else { - for(int i = 0; i <= resolution; i++) { + for(int i = 0; i < resolution; i++) { float x = from + range * (float)i * inv_resolution; int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin(); float t; - if(index < cdf.size()) { + if(index < cdf.size() - 1) { t = (x - cdf[index])/(cdf[index+1] - cdf[index]); } else { t = 0.0f;