Footroll – or just rolling an object…

April 10th, 2006 by Helge Mathee - Viewed 16999 times -




In this post I would like to demonstrate a technique using a scripted operator to roll something along its edges / boundary. The post includes the full code as well as images / movies for further explanation.

I created an object, and extracted a curve from the boundary edges. Of course, you can always go the other route and create the curve first, and then afterwards create the mesh off the curve.

What I now want to do is roll the object along this curve, like a footroll. Here’s a picture and a movie for further explanation:

adv_footroll1.jpg

The movie is encoded using Camtasia (Techsmith Codec) and is around 3 MB small / large… ;-) Click on this link to get it.

The code is fairly simple, and I tried to comment / document as much as possible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// get the transform of the control object
var inXf = Inlocal1.value.transform;
 
// get the control object's rotation
var inRot = XSIMath.CreateRotation();
inXf.GetRotation(inRot);
 
// get the value of the operator's roll parameter
var roll = In_UpdateContext.parameters("roll").value;
 
// get the value of the operator's distance parameter
var distance = In_UpdateContext.parameters("distance").value;
 
// set a vector which is going to start out as the y axis
var yAxis = XSIMath.CreateVector3();
yAxis.Set(0,1,0);
 
// multiply y by the rotation, so it points along the
// control object's y axis
yAxis.MulByRotationInPlace(inRot);
 
// create the output transform of the curve
var xf = XSIMath.CreateTransform();
 
// if there is any rotation (if y doesn't point straight up)
if(yAxis.x!=0||yAxis.z!=0)
{
	// store the height of y temporarily
	var yAxisHeight = yAxis.y;
 
	// remove the y part of yAxis
	yAxis.y = 0;
 
	// normalize it (puts its length to 1)
	yAxis.NormalizeInPlace();
 
	// multiply the length of y by the distance param
	yAxis.ScaleInPlace(distance );
 
	// get the curve's geometry
	var geo = Incrvlist.value.Geometry;
 
	// get the closest curve position to the resulting
	// position of the yAxis (on the ground plane)
	var vbArgs = new VBArray(geo.GetClosestCurvePosition2(yAxis));
	var args = vbArgs.toArray();
 
	// change the length of y relatively to the distance
	// of the closest point on the curve
	// this removes the unwanted jittery behaviour
	yAxis.NormalizeInPlace();
	yAxis.ScaleInPlace(args[3].length());
 
	// now get the closest position again
	var vbArgs = new VBArray(geo.GetClosestCurvePosition2(yAxis));
	var args = vbArgs.toArray();
 
	// get the U value of the curve for the closest point
	var curveU = args[2];
 
	// now evaluate the curve for the given U
	// note: this is using the hard coded subcurve index
	// 0, so it never works for multi-curve-curvelists
	var vbArgs = new VBArray(geo.curves(0).EvaluatePosition(curveU));
	var args = vbArgs.toArray();
 
	// get the position and tangent
	var curvePos = args[0];
	var curveTan = args[1];
 
	// calculate the angle between the former Y axis and
	// the ground plane
	var angle = Math.acos(yAxisHeight)/2;
 
	// negate (turn around) the yAxis
	// as we want to move the object position
	// relatively to the position on the curve
	curvePos.NegateInPlace();
 
	// define a quaternion for the rotation
	var quat = XSIMath.CreateQuaternion();
 
	// the rotation for the tilt is a rotation around
	// the tangent of the curve on the given position
	// with an angle defined by the overall rotation
	// of the control object
	quat.Set(
		Math.cos(angle),
		Math.sin(angle) * curveTan.x,
		Math.sin(angle) * curveTan.y,
		Math.sin(angle) * curveTan.z
	);
 
	// create a rotation for the tilt
	var rotTilt = XSIMath.CreateRotation();
	rotTilt .SetFromQuaternion(quat);
 
	// now we rotation the position of the curveobject
	// around the tangent of the curve, by using
	// our rotTilt rotation
	var centerPos = XSIMath.CreateVector3();
	centerPos.MulByRotation(curvePos,rotTilt);
 
	// define an additional rotation for the roll	
	var rotRoll = XSIMath.CreateRotation();
	// define an eulerangles vector for the rotation
	var rotAngles = XSIMath.CreateVector3();
	// set the y rotation by the given roll param
	rotAngles.y = XSIMath.DegreesToRadians(roll);
	// set the rotations euler angles by the vector
	rotRoll .SetFromXYZAngles(rotAngles);
	// rotate the position of the curveobject again
	// by the rotRoll rotation
	centerPos.MulByRotationInPlace(rotRoll);
 
	// for the output transform, create a new rotation
	// and multiply both rotations together
	var rot = XSIMath.CreateRotation();
	rot.Mul(rotTilt,rotRoll);
 
	// now substract the curvePosition off the center
	// position, to put it back in its own space
	centerPos.SubInPlace(curvePos);
 
	// for the output transform, set the
	// translation and rotation
	xf.SetTranslation(centerPos);
	xf.SetRotation(rot);
}
 
// output the transform
Out.value.transform = xf;

If you want to checkout the scene, here it is (XSI 5.1).
You can find the scripted operator below the local kinematics of the curve. Enjoy!

7 Responses to “Footroll – or just rolling an object…”

  1. Nicolas Langlois says:

    Very nice and utile Helge! Thanks for the tutorial and script explanations!

  2. This will makes my life easier! thanks a lot Helge

  3. Carlos Valcarcel says:

    Wow, this is great ! Very nice and elegant solution ! Thanks for posting this blog :)

  4. Raul Fraile says:

    Thanks for share!

  5. andr says:

    Plz, explain a little bit how to use this magic code?

  6. Ajlan Altug says:

    Dang… What kind of a wild mind are you man? Wonderful effort and very generous share Helge, as always…

    Cheers

    AJ