diff options
-rw-r--r-- | intern/cycles/blender/addon/properties.py | 18 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 6 | ||||
-rw-r--r-- | intern/cycles/blender/blender_camera.cpp | 21 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_camera.h | 29 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_types.h | 5 | ||||
-rw-r--r-- | intern/cycles/render/camera.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/render/camera.h | 16 |
7 files changed, 103 insertions, 0 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index cbd1a8b1922..f48bc93cabf 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -531,6 +531,24 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): ), ) + cls.rolling_shutter_type = EnumProperty( + name="Shutter Type", + default='NONE', + description="Type of rolling shutter effect matching CMOS-based cameras", + items=( + ('NONE', "None", "No rolling shutter effect used"), + ('TOP', "Top-Bottom", "Sensor is being scanned from top to bottom") + # TODO(seergey): Are there real cameras with different scanning direction? + ), + ) + + cls.rolling_shutter_duration = FloatProperty( + name="Rolling Shutter Duration", + description="Scanline \"exposure\" time for the rolling shutter effect", + default = 0.1, + min=0.0, max=1.0, + ) + @classmethod def unregister(cls): del bpy.types.Scene.cycles diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index e2aa266d53b..495b2f21f7b 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -281,6 +281,12 @@ class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel): row.operator("render.shutter_curve_preset", icon='LINCURVE', text="").shape = 'LINE' row.operator("render.shutter_curve_preset", icon='NOCURVE', text="").shape = 'MAX' + col = layout.column() + col.prop(cscene, "rolling_shutter_type") + row = col.row() + row.active = cscene.rolling_shutter_type != 'NONE' + row.prop(cscene, "rolling_shutter_duration") + class CyclesRender_PT_film(CyclesButtonsPanel, Panel): bl_label = "Film" diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index cde3840b796..5f2e0762964 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -39,6 +39,9 @@ struct BlenderCamera { Camera::MotionPosition motion_position; float shutter_curve[RAMP_TABLE_SIZE]; + Camera::RollingShutterType rolling_shutter_type; + float rolling_shutter_duration; + float aperturesize; uint apertureblades; float aperturerotation; @@ -86,6 +89,8 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render bcam->sensor_fit = BlenderCamera::AUTO; bcam->shuttertime = 1.0f; bcam->motion_position = Camera::MOTION_POSITION_CENTER; + bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE; + bcam->rolling_shutter_duration = 0.1f; bcam->border.right = 1.0f; bcam->border.top = 1.0f; bcam->pano_viewplane.right = 1.0f; @@ -418,6 +423,9 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->fov_post = cam->fov; cam->motion_position = bcam->motion_position; + cam->rolling_shutter_type = bcam->rolling_shutter_type; + cam->rolling_shutter_duration = bcam->rolling_shutter_duration; + memcpy(cam->shutter_curve, bcam->shutter_curve, sizeof(cam->shutter_curve)); /* border */ @@ -460,6 +468,19 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override break; } + switch(RNA_enum_get(&cscene, "rolling_shutter_type")) { + case 0: + bcam.rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE; + break; + case 1: + bcam.rolling_shutter_type = Camera::ROLLING_SHUTTER_TOP; + break; + default: + bcam.rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE; + break; + } + bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration"); + /* border */ if(b_render.use_border()) { bcam.border.left = b_render.border_min_x(); diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index 01017eabde2..c51174b645d 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -294,8 +294,37 @@ ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, f ray->time = TIME_INVALID; } else { + /* TODO(sergey): Such lookup is unneeded when there's rolling shutter + * effect in use but rollign shutter duration is set to 0.0. + */ const int shutter_table_offset = kernel_data.cam.shutter_table_offset; ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE); + /* TODO(sergey): Currently single rolling shutter effect type only + * where scanlines are acquired from top to bottom and whole scanline + * is acquired at once (no delay in acquisition happens between pixels + * of sinle scanline). + * + * Might want to support more models in the future. + */ + if(kernel_data.cam.rolling_shutter_type) { + /* Time corresponding to a fully rolling shutter only effect: + * top of the frame is time 0.0, bottom of the frame is time 1.0. + */ + const float time = 1.0f - (float)y / kernel_data.cam.height; + const float duration = kernel_data.cam.rolling_shutter_duration; + if(duration != 0.0f) { + /* This isn't fully physical correct, but lets us to have simple + * controls in the interface. The idea here is basically sort of + * linear interpolation between how much rolling shutter effect + * exist on the frame and how much of it is a motion blur effect. + */ + ray->time = (ray->time - 0.5f) * duration; + ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f; + } + else { + ray->time = time; + } + } } #endif diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 04d013ceb9c..8682325998d 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -849,6 +849,11 @@ typedef struct KernelCamera { PerspectiveMotionTransform perspective_motion; int shutter_table_offset; + + /* Rolling shutter */ + int rolling_shutter_type; + float rolling_shutter_duration; + int pad; } KernelCamera; diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 33a5c004033..9c17a11e0f1 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -109,6 +109,10 @@ Camera::Camera() for(int i = 0; i < num_shutter_points; ++i) { shutter_curve[i] = 1.0f; } + + /* Initialize rolling shutter effect. */ + rolling_shutter_type = ROLLING_SHUTTER_NONE; + rolling_shutter_duration = 0.1f; } Camera::~Camera() @@ -357,6 +361,10 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) /* Camera in volume. */ kcam->is_inside_volume = 0; + /* Rolling shutter effect */ + kcam->rolling_shutter_type = rolling_shutter_type; + kcam->rolling_shutter_duration = rolling_shutter_duration; + previous_need_motion = need_motion; } diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 1c26afafeff..d4a66b66072 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -47,12 +47,28 @@ public: MOTION_POSITION_END, }; + /* Specifies rolling shutter effect. */ + enum RollingShutterType { + /* No rolling shutter effect. */ + ROLLING_SHUTTER_NONE = 0, + /* Sensor is being scanned vertically from top to bottom. */ + ROLLING_SHUTTER_TOP, + }; + /* motion blur */ float shuttertime; MotionPosition motion_position; float shutter_curve[RAMP_TABLE_SIZE]; size_t shutter_table_offset; + /* ** Rolling shutter effect. ** */ + /* Defines rolling shutter effect type. */ + RollingShutterType rolling_shutter_type; + /* Specifies exposure time of scanlines when using + * rolling shutter effect. + */ + float rolling_shutter_duration; + /* depth of field */ float focaldistance; float aperturesize; |