[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [51295] trunk/blender: Lattice Editing: Distortion-Free "Flip" Operator

Joshua Leung aligorith at gmail.com
Sat Oct 13 12:42:38 CEST 2012


Revision: 51295
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=51295
Author:   aligorith
Date:     2012-10-13 10:42:38 +0000 (Sat, 13 Oct 2012)
Log Message:
-----------
Lattice Editing: Distortion-Free "Flip" Operator

This operator (Ctrl-F) allows you to flip the lattice coordinates without
inverting the normals of meshes deformed by the lattice (or the lattice's
deformation space for that matter). Unlike the traditional mirror tool, this
tool is aware of the fact that the vertex order for lattice control points
matters, and that simply mirroring the coordinates will only cause the lattice
to have an inverted deform along a particular axis (i.e. it will be scaling by a
negative scaling factor along that axis).

The problems (as I discovered the other day) with having such an inverted
deformation space are that:
- the normals of meshes/objects inside that will be incorrect/flipped (and will
disappear in GLSL shading mode for instance)
- transforming objects deformed by the lattices will become really tricky and
counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to
get desired result)
- it is not always immediately obvious that problems have occurred

Specific use cases this operator is meant to solve:
1) You've created a lattice-based deformer for one cartoonish eye. Now you want
to make the second eye, but want to save some time crafting that basic shape
again but mirrored.
2) You've got an even more finely crafted setup for stretchy-rigs, and now need
to apply it to other parts of the rig.

Notes:
* I've implemented a separate operator for this vs extending/patching mirror
transform tool as it's easier to implement this way, but also because there are
still some cases where the old mirroring seems valid (i.e. you explicitly want
these sort of distortion effects).
* Currently this doesn't take selections into account, as it doesn't seem useful
to do so.

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_ui/space_view3d.py
    trunk/blender/source/blender/editors/object/object_intern.h
    trunk/blender/source/blender/editors/object/object_lattice.c
    trunk/blender/source/blender/editors/object/object_ops.c

Modified: trunk/blender/release/scripts/startup/bl_ui/space_view3d.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_view3d.py	2012-10-13 10:41:34 UTC (rev 51294)
+++ trunk/blender/release/scripts/startup/bl_ui/space_view3d.py	2012-10-13 10:42:38 UTC (rev 51295)
@@ -2147,6 +2147,7 @@
         layout.menu("VIEW3D_MT_transform")
         layout.menu("VIEW3D_MT_mirror")
         layout.menu("VIEW3D_MT_snap")
+        layout.operator_menu_enum("lattice.flip", "axis")
 
         layout.separator()
 

Modified: trunk/blender/source/blender/editors/object/object_intern.h
===================================================================
--- trunk/blender/source/blender/editors/object/object_intern.h	2012-10-13 10:41:34 UTC (rev 51294)
+++ trunk/blender/source/blender/editors/object/object_intern.h	2012-10-13 10:42:38 UTC (rev 51295)
@@ -138,6 +138,7 @@
 /* object_lattice.c */
 void LATTICE_OT_select_all(struct wmOperatorType *ot);
 void LATTICE_OT_make_regular(struct wmOperatorType *ot);
+void LATTICE_OT_flip(struct wmOperatorType *ot);
 
 /* object_group.c */
 void GROUP_OT_create(struct wmOperatorType *ot);

Modified: trunk/blender/source/blender/editors/object/object_lattice.c
===================================================================
--- trunk/blender/source/blender/editors/object/object_lattice.c	2012-10-13 10:41:34 UTC (rev 51294)
+++ trunk/blender/source/blender/editors/object/object_lattice.c	2012-10-13 10:42:38 UTC (rev 51295)
@@ -46,6 +46,7 @@
 #include "DNA_scene_types.h"
 
 #include "RNA_access.h"
+#include "RNA_define.h"
 
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
@@ -167,7 +168,7 @@
 	}
 }
 
-/************************** Operators *************************/
+/************************** Select All Operator *************************/
 
 void ED_setflagsLatt(Object *obedit, int flag)
 {
@@ -254,6 +255,8 @@
 	WM_operator_properties_select_all(ot);
 }
 
+/************************** Make Regular Operator *************************/
+
 static int make_regular_poll(bContext *C)
 {
 	Object *ob;
@@ -300,6 +303,253 @@
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/************************** Flip Verts Operator *************************/
+
+/* flipping options */
+typedef enum eLattice_FlipAxes {
+	LATTICE_FLIP_U = 0,
+	LATTICE_FLIP_V = 1,
+	LATTICE_FLIP_W = 2
+} eLattice_FlipAxes;
+
+/* Helper macro for accessing item at index (u, v, w) 
+ * < lt: (Lattice)
+ * < U: (int) u-axis coordinate of point
+ * < V: (int) v-axis coordinate of point
+ * < W: (int) w-axis coordinate of point
+ * < dimU: (int) number of points per row or number of columns (U-Axis)
+ * < dimV: (int) number of rows (V-Axis)
+ * > returns: (BPoint *) pointer to BPoint at this index
+ */
+#define LATTICE_PT(lt, U, V, W, dimU, dimV)       \
+	( (lt)->def               +                   \
+	  ((dimU) * (dimV)) * (W) +                   \
+	  (dimU) * (V)            +                   \
+	  (U)                                         \
+	)
+	
+/* Flip midpoint value so that relative distances between midpoint and neighbour-pair is maintained
+ * ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes)
+ * - Helper for lattice_flip_exec()
+ */
+static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
+{
+	BPoint *bp;
+	float diff;
+	
+	/* just the point in the middle (unpaired) */
+	bp = LATTICE_PT(lt, u, v, w, lt->pntsu, lt->pntsv);
+	
+	/* flip over axis */
+	diff = mid - bp->vec[axis];
+	bp->vec[axis] = mid + diff;
+}
+
+/* Swap pairs of lattice points along a specified axis
+ * - Helper for lattice_flip_exec()
+ */
+static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
+{
+	BPoint *bpA, *bpB;
+	
+	int numU = lt->pntsu;
+	int numV = lt->pntsv;
+	int numW = lt->pntsw;
+	
+	int u0 = u, u1 = u;
+	int v0 = v, v1 = v;
+	int w0 = w, w1 = w;
+	
+	/* get pair index by just overriding the relevant pair-value
+	 * - "-1" else buffer overflow
+	 */
+	switch (axis) {
+		case LATTICE_FLIP_U:
+			u1 = numU - u - 1;
+			break;
+		case LATTICE_FLIP_V:
+			v1 = numV - v - 1;
+			break;
+		case LATTICE_FLIP_W:
+			w1 = numW - w - 1;
+			break;
+	}
+	
+	/* get points to operate on */
+	bpA = LATTICE_PT(lt, u0, v0, w0, numU, numV);
+	bpB = LATTICE_PT(lt, u1, v1, w1, numU, numV);
+	
+	/* Swap all coordinates, so that flipped coordinates belong to
+	 * the indices on the correct side of the lattice.
+	 *
+	 *   Coords:  (-2 4) |0| (3 4)   --> (3 4) |0| (-2 4) 
+	 *   Indices:  (0,L)     (1,R)   --> (0,L)     (1,R)
+	 */
+	swap_v3_v3(bpA->vec, bpB->vec);
+	
+	/* However, we need to mirror the coordinate values on the axis we're dealing with,
+	 * otherwise we'd have effectively only rotated the points around. If we don't do this,
+	 * we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms
+	 * such as flipped normals, etc.
+	 *
+	 *   Coords:  (3 4) |0| (-2 4)  --\   
+	 *                                 \-> (-3 4) |0| (2 4)
+	 *   Indices: (0,L)     (1,R)   -->     (0,L)     (1,R)
+	 */
+	lattice_flip_point_value(lt, u0, v0, w0, mid, axis);
+	lattice_flip_point_value(lt, u1, v1, w1, mid, axis);
+}
+	
+static int lattice_flip_exec(bContext *C, wmOperator *op)
+{
+	Object *obedit = CTX_data_edit_object(C);
+	Lattice *lt;
+	
+	eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
+	int numU, numV, numW;
+	int totP;
+	
+	float mid = 0.0f;
+	short isOdd = 0;
+	
+	/* get lattice - we need the "edit lattice" from the lattice... confusing... */
+	lt = (Lattice *)obedit->data;
+	lt = lt->editlatt->latt;
+	
+	numU = lt->pntsu;
+	numV = lt->pntsv;
+	numW = lt->pntsw;
+	totP = numU * numV * numW;
+	
+	/* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */
+	switch (axis) {
+		case LATTICE_FLIP_U:
+			isOdd = numU & 1;
+			break;
+		case LATTICE_FLIP_V:
+			isOdd = numV & 1;
+			break;
+		case LATTICE_FLIP_W:
+			isOdd = numW & 1;
+			break;
+			
+		default:
+			printf("lattice_flip(): Unknown flipping axis (%d)\n", axis);
+			return OPERATOR_CANCELLED;
+	}
+	
+	if (isOdd) {
+		BPoint *bp;
+		float avgInv = 1.0f / (float)totP;
+		int i;
+		
+		/* midpoint calculation - assuming that u/v/w are axis-aligned */
+		for (i = 0, bp = lt->def; i < totP; i++, bp++) {
+			mid += bp->vec[axis] * avgInv;
+		}
+	}
+	
+	/* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
+	switch (axis) {
+		case LATTICE_FLIP_U:
+		{
+			int u, v, w;
+			
+			/* v/w strips - front to back, top to bottom */
+			for (w = 0; w < numW; w++) {
+				for (v = 0; v < numV; v++) {
+					/* swap coordinates of pairs of vertices on u */
+					for (u = 0; u < (numU / 2); u++) {
+						lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+					}
+					
+					/* flip u-coordinate of midpoint (i.e. unpaired point on u) */
+					if (isOdd) {
+						u = (numU / 2);
+						lattice_flip_point_value(lt, u, v, w, mid, axis);
+					}
+				}
+			}
+		}
+		break;
+		case LATTICE_FLIP_V:
+		{
+			int u, v, w;
+			
+			/* u/w strips - front to back, left to right */
+			for (w = 0; w < numW; w++) {
+				for (u = 0; u < numU; u++) {
+					/* swap coordinates of pairs of vertices on v */
+					for (v = 0; v < (numV / 2); v++) {
+						lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+					}
+					
+					/* flip v-coordinate of midpoint (i.e. unpaired point on v) */
+					if (isOdd) {
+						v = (numV / 2);
+						lattice_flip_point_value(lt, u, v, w, mid, axis);
+					}
+				}
+			}
+		}
+		break;
+		case LATTICE_FLIP_W:
+		{
+			int u, v, w;
+			
+			for (v = 0; v < numV; v++) {
+				for (u = 0; u < numU; u++) {
+					/* swap coordinates of pairs of vertices on w */
+					for (w = 0; w < (numW / 2); w++) {
+						lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+					}
+					
+					/* flip w-coordinate of midpoint (i.e. unpaired point on w) */
+					if (isOdd) {
+						w = (numW / 2);
+						lattice_flip_point_value(lt, u, v, w, mid, axis);
+					}
+				}
+			}
+		}
+		break;
+		
+		default: /* shouldn't happen, but just in case */
+			break;
+	}
+	
+	/* updates */
+	DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+	WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+	
+	return OPERATOR_FINISHED;
+}
+
+void LATTICE_OT_flip(wmOperatorType *ot)
+{
+	static EnumPropertyItem flip_items[] = {
+		{LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""},
+		{LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""},
+		{LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""},
+		{0, NULL, 0, NULL, NULL}};
+	
+	/* identifiers */
+	ot->name = "Flip (Distortion Free)";
+	ot->description = "Mirror all control points without inverting the lattice deform";
+	ot->idname = "LATTICE_OT_flip";
+	
+	/* api callbacks */
+	ot->poll = ED_operator_editlattice;
+	ot->invoke = WM_menu_invoke;
+	ot->exec = lattice_flip_exec;
+	
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+	
+	/* properties */
+	ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped");
+}
+
 /****************************** Mouse Selection *************************/
 
 static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2])

Modified: trunk/blender/source/blender/editors/object/object_ops.c
===================================================================
--- trunk/blender/source/blender/editors/object/object_ops.c	2012-10-13 10:41:34 UTC (rev 51294)
+++ trunk/blender/source/blender/editors/object/object_ops.c	2012-10-13 10:42:38 UTC (rev 51295)
@@ -211,6 +211,7 @@
 
 	WM_operatortype_append(LATTICE_OT_select_all);
 	WM_operatortype_append(LATTICE_OT_make_regular);
+	WM_operatortype_append(LATTICE_OT_flip);
 
 	WM_operatortype_append(OBJECT_OT_group_add);
 	WM_operatortype_append(OBJECT_OT_group_link);
@@ -424,6 +425,8 @@
 
 	WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
 	
+	WM_keymap_add_item(keymap, "LATTICE_OT_flip", FKEY, KM_PRESS, KM_CTRL, 0);
+	
 	/* menus */
 	WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0);
 




More information about the Bf-blender-cvs mailing list