[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [23129] branches/blender2.5/blender: curve twist

Campbell Barton ideasman42 at gmail.com
Fri Sep 11 17:35:30 CEST 2009


Revision: 23129
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=23129
Author:   campbellbarton
Date:     2009-09-11 17:35:30 +0200 (Fri, 11 Sep 2009)

Log Message:
-----------
curve twist
* added new twist method - "Tangent", suggested by Martin.
  the nice thing about this is its stable no matter how you rotate the data, rotation is local to each segment.
* added smooth option that smooths the twisting (before applying user twist), to workaround Z-Up and Tangent's ugly curve twisting. Id prefer not to have this however it makes tangent much nicer. Possibly tangent can be improved some other way and this can be removed.
  A smooth value of 1.0 will iterate over and smooth the twisting by the resolution value of the spline.
* Minimum-Twist method now corrects for cyclic twist by taking the roll difference between first and last, then increasingly counter rotate each segment over the entire curve. Previously it calculated from both directions and blended them.

details
* BevPoints use quats rather then 3x3 matrix.
* added BevPoint direction "dir" and tangent "tan" used only for 3D curves.
* don't calculate BevPoint->cosa, BevPoint->sina for 3D curves.
* split bevel tilt calculation into functions.
* nurbs curves currently don't generate tangents and wont work with tangent twist method.
* some of the use of quats should be optimized.
* smoothing is not animation safe, the higher the smoothing the higher the likelyhood of flipping.

Modified Paths:
--------------
    branches/blender2.5/blender/release/ui/buttons_data_curve.py
    branches/blender2.5/blender/source/blender/blenkernel/BKE_utildefines.h
    branches/blender2.5/blender/source/blender/blenkernel/intern/curve.c
    branches/blender2.5/blender/source/blender/blenkernel/intern/displist.c
    branches/blender2.5/blender/source/blender/editors/space_view3d/drawobject.c
    branches/blender2.5/blender/source/blender/makesdna/DNA_curve_types.h
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_curve.c

Modified: branches/blender2.5/blender/release/ui/buttons_data_curve.py
===================================================================
--- branches/blender2.5/blender/release/ui/buttons_data_curve.py	2009-09-11 14:56:54 UTC (rev 23128)
+++ branches/blender2.5/blender/release/ui/buttons_data_curve.py	2009-09-11 15:35:30 UTC (rev 23129)
@@ -56,8 +56,7 @@
 
 		if not is_surf:
 			row = layout.row()
-			row.itemR(curve, "curve_2d")			
-			row.itemR(curve, "use_twist_correction")
+			row.itemR(curve, "curve_2d")
 		
 		split = layout.split()
 		
@@ -86,7 +85,12 @@
 			sub.itemR(curve, "resolution_v", text="Preview V")
 			sub.itemR(curve, "render_resolution_v", text="Render V")
 		
+		# XXX - put somewhere nicer.
+		row= layout.row()
+		row.itemR(curve, "twist_mode")
+		row.itemR(curve, "twist_smooth") # XXX - may not be kept
 
+
 #		col.itemL(text="Display:")
 #		col.itemL(text="HANDLES")
 #		col.itemL(text="NORMALS")

Modified: branches/blender2.5/blender/source/blender/blenkernel/BKE_utildefines.h
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/BKE_utildefines.h	2009-09-11 14:56:54 UTC (rev 23128)
+++ branches/blender2.5/blender/source/blender/blenkernel/BKE_utildefines.h	2009-09-11 15:35:30 UTC (rev 23129)
@@ -107,6 +107,7 @@
 #define VECSUB(v1,v2,v3) 	{*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
 #define VECSUB2D(v1,v2,v3) 	{*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
 #define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
+#define VECSUBFAC(v1,v2,v3,fac) {*(v1)= *(v2) - *(v3)*(fac); *(v1+1)= *(v2+1) - *(v3+1)*(fac); *(v1+2)= *(v2+2) - *(v3+2)*(fac);}
 #define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);}
 
 #define INPR(v1, v2)		( (v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2] )

Modified: branches/blender2.5/blender/source/blender/blenkernel/intern/curve.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/intern/curve.c	2009-09-11 14:56:54 UTC (rev 23128)
+++ branches/blender2.5/blender/source/blender/blenkernel/intern/curve.c	2009-09-11 15:35:30 UTC (rev 23129)
@@ -975,8 +975,27 @@
  		q1+= q2;
  		q2+= q3;
  	}
-}	
+}
 
+void forward_diff_bezier_cotangent(float *p0, float *p1, float *p2, float *p3, float *p, int it, int stride)
+{
+	/* note that these are not purpendicular to the curve
+	 * they need to be rotated for this,
+	 *
+	 * This could also be optimized like forward_diff_bezier */
+	int a;
+  	for(a=0; a<=it; a++) {
+		float t = (float)a / (float)it;
+
+		int i;
+		for(i=0; i<3; i++) {
+			p[i]= (-6*t + 6)*p0[i] + (18*t - 12)*p1[i] + (-18*t + 6)*p2[i] + (6*t)*p3[i];
+		}
+		Normalize(p);
+		p = (float *)(((char *)p)+stride);
+ 	}
+}
+
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
 float *make_orco_surf(Object *ob)
@@ -1545,6 +1564,348 @@
 	}
 }
 
+/* make_bevel_list_3D_* funcs, at a minimum these must
+ * fill in the bezp->quat and bezp->dir values */
+
+/* correct non-cyclic cases by copying direction and rotation
+ * values onto the first & last end-points */
+static void bevel_list_cyclic_fix(BevList *bl)
+{
+	BevPoint *bevp, *bevp1;
+
+	bevp= (BevPoint *)(bl+1);
+	bevp1= bevp+1;
+	QUATCOPY(bevp->quat, bevp1->quat);
+	VECCOPY(bevp->dir, bevp1->dir);
+	VECCOPY(bevp->tan, bevp1->tan);
+	bevp= (BevPoint *)(bl+1);
+	bevp+= (bl->nr-1);
+	bevp1= bevp-1;
+	QUATCOPY(bevp->quat, bevp1->quat);
+	VECCOPY(bevp->dir, bevp1->dir);
+	VECCOPY(bevp->tan, bevp1->tan);
+}
+/* utility for make_bevel_list_3D_* funcs */
+static void bevel_list_calc_bisect(BevList *bl)
+{
+	BevPoint *bevp2, *bevp1, *bevp0;
+	int nr;
+
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	nr= bl->nr;
+	while(nr--) {
+		/* totally simple */
+		VecBisect3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+}
+static void bevel_list_flip_tangents(BevList *bl)
+{
+	BevPoint *bevp2, *bevp1, *bevp0;
+	int nr;
+
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	nr= bl->nr;
+	while(nr--) {
+		if(VecAngle2(bevp0->tan, bevp1->tan) > 90)
+			VecNegf(bevp1->tan);
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+}
+/* apply user tilt */
+static void bevel_list_apply_tilt(BevList *bl)
+{
+	BevPoint *bevp2, *bevp1, *bevp0;
+	int nr;
+	float q[4];
+
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	nr= bl->nr;
+	while(nr--) {
+		AxisAngleToQuat(q, bevp1->dir, bevp1->alfa);
+		QuatMul(bevp1->quat, q, bevp1->quat);
+		NormalQuat(bevp1->quat);
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+}
+/* smooth quats, this function should be optimized, it can get slow with many iterations. */
+static void bevel_list_smooth(BevList *bl, int smooth_iter)
+{
+	BevPoint *bevp2, *bevp1, *bevp0;
+	int nr;
+
+	float q[4];
+	float bevp0_quat[4];
+	int a;
+
+	for(a=0; a < smooth_iter; a++) {
+
+		bevp2= (BevPoint *)(bl+1);
+		bevp1= bevp2+(bl->nr-1);
+		bevp0= bevp1-1;
+
+		nr= bl->nr;
+
+		if(bl->poly== -1) { /* check its not cyclic */
+			/* skip the first point */
+			bevp0= bevp1;
+			bevp1= bevp2;
+			bevp2++;
+			nr--;
+
+			bevp0= bevp1;
+			bevp1= bevp2;
+			bevp2++;
+			nr--;
+
+		}
+
+		QUATCOPY(bevp0_quat, bevp0->quat);
+
+		while(nr--) {
+			/* interpolate quats */
+			float zaxis[3] = {0,0,1}, cross[3], q2[4];
+			QuatInterpol(q, bevp0_quat, bevp2->quat, 0.5);
+			NormalQuat(q);
+
+			QuatMulVecf(q, zaxis);
+			Crossf(cross, zaxis, bevp1->dir);
+			AxisAngleToQuat(q2, cross, NormalizedVecAngle2(zaxis, bevp1->dir));
+			NormalQuat(q2);
+
+			QUATCOPY(bevp0_quat, bevp1->quat);
+			QuatMul(q, q2, q);
+			QuatInterpol(bevp1->quat, bevp1->quat, q, 0.5);
+			NormalQuat(bevp1->quat);
+
+
+			bevp0= bevp1;
+			bevp1= bevp2;
+			bevp2++;
+		}
+	}
+}
+
+static void make_bevel_list_3D_zup(BevList *bl)
+{
+	BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+	int nr;
+
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	nr= bl->nr;
+	while(nr--) {
+		/* totally simple */
+		VecBisect3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
+		vectoquat(bevp1->dir, 5, 1, bevp1->quat);
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+}
+
+static void make_bevel_list_3D_minimum_twist(BevList *bl)
+{
+	BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+	int nr;
+	float q[4];
+
+	float cross_tmp[3];
+
+	bevel_list_calc_bisect(bl);
+
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	nr= bl->nr;
+	while(nr--) {
+
+		if(nr+4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
+			vectoquat(bevp1->dir, 5, 1, bevp1->quat);
+		}
+		else {
+			float angle= NormalizedVecAngle2(bevp0->dir, bevp1->dir);
+
+			if(angle > 0.0f) { /* otherwise we can keep as is */
+				Crossf(cross_tmp, bevp0->dir, bevp1->dir);
+				AxisAngleToQuat(q, cross_tmp, angle);
+				QuatMul(bevp1->quat, q, bevp0->quat);
+			}
+			else {
+				QUATCOPY(bevp1->quat, bevp0->quat);
+			}
+		}
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+
+	if(bl->poly != -1) { /* check for cyclic */
+
+		/* Need to correct for the start/end points not matching
+		 * do this by calculating the tilt angle difference, then apply
+		 * the rotation gradually over the entire curve
+		 *
+		 * note that the split is between last and second last, rather then first/last as youd expect.
+		 *
+		 * real order is like this
+		 * 0,1,2,3,4 --> 1,2,3,4,0
+		 *
+		 * this is why we compare last with second last
+		 * */
+		float vec_1[3]= {0,1,0}, vec_2[3]= {0,1,0}, angle, ang_fac, cross_tmp[3];
+
+		BevPoint *bevp_first;
+		BevPoint *bevp_last;
+
+
+		bevp_first= (BevPoint *)(bl+1);
+		bevp_first+= bl->nr-1;
+		bevp_last = bevp_first;
+		bevp_last--;
+
+		/* quats and vec's are normalized, should not need to re-normalize */
+		QuatMulVecf(bevp_first->quat, vec_1);
+		QuatMulVecf(bevp_last->quat, vec_2);
+		Normalize(vec_1);
+		Normalize(vec_2);
+
+		/* align the vector, can avoid this and it looks 98% OK but
+		 * better to align the angle quat roll's before comparing */
+		{
+			Crossf(cross_tmp, bevp_last->dir, bevp_first->dir);
+			angle = NormalizedVecAngle2(bevp_first->dir, bevp_last->dir);
+			AxisAngleToQuat(q, cross_tmp, angle);
+			QuatMulVecf(q, vec_2);
+		}
+
+		angle= NormalizedVecAngle2(vec_1, vec_2);
+
+		/* flip rotation if needs be */
+		Crossf(cross_tmp, vec_1, vec_2);
+		Normalize(cross_tmp);
+		if(NormalizedVecAngle2(bevp_first->dir, cross_tmp) < 90/(180.0/M_PI))
+			angle = -angle;
+
+		bevp2= (BevPoint *)(bl+1);
+		bevp1= bevp2+(bl->nr-1);
+		bevp0= bevp1-1;
+
+		nr= bl->nr;
+		while(nr--) {
+			ang_fac= angle * (1.0f-((float)nr/bl->nr)); /* also works */
+
+			AxisAngleToQuat(q, bevp1->dir, ang_fac);
+			QuatMul(bevp1->quat, q, bevp1->quat);
+
+			bevp0= bevp1;
+			bevp1= bevp2;
+			bevp2++;
+		}
+	}
+}
+
+static void make_bevel_list_3D_tangent(BevList *bl)
+{
+	BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+	int nr;
+
+	float bevp0_tan[3], cross_tmp[3];
+
+	bevel_list_calc_bisect(bl);
+	if(bl->poly== -1) /* check its not cyclic */
+		bevel_list_cyclic_fix(bl); // XXX - run this now so tangents will be right before doing the flipping
+	bevel_list_flip_tangents(bl);
+
+	/* correct the tangents */
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	nr= bl->nr;
+	while(nr--) {
+
+		Crossf(cross_tmp, bevp1->tan, bevp1->dir);
+		Crossf(bevp1->tan, cross_tmp, bevp1->dir);
+		Normalize(bevp1->tan);
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+
+
+	/* now for the real twist calc */
+	bevp2= (BevPoint *)(bl+1);
+	bevp1= bevp2+(bl->nr-1);
+	bevp0= bevp1-1;
+
+	VECCOPY(bevp0_tan, bevp0->tan);
+
+	nr= bl->nr;
+	while(nr--) {
+
+		/* make perpendicular, modify tan in place, is ok */
+		float cross_tmp[3];
+		float zero[3] = {0,0,0};
+
+		Crossf(cross_tmp, bevp1->tan, bevp1->dir);
+		Normalize(cross_tmp);
+		triatoquat(zero, cross_tmp, bevp1->tan, bevp1->quat); /* XXX - could be faster */
+
+		bevp0= bevp1;
+		bevp1= bevp2;
+		bevp2++;
+	}
+}
+
+void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode)
+{
+	switch(twist_mode) {
+	case CU_TWIST_TANGENT:
+		make_bevel_list_3D_tangent(bl);
+		break;
+	case CU_TWIST_MINIMUM:
+		make_bevel_list_3D_minimum_twist(bl);
+		break;
+	default: /* CU_TWIST_Z_UP default, pre 2.49c */

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list