diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-02-03 23:16:28 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-02-03 23:17:59 +0300 |
commit | 1dddcfbaff14ff2871918b044714c87c7024e589 (patch) | |
tree | b33ad2b5571738e0ad50346acc60cffd0b07e21c /source/blender/compositor/operations | |
parent | c69458985cdb0cc1b388b81f61e5091c73461003 (diff) |
Compositor: Implement sampled motion blur for plane track deform node
Quite striaghtforward change, and in theory we can even try supporting motion
blur for the corner pin node (which is tricky because coordinates actually
coming from sockets, but with some black magic should be doable).
Diffstat (limited to 'source/blender/compositor/operations')
5 files changed, 170 insertions, 78 deletions
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp index fe272000b6e..fb8730c9fa0 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp @@ -135,7 +135,7 @@ void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect) getInputSocketReader(3) }; float corners[4][2]; readCornersFromSockets(rect, readers, corners); - calculateCorners(corners, true); + calculateCorners(corners, true, 0); m_corners_ready = true; } @@ -194,8 +194,7 @@ void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect) getInputSocketReader(4) }; float corners[4][2]; readCornersFromSockets(rect, readers, corners); - calculateCorners(corners, true); - calculatePerspectiveMatrix(); + calculateCorners(corners, true, 0); m_corners_ready = true; } diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp index c507b4cfa98..e3095f74b99 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp @@ -56,36 +56,38 @@ PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() : this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); this->addOutputSocket(COM_DT_COLOR); this->m_pixelReader = NULL; + this->m_motion_blur_samples = 1; + this->m_motion_blur_shutter = 0.5f; this->setComplex(true); } -void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], bool normalized) +void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], + bool normalized, + int sample) { + BLI_assert(sample < this->m_motion_blur_samples); + const int width = this->m_pixelReader->getWidth(); + const int height = this->m_pixelReader->getHeight(); + float frame_corners[4][2] = {{0.0f, 0.0f}, + {(float) width, 0.0f}, + {(float) width, (float) height}, + {0.0f, (float) height}}; + MotionSample *sample_data = &this->m_samples[sample]; if (normalized) { for (int i = 0; i < 4; i++) { - this->m_frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); - this->m_frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); + sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); + sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); } } else { for (int i = 0; i < 4; i++) { - this->m_frameSpaceCorners[i][0] = corners[i][0]; - this->m_frameSpaceCorners[i][1] = corners[i][1]; + sample_data->frameSpaceCorners[i][0] = corners[i][0]; + sample_data->frameSpaceCorners[i][1] = corners[i][1]; } } -} - -void PlaneDistortWarpImageOperation::calculatePerspectiveMatrix() -{ - const int width = this->m_pixelReader->getWidth(); - const int height = this->m_pixelReader->getHeight(); - float frame_corners[4][2] = {{0.0f, 0.0f}, - {(float) width, 0.0f}, - {(float) width, (float) height}, - {0.0f, (float) height}}; - BKE_tracking_homography_between_two_quads(this->m_frameSpaceCorners, + BKE_tracking_homography_between_two_quads(sample_data->frameSpaceCorners, frame_corners, - this->m_perspectiveMatrix); + sample_data->perspectiveMatrix); } void PlaneDistortWarpImageOperation::initExecution() @@ -100,35 +102,47 @@ void PlaneDistortWarpImageOperation::deinitExecution() void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { - float xy[2] = {x, y}; float uv[2]; float deriv[2][2]; - - pixelTransform(xy, uv, deriv); - - m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR); -} - -void PlaneDistortWarpImageOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]) -{ - warpCoord(xy[0], xy[1], m_perspectiveMatrix, r_uv, r_deriv); + if (this->m_motion_blur_samples == 1) { + warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv); + m_pixelReader->readFiltered(output, + uv[0], uv[1], + deriv[0], deriv[1], + COM_PS_BILINEAR); + } + else { + zero_v4(output); + for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) { + float color[4]; + warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv); + m_pixelReader->readFiltered(color, + uv[0], uv[1], + deriv[0], deriv[1], + COM_PS_BILINEAR); + add_v4_v4(output, color); + } + mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples); + } } bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) { - float UVs[4][2]; - float deriv[2][2]; - - /* TODO(sergey): figure out proper way to do this. */ - warpCoord(input->xmin - 2, input->ymin - 2, this->m_perspectiveMatrix, UVs[0], deriv); - warpCoord(input->xmax + 2, input->ymin - 2, this->m_perspectiveMatrix, UVs[1], deriv); - warpCoord(input->xmax + 2, input->ymax + 2, this->m_perspectiveMatrix, UVs[2], deriv); - warpCoord(input->xmin - 2, input->ymax + 2, this->m_perspectiveMatrix, UVs[3], deriv); - float min[2], max[2]; INIT_MINMAX2(min, max); - for (int i = 0; i < 4; i++) { - minmax_v2v2_v2(min, max, UVs[i]); + + for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) { + float UVs[4][2]; + float deriv[2][2]; + MotionSample *sample_data = &this->m_samples[sample]; + /* TODO(sergey): figure out proper way to do this. */ + warpCoord(input->xmin - 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv); + warpCoord(input->xmax + 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv); + warpCoord(input->xmax + 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv); + warpCoord(input->xmin - 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv); + for (int i = 0; i < 4; i++) { + minmax_v2v2_v2(min, max, UVs[i]); + } } rcti newInput; @@ -151,20 +165,26 @@ PlaneDistortMaskOperation::PlaneDistortMaskOperation() : /* Currently hardcoded to 8 samples. */ m_osa = 8; + this->m_motion_blur_samples = 1; + this->m_motion_blur_shutter = 0.5f; } -void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2], bool normalized) +void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2], + bool normalized, + int sample) { + BLI_assert(sample < this->m_motion_blur_samples); + MotionSample *sample_data = &this->m_samples[sample]; if (normalized) { for (int i = 0; i < 4; i++) { - this->m_frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); - this->m_frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); + sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); + sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); } } else { for (int i = 0; i < 4; i++) { - this->m_frameSpaceCorners[i][0] = corners[i][0]; - this->m_frameSpaceCorners[i][1] = corners[i][1]; + sample_data->frameSpaceCorners[i][0] = corners[i][0]; + sample_data->frameSpaceCorners[i][1] = corners[i][1]; } } } @@ -177,18 +197,44 @@ void PlaneDistortMaskOperation::initExecution() void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { float point[2]; - int inside_counter = 0; - for (int sample = 0; sample < this->m_osa; sample++) { - point[0] = x + this->m_jitter[sample][0]; - point[1] = y + this->m_jitter[sample][1]; - - if (isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) || - isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3])) + if (this->m_motion_blur_samples == 1) { + MotionSample *sample_data = &this->m_samples[0]; + for (int sample = 0; sample < this->m_osa; sample++) { + point[0] = x + this->m_jitter[sample][0]; + point[1] = y + this->m_jitter[sample][1]; + if (isect_point_tri_v2(point, sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[1], + sample_data->frameSpaceCorners[2]) || + isect_point_tri_v2(point, sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[2], + sample_data->frameSpaceCorners[3])) + { + inside_counter++; + } + } + output[0] = (float)inside_counter / this->m_osa; + } + else { + for (int motion_sample = 0; + motion_sample < this->m_motion_blur_samples; + ++motion_sample) { - inside_counter++; + MotionSample *sample_data = &this->m_samples[motion_sample]; + for (int osa_sample = 0; osa_sample < this->m_osa; ++osa_sample) { + point[0] = x + this->m_jitter[osa_sample][0]; + point[1] = y + this->m_jitter[osa_sample][1]; + if (isect_point_tri_v2(point, sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[1], + sample_data->frameSpaceCorners[2]) || + isect_point_tri_v2(point, sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[2], + sample_data->frameSpaceCorners[3])) + { + inside_counter++; + } + } } + output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples); } - - output[0] = (float) inside_counter / this->m_osa; } diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h index ee2874c6b46..6ceb476f5f9 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h @@ -33,43 +33,68 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#define PLANE_DISTORT_MAX_SAMPLES 64 class PlaneDistortWarpImageOperation : public NodeOperation { protected: + struct MotionSample { + float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ + float perspectiveMatrix[3][3]; + }; SocketReader *m_pixelReader; - float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ - float m_perspectiveMatrix[3][3]; + MotionSample m_samples[PLANE_DISTORT_MAX_SAMPLES]; + int m_motion_blur_samples; + float m_motion_blur_shutter; public: PlaneDistortWarpImageOperation(); - void calculateCorners(const float corners[4][2], bool normalized); - void calculatePerspectiveMatrix(); + void calculateCorners(const float corners[4][2], + bool normalized, + int sample); void initExecution(); void deinitExecution(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); + + void setMotionBlurSamples(int samples) { + BLI_assert(samples <= PLANE_DISTORT_MAX_SAMPLES); + this->m_motion_blur_samples = samples; + } + void setMotionBlurShutter(float shutter) { this->m_motion_blur_shutter = shutter; } }; class PlaneDistortMaskOperation : public NodeOperation { protected: + struct MotionSample { + float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ + }; int m_osa; + MotionSample m_samples[PLANE_DISTORT_MAX_SAMPLES]; float m_jitter[32][2]; - float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ + int m_motion_blur_samples; + float m_motion_blur_shutter; public: PlaneDistortMaskOperation(); - void calculateCorners(const float corners[4][2], bool normalized); + void calculateCorners(const float corners[4][2], + bool normalized, + int sample); void initExecution(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + + void setMotionBlurSamples(int samples) { + BLI_assert(samples <= PLANE_DISTORT_MAX_SAMPLES); + this->m_motion_blur_samples = samples; + } + void setMotionBlurShutter(float shutter) { this->m_motion_blur_shutter = shutter; } }; #endif diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp index fec39cbfde0..f6152981ee7 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp @@ -46,7 +46,7 @@ PlaneTrackCommon::PlaneTrackCommon() this->m_planeTrackName[0] = '\0'; } -void PlaneTrackCommon::readCornersFromTrack(float corners[4][2]) +void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame) { MovieTracking *tracking; MovieTrackingObject *object; @@ -64,13 +64,13 @@ void PlaneTrackCommon::readCornersFromTrack(float corners[4][2]) if (plane_track) { MovieTrackingPlaneMarker *plane_marker; - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber); - + float clip_framenr = + BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, + frame); plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); - copy_v2_v2(corners[0], plane_marker->corners[0]); - copy_v2_v2(corners[1], plane_marker->corners[1]); - copy_v2_v2(corners[2], plane_marker->corners[2]); - copy_v2_v2(corners[3], plane_marker->corners[3]); + BKE_tracking_plane_marker_get_subframe_corners(plane_track, + clip_framenr, + corners); } } } @@ -98,10 +98,21 @@ void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned void PlaneTrackMaskOperation::initExecution() { PlaneDistortMaskOperation::initExecution(); - float corners[4][2]; - readCornersFromTrack(corners); - calculateCorners(corners, true); + if (this->m_motion_blur_samples == 1) { + readCornersFromTrack(corners, this->m_framenumber); + calculateCorners(corners, true, 0); + } + else { + const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter; + const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples; + float frame_iter = frame; + for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) { + readCornersFromTrack(corners, frame_iter); + calculateCorners(corners, true, sample); + frame_iter += frame_step; + } + } } /* ******** PlaneTrackWarpImageOperation ******** */ @@ -109,9 +120,20 @@ void PlaneTrackMaskOperation::initExecution() void PlaneTrackWarpImageOperation::initExecution() { PlaneDistortWarpImageOperation::initExecution(); - + /* TODO(sergey): De-duplicate with mask operation. */ float corners[4][2]; - readCornersFromTrack(corners); - calculateCorners(corners, true); - calculatePerspectiveMatrix(); + if (this->m_motion_blur_samples == 1) { + readCornersFromTrack(corners, this->m_framenumber); + calculateCorners(corners, true, 0); + } + else { + const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter; + const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples; + float frame_iter = frame; + for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) { + readCornersFromTrack(corners, frame_iter); + calculateCorners(corners, true, sample); + frame_iter += frame_step; + } + } } diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h index 3c5dd783542..b355c64a1ca 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h @@ -43,7 +43,7 @@ protected: /* note: this class is not an operation itself (to prevent virtual inheritance issues) * implementation classes must make wrappers to use these methods, see below. */ - void readCornersFromTrack(float corners[4][2]); + void readCornersFromTrack(float corners[4][2], float frame); void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); public: |