[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [23019] trunk/blender/source/blender: Option to correct for 3D curve twist error.

Campbell Barton ideasman42 at gmail.com
Sat Sep 5 11:54:01 CEST 2009


Revision: 23019
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=23019
Author:   campbellbarton
Date:     2009-09-05 11:54:01 +0200 (Sat, 05 Sep 2009)

Log Message:
-----------
Option to correct for 3D curve twist error. example before and after.
http://www.graphicall.org/ftp/ideasman42/curve_auto_twist.png
Access next to the "3D" edit button.

details...
- open curves use the first points orientation and minimize twist for each new segment.
- cyclic curves calculate the least twist in both directions and blend between them
- AxisAngleToQuat replaced inline code.
- Notice the model on the right now has more even corners. added Vec3ToTangent to arithb.c.

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/intern/curve.c
    trunk/blender/source/blender/blenlib/BLI_arithb.h
    trunk/blender/source/blender/blenlib/intern/arithb.c
    trunk/blender/source/blender/makesdna/DNA_curve_types.h
    trunk/blender/source/blender/src/buttons_editing.c

Modified: trunk/blender/source/blender/blenkernel/intern/curve.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/curve.c	2009-09-05 06:10:30 UTC (rev 23018)
+++ trunk/blender/source/blender/blenkernel/intern/curve.c	2009-09-05 09:54:01 UTC (rev 23019)
@@ -1513,7 +1513,7 @@
 	BPoint *bp;
 	BevList *bl, *blnew, *blnext;
 	BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
-	float min, inp, x1, x2, y1, y2, vec[3];
+	float min, inp, x1, x2, y1, y2, vec[3], vec_prev[3], q[4], quat[4], quat_prev[4], cross[3];
 	float *coord_array, *tilt_array=NULL, *radius_array=NULL, *coord_fp, *tilt_fp=NULL, *radius_fp=NULL;
 	float *v1, *v2;
 	struct bevelsort *sortdata, *sd, *sd1;
@@ -1872,7 +1872,10 @@
 	bl= cu->bev.first;
 	while(bl) {
 	
-		if(bl->nr==2) {	/* 2 pnt, treat separate */
+		if(bl->nr < 2) {
+			/* do nothing */
+		}
+		else if(bl->nr==2) {	/* 2 pnt, treat separate */
 			bevp2= (BevPoint *)(bl+1);
 			bevp1= bevp2+1;
 
@@ -1886,68 +1889,169 @@
 			if(cu->flag & CU_3D) {	/* 3D */
 				float quat[4], q[4];
 			
-				vec[0]= bevp1->x - bevp2->x;
-				vec[1]= bevp1->y - bevp2->y;
-				vec[2]= bevp1->z - bevp2->z;
+				VecSubf(vec, &bevp1->x, &bevp2->x);
 				
 				vectoquat(vec, 5, 1, quat);
 				
-				Normalize(vec);
-				q[0]= (float)cos(0.5*bevp1->alfa);
-				x1= (float)sin(0.5*bevp1->alfa);
-				q[1]= x1*vec[0];
-				q[2]= x1*vec[1];
-				q[3]= x1*vec[2];
+				AxisAngleToQuat(q, vec, bevp1->alfa);
 				QuatMul(quat, q, quat);
 				
 				QuatToMat3(quat, bevp1->mat);
 				Mat3CpyMat3(bevp2->mat, bevp1->mat);
 			}
 
+		}	/* this has to be >2 points */
+		else if(cu->flag & CU_NO_TWIST && cu->flag & CU_3D && bl->poly != -1) {
+
+			/* Special case, cyclic curve with no twisy. tricky... */
+
+			float quat[4], q[4], cross[3];
+
+			/* correcting a cyclic curve is more complicated, need to be corrected from both ends */
+			float *quat_tmp1, *quat_tmp2; /* store a quat in the matrix temporarily */
+			int iter_dir;
+			BevPoint *bevp_start= (BevPoint *)(bl+1);
+
+			/* loop over the points twice, once up, once back, accumulate the quat rotations
+			 * in both directions, then blend them in the 3rd loop and apply the tilt */
+			for(iter_dir = 0; iter_dir < 2; iter_dir++) {
+
+				bevp2= (BevPoint *)(bl+1);
+				bevp1= bevp2+(bl->nr-1);
+				bevp0= bevp1-1;
+
+				nr= bl->nr;
+				while(nr--) {
+	
+					/* Normalizes */
+					Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+					if(bl->nr==nr+1) { /* first time */
+						vectoquat(vec, 5, 1, quat);
+					}
+					else {
+						float angle = NormalizedVecAngle2(vec_prev, vec);
+					
+						if(angle > 0.0f) { /* otherwise we can keep as is */
+							Crossf(cross, vec_prev, vec);
+							AxisAngleToQuat(q, cross, angle);
+							QuatMul(quat, q, quat_prev);
+						}
+						else {
+							QUATCOPY(quat, quat_prev);
+						}
+					}
+					QUATCOPY(quat_prev, quat); /* quat_prev can't have the tilt applied */
+					VECCOPY(vec_prev, vec);
+
+					if(iter_dir==0) { /* up, first time */
+						quat_tmp1= (float *)bevp1->mat;
+
+						bevp0= bevp1;
+						bevp1= bevp2;
+						bevp2++;
+					}
+					else { /* down second time */
+						quat_tmp1= ((float *)bevp1->mat)+4;
+
+						bevp2= bevp1;
+						bevp1= bevp0;
+						bevp0--;
+
+						/* wrap around */
+						if (bevp0 < bevp_start)
+							bevp0= bevp_start+(bl->nr-1);
+					}
+
+					QUATCOPY(quat_tmp1, quat);
+				}
+			}
+
+			/* Now interpolate the 2 quats and apply tilt */
+
+			bevp2= (BevPoint *)(bl+1);
+			bevp1= bevp2+(bl->nr-1);
+			bevp0= bevp1-1;
+
+			nr= bl->nr;
+			while(nr--) {
+
+				Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+				quat_tmp1= (float *)bevp1->mat;
+				quat_tmp2= quat_tmp1+4;
+
+				/* blend the 2 rotations gathered from both directions */
+				QuatInterpol(quat, quat_tmp1, quat_tmp2, 1.0 - (((float)nr)/bl->nr));
+
+				AxisAngleToQuat(q, vec, bevp1->alfa);
+				QuatMul(quat, q, quat);
+				QuatToMat3(quat, bevp1->mat);
+				
+				/* generic */
+				x1= bevp1->x- bevp0->x;
+				x2= bevp1->x- bevp2->x;
+				y1= bevp1->y- bevp0->y;
+				y2= bevp1->y- bevp2->y;
+			
+				calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
+				
+				bevp0= bevp1;
+				bevp1= bevp2;
+				bevp2++;
+			}
 		}
-		else if(bl->nr>2) {
+		else {
+			/* Any curve with 3 or more points */
+
 			bevp2= (BevPoint *)(bl+1);
 			bevp1= bevp2+(bl->nr-1);
 			bevp0= bevp1-1;
 
-		
 			nr= bl->nr;
-	
 			while(nr--) {
-	
+
 				if(cu->flag & CU_3D) {	/* 3D */
-					float quat[4], q[4];
-				
-					vec[0]= bevp2->x - bevp0->x;
-					vec[1]= bevp2->y - bevp0->y;
-					vec[2]= bevp2->z - bevp0->z;
-					
-					Normalize(vec);
 
-					vectoquat(vec, 5, 1, quat);
-					
-					q[0]= (float)cos(0.5*bevp1->alfa);
-					x1= (float)sin(0.5*bevp1->alfa);
-					q[1]= x1*vec[0];
-					q[2]= x1*vec[1];
-					q[3]= x1*vec[2];
+					/* Normalizes */
+					Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+					if(bl->nr==nr+1 || !(cu->flag & CU_NO_TWIST)) { /* first time */
+						vectoquat(vec, 5, 1, quat);
+					}
+					else {
+						float angle = NormalizedVecAngle2(vec_prev, vec);
+
+						if(angle > 0.0f) { /* otherwise we can keep as is */
+							Crossf(cross, vec_prev, vec);
+							AxisAngleToQuat(q, cross, angle);
+							QuatMul(quat, q, quat_prev);
+						}
+						else {
+							QUATCOPY(quat, quat_prev);
+						}
+					}
+					QUATCOPY(quat_prev, quat); /* quat_prev can't have the tilt applied */
+					VECCOPY(vec_prev, vec);
+
+					AxisAngleToQuat(q, vec, bevp1->alfa);
 					QuatMul(quat, q, quat);
-					
 					QuatToMat3(quat, bevp1->mat);
 				}
-				
+
 				x1= bevp1->x- bevp0->x;
 				x2= bevp1->x- bevp2->x;
 				y1= bevp1->y- bevp0->y;
 				y2= bevp1->y- bevp2->y;
-			
+
 				calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
-				
-				
+
+
 				bevp0= bevp1;
 				bevp1= bevp2;
 				bevp2++;
 			}
+
 			/* correct non-cyclic cases */
 			if(bl->poly== -1) {
 				if(bl->nr>2) {

Modified: trunk/blender/source/blender/blenlib/BLI_arithb.h
===================================================================
--- trunk/blender/source/blender/blenlib/BLI_arithb.h	2009-09-05 06:10:30 UTC (rev 23018)
+++ trunk/blender/source/blender/blenlib/BLI_arithb.h	2009-09-05 09:54:01 UTC (rev 23019)
@@ -270,6 +270,7 @@
 void RotationBetweenVectorsToQuat(float *q, float v1[3], float v2[3]);
 void vectoquat(float *vec, short axis, short upflag, float *q);
 
+void Vec3ToTangent(float *v, float *v1, float *v2, float *v3);
 float VecAngle2(float *v1, float *v2);
 float VecAngle3(float *v1, float *v2, float *v3);
 float NormalizedVecAngle2(float *v1, float *v2);

Modified: trunk/blender/source/blender/blenlib/intern/arithb.c
===================================================================
--- trunk/blender/source/blender/blenlib/intern/arithb.c	2009-09-05 06:10:30 UTC (rev 23018)
+++ trunk/blender/source/blender/blenlib/intern/arithb.c	2009-09-05 09:54:01 UTC (rev 23019)
@@ -2969,6 +2969,19 @@
 	}
 }
 
+/* get a direction from 3 vectors that wont depend
+ * on the distance between the points */
+void Vec3ToTangent(float *v, float *v1, float *v2, float *v3)
+{
+	float d_12[3], d_23[3];
+	VecSubf(d_12, v2, v1);
+	VecSubf(d_23, v3, v2);
+	Normalize(d_12);
+	Normalize(d_23);
+	VecAddf(v, d_12, d_23);
+	Normalize(v);
+}
+
 /* Return the angle in degrees between vecs 1-2 and 2-3 in degrees
    If v1 is a shoulder, v2 is the elbow and v3 is the hand,
    this would return the angle at the elbow */

Modified: trunk/blender/source/blender/makesdna/DNA_curve_types.h
===================================================================
--- trunk/blender/source/blender/makesdna/DNA_curve_types.h	2009-09-05 06:10:30 UTC (rev 23018)
+++ trunk/blender/source/blender/makesdna/DNA_curve_types.h	2009-09-05 09:54:01 UTC (rev 23019)
@@ -205,6 +205,8 @@
 #define CU_FAST			512 /* Font: no filling inside editmode */
 #define CU_RETOPO               1024
 
+#define CU_NO_TWIST		4096
+
 /* spacemode */
 #define CU_LEFT			0
 #define CU_MIDDLE		1

Modified: trunk/blender/source/blender/src/buttons_editing.c
===================================================================
--- trunk/blender/source/blender/src/buttons_editing.c	2009-09-05 06:10:30 UTC (rev 23018)
+++ trunk/blender/source/blender/src/buttons_editing.c	2009-09-05 09:54:01 UTC (rev 23019)
@@ -3671,7 +3671,8 @@
 		uiBlockSetCol(block, TH_BUT_SETTING1);
 		uiDefButBitS(block, TOG, CU_BACK, B_MAKEDISP, "Back",	760,115,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled back for extruded/beveled curves");
 		uiDefButBitS(block, TOG, CU_FRONT, B_MAKEDISP, "Front",810,115,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled front for extruded/beveled curves");
-		uiDefButBitS(block, TOG, CU_3D, B_CU3D, "3D",		860,115,50,19, &cu->flag, 0, 0, 0, 0, "Allow Curve to be 3d, it doesn't fill then");
+		uiDefButBitS(block, TOG, CU_3D, B_CU3D, "3D",		860,115,30,19, &cu->flag, 0, 0, 0, 0, "Allow Curve to be 3d, it doesn't fill then");
+		uiDefIconButBitS(block, TOG, CU_NO_TWIST, B_MAKEDISP, ICON_AUTO,	890,115,20,19, &cu->flag, 0.0, 0.0, 0, 0, "Avoid twisting artifacts for 3D beveled/extruded curves");
 	}
 }
 





More information about the Bf-blender-cvs mailing list