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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to