[Bf-blender-cvs] [5765dee] master: GPencil: New option to lock strokes to axis

Antonioya noreply at git.blender.org
Sat Oct 22 16:45:10 CEST 2016


Commit: 5765deecd42eedda780b88ed7448e4b1c185d0d8
Author: Antonioya
Date:   Sat Oct 22 16:44:11 2016 +0200
Branches: master
https://developer.blender.org/rB5765deecd42eedda780b88ed7448e4b1c185d0d8

GPencil: New option to lock strokes to axis

Now, the strokes can be locked to a plane set in the cursor location.
This option allow the artist to rotate the view and draw keeping the
strokes flat over the surface. This option is similar to surface option
but doesn't need a object.

The option is only valid for 3D view and strokes in CURSOR mode.

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

M	release/scripts/startup/bl_ui/properties_grease_pencil_common.py
M	source/blender/editors/gpencil/gpencil_paint.c
M	source/blender/makesdna/DNA_scene_types.h
M	source/blender/makesrna/intern/rna_sculpt_paint.c

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

diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 84442f9..bc40932 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -52,6 +52,12 @@ def gpencil_stroke_placement_settings(context, layout):
         row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'}
         row.prop(ts, "use_gpencil_stroke_endpoints")
 
+        if context.scene.tool_settings.gpencil_stroke_placement_view3d == 'CURSOR':
+            row = col.row(align=True)
+            row.label("Lock axis:")
+            row = col.row(align=True)
+            row.prop(ts.gpencil_sculpt, "lockaxis", expand=True)
+
 
 def gpencil_active_brush_settings_simple(context, layout):
     brush = context.active_gpencil_brush
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index cc45cbd..c23bfb1 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -40,6 +40,7 @@
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 #include "BLI_rand.h"
+#include "BLI_math_geom.h"
 
 #include "BLT_translation.h"
 
@@ -160,6 +161,7 @@ typedef struct tGPsdata {
 	bGPDpalettecolor *palettecolor; /* current palette color */
 	bGPDbrush *brush; /* current drawing brush */
 	short straight[2];   /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
+	int lock_axis;       /* lock drawing to one axis */
 } tGPsdata;
 
 /* ------ */
@@ -278,6 +280,64 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
 		return false;
 }
 
+/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */
+static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
+{
+	float plane_normal[3];
+	float vn[3];
+
+	float ray[3];
+	float rpoint[3];
+
+	/* normal vector for a plane locked to axis */
+	zero_v3(plane_normal);
+	plane_normal[axis] = 1.0f;
+
+	/* Reproject the points in the plane */
+	for (int i = 0; i < gps->totpoints; i++) {
+		bGPDspoint *pt = &gps->points[i];
+
+		/* get a vector from the point with the current view direction of the viewport */
+		ED_view3d_global_to_vector(rv3d, &pt->x, vn);
+
+		/* calculate line extrem point to create a ray that cross the plane */
+		mul_v3_fl(vn, -50.0f);
+		add_v3_v3v3(ray, &pt->x, vn);
+
+		/* if the line never intersect, the point is not changed */
+		if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+			copy_v3_v3(&pt->x, rpoint);
+		}
+	}
+}
+
+/* reproject stroke to plane locked to axis in 3d cursor location */
+static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
+{
+	bGPdata *gpd = p->gpd;
+	float origin[3];
+	float cursor[3];
+	RegionView3D *rv3d = p->ar->regiondata;
+
+	/* verify the stroke mode is CURSOR 3d space mode */
+	if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
+		return;
+	}
+	if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+		return;
+	}
+	if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) {
+		return;
+	}
+
+	/* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
+	gp_get_3d_reference(p, cursor);
+	zero_v3(origin);
+	origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
+
+	gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+}
+
 /* convert screen-coordinates to buffer-coordinates */
 /* XXX this method needs a total overhaul! */
 static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
@@ -581,6 +641,10 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
 			
 			/* convert screen-coordinates to appropriate coordinates (and store them) */
 			gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+			/* if axis locked, reproject to plane locked (only in 3d space) */
+			if (p->lock_axis > GP_LOCKAXIS_NONE) {
+				gp_reproject_toplane(p, gps);
+			}
 			/* if parented change position relative to parent object */
 			if (gpl->parent != NULL) {
 				gp_apply_parent_point(gpl, pts);
@@ -679,7 +743,6 @@ static void gp_stroke_simplify(tGPsdata *p)
 	MEM_freeN(old_points);
 }
 
-
 /* make a new stroke from the buffer data */
 static void gp_stroke_newfrombuffer(tGPsdata *p)
 {
@@ -756,6 +819,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 			
 			/* convert screen-coordinates to appropriate coordinates (and store them) */
 			gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+			/* if axis locked, reproject to plane locked (only in 3d space) */
+			if (p->lock_axis > GP_LOCKAXIS_NONE) {
+				gp_reproject_toplane(p, gps);
+			}
 			/* if parented change position relative to parent object */
 			if (gpl->parent != NULL) {
 				gp_apply_parent_point(gpl, pt);
@@ -775,6 +842,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 			
 			/* convert screen-coordinates to appropriate coordinates (and store them) */
 			gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+			/* if axis locked, reproject to plane locked (only in 3d space) */
+			if (p->lock_axis > GP_LOCKAXIS_NONE) {
+				gp_reproject_toplane(p, gps);
+			}
 			/* if parented change position relative to parent object */
 			if (gpl->parent != NULL) {
 				gp_apply_parent_point(gpl, pt);
@@ -793,6 +864,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 		
 		/* convert screen-coordinates to appropriate coordinates (and store them) */
 		gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+		/* if axis locked, reproject to plane locked (only in 3d space) */
+		if (p->lock_axis > GP_LOCKAXIS_NONE) {
+			gp_reproject_toplane(p, gps);
+		}
 		/* if parented change position relative to parent object */
 		if (gpl->parent != NULL) {
 			gp_apply_parent_point(gpl, pt);
@@ -805,30 +880,30 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 	}
 	else {
 		float *depth_arr = NULL;
-		
+
 		/* get an array of depths, far depths are blended */
 		if (gpencil_project_check(p)) {
-			int mval[2], mval_prev[2] = {0};
+			int mval[2], mval_prev[2] = { 0 };
 			int interp_depth = 0;
 			int found_depth = 0;
-			
+
 			depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
-			
+
 			for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
 				copy_v2_v2_int(mval, &ptc->x);
-				
+
 				if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
-				    (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
+					(i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
 				{
 					interp_depth = true;
 				}
 				else {
 					found_depth = true;
 				}
-				
+
 				copy_v2_v2_int(mval_prev, mval);
 			}
-			
+
 			if (found_depth == false) {
 				/* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
 				for (i = gpd->sbuffer_size - 1; i >= 0; i--)
@@ -839,54 +914,54 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 					/* remove all info between the valid endpoints */
 					int first_valid = 0;
 					int last_valid = 0;
-					
+
 					for (i = 0; i < gpd->sbuffer_size; i++) {
 						if (depth_arr[i] != FLT_MAX)
 							break;
 					}
 					first_valid = i;
-					
+
 					for (i = gpd->sbuffer_size - 1; i >= 0; i--) {
 						if (depth_arr[i] != FLT_MAX)
 							break;
 					}
 					last_valid = i;
-					
+
 					/* invalidate non-endpoints, so only blend between first and last */
 					for (i = first_valid + 1; i < last_valid; i++)
 						depth_arr[i] = FLT_MAX;
-					
+
 					interp_depth = true;
 				}
-				
+
 				if (interp_depth) {
 					interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX);
 				}
 			}
 		}
-		
-		
+
+
 		pt = gps->points;
-		
+
 		/* convert all points (normal behavior) */
 		for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
 			/* convert screen-coordinates to appropriate coordinates (and store them) */
 			gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
-			
+
 			/* copy pressure and time */
 			pt->pressure = ptc->pressure;
 			pt->strength = ptc->strength;
 			CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
 			pt->time = ptc->time;
 		}
-		
+
 		/* subdivide the stroke */
 		if (sublevel > 0) {
 			int totpoints = gps->totpoints;
 			for (i = 0; i < sublevel; i++) {
 				/* we're adding one new point between each pair of verts on each step */
 				totpoints += totpoints - 1;
-				
+
 				gp_subdivide_stroke(gps, totpoints);
 			}
 		}
@@ -895,8 +970,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 			gp_randomize_stroke(gps, brush);
 		}
 
-		/* smooth stroke after subdiv - only if there's something to do 
-		 * for each iteration, the factor is reduced to get a better smoothing without changing too much 
+		/* smooth stroke after subdiv - only if there's something to do
+		 * for each iteration, the factor is reduced to get a better smoothing without changing too much
 		 * the original stroke
 		 */
 		if (brush->draw_smoothfac > 0.0f) {
@@ -909,6 +984,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
 				reduce += 0.25f;  // reduce the factor
 			}
 		}
+
+		/* if axis locked, reproject to plane locked (only in 3d space) */
+		if (p->lock_axis > GP_LOCKAXIS_NONE) {
+			gp_reproject_toplane(p, gps);
+		}
 		/* if parented change position relative to parent object */
 		if (gpl->parent != NULL) {
 			gp_apply_parent(gpl, gps);
@@ -1467,6 +1547,8 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
 	bGPdata *pdata = p->gpd;
 	copy_v4_v4(pdata->scolor, palcolor->color);
 	pdata->sflag = palcolor->flag;
+	/* lock axis */
+	p->lock_axis = ts->gp_sculpt.lock_axis;
 
 	return 1;
 }
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 94f2319..9b0781e 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1160,6 +1160,14 @@ typedef enum eGP_EditBrush_Ty

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list