[Bf-blender-cvs] [45d0e3d] PSketch: Pose Sketching: First working prototype of "Direct Mode"

Joshua Leung noreply at git.blender.org
Sun Jan 31 14:28:34 CET 2016


Commit: 45d0e3da51e2fb32ee87a90cce0efbef35decbb4
Author: Joshua Leung
Date:   Tue Sep 1 14:16:12 2015 +1200
Branches: PSketch
https://developer.blender.org/rB45d0e3da51e2fb32ee87a90cce0efbef35decbb4

Pose Sketching: First working prototype of "Direct Mode"

This commit introduces a new tool which allows users to draw the shape that
a chain of bones should form, and have the bones be transformed to fit.

Usage:
1) Select a chain of bones. You must select at least 2 bones, and they should
   ideally be connected (or appear to be) for best results.
2) EKEY to invoke the operator
3) Draw a stroke  (*)
4) Your rig should now be posed

(*) This operator uses Grease Pencil strokes to provide its sketch input.
    Please ensure that strokes are drawn in 3D space (not view), and that
    "Continous Drawing" is not enabled.

The currently implementation is still heavily WIP, and suffers from a number
of limitations. It is also just "simpler" of the two initial algorithms planned.
* It currently only sets the pose_mat values (and the pose_head/tail) values.
  To keyframe any poses made this way, use "Visual Keying" or else the poses
  won't hold.

* There is currently a bug where each subsequent attempt to pose the rig
  will result in incorrect bone alignments. More work is required to figure
  out why this occurs.

===================================================================

M	source/blender/editors/armature/armature_intern.h
M	source/blender/editors/armature/armature_ops.c
A	source/blender/editors/armature/pose_sketch.c

===================================================================

diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 2968851..3161af8 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -210,6 +210,12 @@ void POSE_OT_breakdown(struct wmOperatorType *ot);
 void POSE_OT_propagate(struct wmOperatorType *ot);
 
 /* ******************************************************* */
+/* Pose Sketching/Sculpting Tools */
+
+/* pose_sketch.c */
+void POSE_OT_sketch_direct(struct wmOperatorType *ot);
+
+/* ******************************************************* */
 /* Various Armature Edit/Pose Editing API's */
 
 /* Ideally, many of these defines would not be needed as everything would be strictly self-contained
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index e7f036f..c58486a 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -160,6 +160,9 @@ void ED_operatortypes_armature(void)
 	WM_operatortype_append(POSE_OT_push);
 	WM_operatortype_append(POSE_OT_relax);
 	WM_operatortype_append(POSE_OT_breakdown);
+	
+	/* POSE SKETCHING */
+	WM_operatortype_append(POSE_OT_sketch_direct);
 }
 
 void ED_operatormacros_armature(void)
@@ -191,6 +194,17 @@ void ED_operatormacros_armature(void)
 	RNA_boolean_set(otmacro->ptr, "forked", true);
 	otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
 	RNA_enum_set(otmacro->ptr, "proportional", 0);
+	
+	
+	
+	/* Pose Sketching operators for now must be paired with Grease Pencil ones
+	 * (GPencil first) or else we wouldn't have anything to work with
+	 */
+	ot = WM_operatortype_append_macro("POSE_OT_sketch_direct_interactive", "Sketch Bone Chain Pose",
+	                                  "Interactively sketch the pose for the selected bones",
+	                                  OPTYPE_UNDO | OPTYPE_REGISTER);
+	otmacro = WM_operatortype_macro_define(ot, "GPENCIL_OT_draw");
+	otmacro = WM_operatortype_macro_define(ot, "POSE_OT_sketch_direct");
 }
 
 void ED_keymap_armature(wmKeyConfig *keyconf)
@@ -411,6 +425,13 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
 	WM_keymap_add_item(keymap, "POSE_OT_push", EKEY, KM_PRESS, KM_CTRL, 0);
 	WM_keymap_add_item(keymap, "POSE_OT_relax", EKEY, KM_PRESS, KM_ALT, 0);
 	WM_keymap_add_item(keymap, "POSE_OT_breakdown", EKEY, KM_PRESS, KM_SHIFT, 0);
+	
+	
+	/* Pose -> Pose Sketching ----------- */
+	/* only set in posemode, by space_view3d listener */
+	
+	// XXX: temporary mappings
+	WM_keymap_add_item(keymap, "POSE_OT_sketch_direct_interactive", EKEY, KM_PRESS, 0, 0);
 
 	/* menus */
 	WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/armature/pose_sketch.c b/source/blender/editors/armature/pose_sketch.c
new file mode 100644
index 0000000..1284fba
--- /dev/null
+++ b/source/blender/editors/armature/pose_sketch.c
@@ -0,0 +1,509 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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.
+*
+* The Original Code is Copyright (C) 2014 Blender Foundation, Joshua Leung
+* 
+* Original Author: Joshua Leung
+* Contributor(s): Joshua Leung
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Sketch-based posing tools for armatures
+*
+*/
+/** \file blender/editors/armature/pose_sketch.c
+* \ingroup edarmature
+*/
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+//#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_report.h"
+
+#include "ED_armature.h"
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+
+#include "armature_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* ***************************************************** */
+/* Simple "Direct-Sketch" operator:
+ * This operator assumes that the sketched line directly corresponds to
+ * a bone chain, allowing us to directly map the bones to the sketched
+ * line (using parametric positions).
+ *
+ * For now, this just uses Grease Pencil to provide the sketching functionality,
+ * letting us focus on testing out the deformations-side of things.
+ *
+ * To simplify things further for the initial prototype, the actual keymapped tool
+ * will just be a macro binding together Grease Pencil paint (one sketch) + this operator
+ */
+
+/* ---------------------------------------------------------------- */
+
+/* Helper - Logic for which bones to include */
+static bool psketch_direct_bone_can_include(bPoseChannel *pchan, bPoseChannel *prev_pchan)
+{
+	// XXX: potential bug with non-connected bones - we don't want to skip across that boundary for now...
+	return ((prev_pchan == NULL) || (pchan->parent == prev_pchan));
+}
+
+
+/* Simplified GPencil stroke point, ready for pose matching */
+typedef struct tGPStrokePosePoint {
+	float co[3];	/* pose-space coordinates of this point */
+	int index;		/* original index of this point in the stroke */
+} tGPStrokePosePoint;
+
+/* Figure out where each joint should fit along the stroke 
+ *
+ * The algorithm used here is roughly based on the technique
+ * used in anim.c : calc_curvepath()
+ */
+static tGPStrokePosePoint *psketch_stroke_to_points(Object *ob, bGPDstroke *stroke, 
+                                                    float *joint_dists, size_t num_joints, 
+                                                    bool reversed)
+{
+	tGPStrokePosePoint *result = MEM_callocN(sizeof(tGPStrokePosePoint) * num_joints, "tGPStrokePosePoints");
+	tGPStrokePosePoint *pt;
+	
+	float *distances = MEM_callocN(sizeof(float) * stroke->totpoints, "psketch stroke distances"); // XXX: wrong length
+	float totlen = 0.0f;
+	int i;
+	
+	/* 1) Compute total length of stroke, and the cumulative distance that each point sits at */
+	/* NOTE: We start at i = 1, as distances[0] = 0 = totlen */
+	for (i = 1; i < stroke->totpoints; i++) {		
+		bGPDspoint *p2 = &stroke->points[i];
+		bGPDspoint *p1 = &stroke->points[i - 1];
+		
+		totlen += len_v3v3(&p1->x, &p2->x);
+		distances[i] = totlen;
+		
+		// xxx: debug: unselect all points so that the only selected ones are the ones we want
+		p1->flag &= ~GP_SPOINT_SELECT;
+		p2->flag &= ~GP_SPOINT_SELECT;
+	}
+	
+	// XXX: prevent divbyzero
+	printf("totlen = %f\n", totlen);
+	if (totlen < 0.00001f)
+		totlen = 1.0f;
+	
+	/* 2) Compute each stroke point */
+	// XXX: assume ob->imat is initialised already
+	for (i = 0, pt = result; i < num_joints; i++, pt++) {
+		bGPDspoint *sp, *prev;
+		float dist, dist_prev;
+		float fac1, fac2;
+		float d;
+		int j;
+		bool found = false;
+		
+		/* Get the distance that this stroke point is supposed to represent */
+		/* NOTE: Multiplying the target distance out may lead to precision issues,
+		 * but at least we don't need to do O(n) divides - one per poitn!
+		 */
+		if (reversed) {
+			/* Reverse Order - ith joint from end/tail of chain */
+			d = joint_dists[num_joints - i - 1] * totlen;
+		}
+		else {
+			/* Forward Order - ith joint from start/head of chain, normal order */
+			d = joint_dists[i] * totlen;
+		}
+		
+		/* Go through stroke points searching for the one where the distance
+		 * is greater than the current joint requires.
+		 *
+		 * NOTE: We start from the second point, so that we can calc the difference
+		 *       between those and interpolate coordinates as required...
+		 */
+		for (j = 1, sp = stroke->points + 1;
+		     j < stroke->totpoints;
+		     j++, sp++)
+		{
+			if (d < distances[j]) {
+				/* we just passed the point we need to use */
+				found = true;
+				break;
+			}
+		}
+		
+		if (found == false) {
+			/* assume this is the last point */
+			j = stroke->totpoints - 1;
+			sp = &stroke->points[j];
+		}
+
+		dist_prev = distances[j - 1];
+		prev = sp - 1;
+		
+		if (fabsf(dist - dist_prev) > 0.00001f) {
+			fac1 = (dist - d) / (dist - dist_prev);
+			fac2 = 1.0f - fac1;
+		}
+		else {
+			// XXX?
+			fac1 = 1.0f;
+			fac2 = 0.0f;
+		}
+		
+		/* Convert stroke coordinate to pose-space */
+		interp_v3_v3v3(pt->co, &prev->x, &sp->x, fac2);
+		mul_m4_v3(ob->imat, pt->co);
+		
+		/* Store index of point(s) from stroke that correspond to this */
+		pt->index = j; // XXX
+		
+		// XXX: debug... for seeing which points were involved
+		sp->flag |= GP_SPOINT_SELECT;
+		prev->flag |= GP_SPOINT_SELECT;
+	}
+	
+	// XXX: debugging...
+	stroke->flag |= GP_STROKE_SELECT;
+	
+	/* Free temp data and return the stroke points array */
+	MEM_freeN(distances);
+	return result;
+}
+
+
+/* Adaptation of "Direct Mode" technique from Oztireli et al. (2013) */
+static int psketch_direct_exec(bContext *C, wmOperator *op)
+{
+	Scene *scene = CTX_data_scene(C);
+	Object *ob = CTX_data_active_object(C);
+	
+	bGPdata *gpd = ED_gpencil_data_get_active(C);
+	bGPDlayer *gpl = gpencil_layer_getactive(gpd); // XXX: this assumes that any layer will do, as long as user drew in it recently
+	bGPDframe *gpf = (gpl) ? gpl->actframe : NULL;
+	bGPDstroke *stroke = (gpf) ? gpf->strokes.last : NULL;
+	
+	floa

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list