Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2014-03-11 17:07:49 +0400
committerLukas Tönne <lukas.toenne@gmail.com>2014-03-11 17:12:08 +0400
commit658b4c0d56dffbcf1476c2a2a019fa0ecfb79376 (patch)
tree28fb8dd6b9a3bedf6d95e9e7737e3753b7308e90 /source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
parent558fa43ffd5bb1c4950855bd07450841664e89aa (diff)
New Corner Pin node: uses explicit corner values for a plane warp transformation.
This was suggested by Christopher Barrett (terrachild). Corner pin is a common feature in compositing. The corners for the plane warping can be defined by using vector node inputs to allow using perspective plane transformations without having to go via the MovieClip editor tracking data. Uses the same math as the PlaneTrack node, but without the link to MovieClip and Object. {F78199} The code for PlaneTrack operations has been restructured a bit to share it with the CornerPin node. * PlaneDistortCommonOperation.h/.cpp: Shared generic code for warping images based on 4 plane corners and a perspective matrix generated from these. Contains operation base classes for both the WarpImage and Mask operations. * PlaneTrackOperation.h/.cpp: Current plane track node operations, based on the common code above. These add pointers to MovieClip and Object which define the track data from wich to read the corners. * PlaneCornerPinOperation.h/.cpp: New corner pin variant, using explicit input sockets for the plane corners. One downside of the current compositor design is that there is no concept of invariables (constants) that don't vary over the image space. This has already been an issue for Blur nodes (size input is usually constant except when "variable size" is enabled) and a few others. For the corner pin node it is necessary that the corner input sockets are also invariant. They have to be evaluated for each tile now, otherwise the data is not available. This in turn makes it necessary to make the operation "complex" and request full input buffers, which adds unnecessary overhead.
Diffstat (limited to 'source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp')
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
new file mode 100644
index 00000000000..fe272000b6e
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ * Lukas Toenne
+ */
+
+#include "COM_PlaneCornerPinOperation.h"
+#include "COM_ReadBufferOperation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+
+extern "C" {
+# include "BLI_jitter.h"
+
+# include "BKE_node.h"
+}
+
+static bool check_corners(float corners[4][2])
+{
+ int i, next, prev;
+ float cross = 0.0f;
+
+ for (i = 0; i < 4; i++) {
+ float v1[2], v2[2], cur_cross;
+
+ next = (i + 1) % 4;
+ prev = (4 + i - 1) % 4;
+
+ sub_v2_v2v2(v1, corners[i], corners[prev]);
+ sub_v2_v2v2(v2, corners[next], corners[i]);
+
+ cur_cross = cross_v2v2(v1, v2);
+ if (fabsf(cur_cross) <= FLT_EPSILON)
+ return false;
+
+ if (cross == 0.0f)
+ cross = cur_cross;
+ else if (cross * cur_cross < 0.0f)
+ return false;
+ }
+
+ return true;
+}
+
+static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2])
+{
+ for (int i = 0; i < 4; ++i) {
+ float result[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST);
+ corners[i][0] = result[0];
+ corners[i][1] = result[1];
+ }
+
+ /* convexity check:
+ * concave corners need to be prevented, otherwise
+ * BKE_tracking_homography_between_two_quads will freeze
+ */
+ if (!check_corners(corners)) {
+ /* simply revert to default corners
+ * there could be a more elegant solution,
+ * this prevents freezing at least.
+ */
+ corners[0][0] = 0.0f; corners[0][1] = 0.0f;
+ corners[1][0] = 1.0f; corners[1][1] = 0.0f;
+ corners[2][0] = 1.0f; corners[2][1] = 1.0f;
+ corners[3][0] = 0.0f; corners[3][1] = 1.0f;
+ }
+}
+
+
+/* ******** PlaneCornerPinMaskOperation ******** */
+
+PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() :
+ PlaneDistortMaskOperation(),
+ m_corners_ready(false)
+{
+ addInputSocket(COM_DT_VECTOR);
+ addInputSocket(COM_DT_VECTOR);
+ addInputSocket(COM_DT_VECTOR);
+ addInputSocket(COM_DT_VECTOR);
+
+ /* XXX this is stupid: we need to make this "complex",
+ * so we can use the initializeTileData function
+ * to read corners from input sockets ...
+ */
+ setComplex(true);
+}
+
+void PlaneCornerPinMaskOperation::initExecution()
+{
+ PlaneDistortMaskOperation::initExecution();
+
+ initMutex();
+}
+
+void PlaneCornerPinMaskOperation::deinitExecution()
+{
+ PlaneDistortMaskOperation::deinitExecution();
+
+ deinitMutex();
+}
+
+void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect)
+{
+ void *data = PlaneDistortMaskOperation::initializeTileData(rect);
+
+ /* get corner values once, by reading inputs at (0,0)
+ * XXX this assumes invariable values (no image inputs),
+ * we don't have a nice generic system for that yet
+ */
+ lockMutex();
+ if (!m_corners_ready) {
+ SocketReader *readers[4] = { getInputSocketReader(0),
+ getInputSocketReader(1),
+ getInputSocketReader(2),
+ getInputSocketReader(3) };
+ float corners[4][2];
+ readCornersFromSockets(rect, readers, corners);
+ calculateCorners(corners, true);
+
+ m_corners_ready = true;
+ }
+ unlockMutex();
+
+ return data;
+}
+
+void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+{
+ resolution[0] = preferredResolution[0];
+ resolution[1] = preferredResolution[1];
+}
+
+
+/* ******** PlaneCornerPinWarpImageOperation ******** */
+
+PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() :
+ PlaneDistortWarpImageOperation(),
+ m_corners_ready(false)
+{
+ addInputSocket(COM_DT_VECTOR);
+ addInputSocket(COM_DT_VECTOR);
+ addInputSocket(COM_DT_VECTOR);
+ addInputSocket(COM_DT_VECTOR);
+}
+
+void PlaneCornerPinWarpImageOperation::initExecution()
+{
+ PlaneDistortWarpImageOperation::initExecution();
+
+ initMutex();
+}
+
+void PlaneCornerPinWarpImageOperation::deinitExecution()
+{
+ PlaneDistortWarpImageOperation::deinitExecution();
+
+ deinitMutex();
+}
+
+void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect)
+{
+ void *data = PlaneDistortWarpImageOperation::initializeTileData(rect);
+
+ /* get corner values once, by reading inputs at (0,0)
+ * XXX this assumes invariable values (no image inputs),
+ * we don't have a nice generic system for that yet
+ */
+ lockMutex();
+ if (!m_corners_ready) {
+ /* corner sockets start at index 1 */
+ SocketReader *readers[4] = { getInputSocketReader(1),
+ getInputSocketReader(2),
+ getInputSocketReader(3),
+ getInputSocketReader(4) };
+ float corners[4][2];
+ readCornersFromSockets(rect, readers, corners);
+ calculateCorners(corners, true);
+ calculatePerspectiveMatrix();
+
+ m_corners_ready = true;
+ }
+ unlockMutex();
+
+ return data;
+}
+
+bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+{
+ for (int i = 0; i < 4; ++i)
+ if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output))
+ return true;
+
+ /* XXX this is bad, but unavoidable with the current design:
+ * we don't know the actual corners and matrix at this point,
+ * so all we can do is get the full input image
+ */
+ output->xmin = 0;
+ output->ymin = 0;
+ output->xmax = getInputOperation(0)->getWidth();
+ output->ymax = getInputOperation(0)->getHeight();
+ return true;
+// return PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(input, readOperation, output);
+}