diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 5f65fd7506b..094d68e4f53 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -519,6 +519,18 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): min=0.0, max=5.0 ) + cls.motion_blur_position = EnumProperty( + name="Motion Blur Position", + default='CENTER', + description="Specifies an offset for the shutter’s time interval " + "which allows to change the motion blur trails", + items=( + ('START', "Start on Frame", "The shutter opens at the current frame"), + ('CENTER', "Center on Frame", "The shutter is open during the current frame"), + ('END', "End on Frame", "The shutter closes at the current frame"), + ), + ) + @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 ecd98551747..3700da3263e 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -259,11 +259,14 @@ class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout - rd = context.scene.render + scene = context.scene + cscene = scene.cycles + rd = scene.render layout.active = rd.use_motion_blur - row = layout.row() - row.prop(rd, "motion_blur_shutter") + col = layout.column() + col.prop(cscene, "motion_blur_position", text="Position") + col.prop(rd, "motion_blur_shutter") class CyclesRender_PT_film(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 1cc601ce148..04926f94c62 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -36,6 +36,7 @@ struct BlenderCamera { float lens; float shuttertime; + Camera::MotionPosition motion_position; float aperturesize; uint apertureblades; @@ -83,6 +84,7 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render bcam->sensor_height = 18.0f; bcam->sensor_fit = BlenderCamera::AUTO; bcam->shuttertime = 1.0f; + bcam->motion_position = Camera::MOTION_POSITION_CENTER; bcam->border.right = 1.0f; bcam->border.top = 1.0f; bcam->pano_viewplane.right = 1.0f; @@ -409,6 +411,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->shuttertime = bcam->shuttertime; cam->fov_pre = cam->fov; cam->fov_post = cam->fov; + cam->motion_position = bcam->motion_position; /* border */ cam->border = bcam->border; @@ -431,6 +434,22 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override bcam.pixelaspect.y = b_render.pixel_aspect_y(); bcam.shuttertime = b_render.motion_blur_shutter(); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + switch(RNA_enum_get(&cscene, "motion_blur_position")) { + case 0: + bcam.motion_position = Camera::MOTION_POSITION_START; + break; + case 1: + bcam.motion_position = Camera::MOTION_POSITION_CENTER; + break; + case 2: + bcam.motion_position = Camera::MOTION_POSITION_END; + break; + default: + bcam.motion_position = Camera::MOTION_POSITION_CENTER; + break; + } + /* border */ if(b_render.use_border()) { bcam.border.left = b_render.border_min_x(); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 7dc57c33ed3..11593807a00 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -685,6 +685,28 @@ void BlenderSync::sync_motion(BL::RenderSettings b_render, Camera prevcam = *(scene->camera); int frame_center = b_scene.frame_current(); + float frame_center_delta = 0.0f; + + if(scene->need_motion() != Scene::MOTION_PASS && + scene->camera->motion_position != Camera::MOTION_POSITION_CENTER) + { + float shuttertime = scene->camera->shuttertime; + if(scene->camera->motion_position == Camera::MOTION_POSITION_END) { + frame_center_delta = -shuttertime * 0.5f; + } + else { + assert(scene->camera->motion_position == Camera::MOTION_POSITION_START); + frame_center_delta = shuttertime * 0.5f; + } + float time = frame_center + frame_center_delta; + int frame = (int)floorf(time); + float subframe = time - frame; + python_thread_state_restore(python_thread_state); + b_engine.frame_set(frame, subframe); + python_thread_state_save(python_thread_state); + sync_camera_motion(b_render, b_cam, width, height, 0.0f); + sync_objects(b_v3d, 0.0f); + } /* always sample these times for camera motion */ motion_times.insert(-1.0f); @@ -704,7 +726,7 @@ void BlenderSync::sync_motion(BL::RenderSettings b_render, shuttertime = scene->camera->shuttertime; /* compute frame and subframe time */ - float time = frame_center + relative_time * shuttertime * 0.5f; + float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f; int frame = (int)floorf(time); float subframe = time - frame; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index aed1b6de138..986e90c59f7 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -161,7 +161,12 @@ void BlenderSync::sync_data(BL::RenderSettings b_render, mesh_synced.clear(); /* use for objects and motion sync */ - sync_objects(b_v3d); + if(scene->need_motion() == Scene::MOTION_PASS || + scene->need_motion() == Scene::MOTION_NONE || + scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) + { + sync_objects(b_v3d); + } sync_motion(b_render, b_v3d, b_override, diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 127d116e556..88ff7fbb70a 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -29,6 +29,7 @@ CCL_NAMESPACE_BEGIN Camera::Camera() { shuttertime = 1.0f; + motion_position = MOTION_POSITION_CENTER; aperturesize = 0.0f; focaldistance = 10.0f; diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 1bedb051112..53bd4f0bc14 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -32,12 +32,24 @@ class Scene; /* Camera * * The camera parameters are quite standard, tested to be both compatible with - * Renderman, and Blender after remapping. */ + * Renderman, and Blender after remapping. + */ class Camera { public: + /* Specifies an offset for the shutter's time interval. */ + enum MotionPosition { + /* Shutter opens at the current frame. */ + MOTION_POSITION_START, + /* Shutter is fully open at the current frame. */ + MOTION_POSITION_CENTER, + /* Shutter closes at the current frame. */ + MOTION_POSITION_END, + }; + /* motion blur */ float shuttertime; + MotionPosition motion_position; /* depth of field */ float focaldistance;