// 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 subtract 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; - See more at: http://www.softimageblog.com/archives/94#sthash.DMqooeqi.dpuf