Trajectory2 1.0 - by Bob Le Gob ******************************* 'trajc.pkg' is the only file that has been modified so far from the original official Trajectory 2.1 plugin. The original code, which is of interest to us is the slidepos2() function, and especially the part taking the interpolation into account. fun slidepos2(x,param)= let param -> [z interpoflag prevframe] in if interpoflag then /* trajectory with interpolation */ ( let x->[o sz l] in let z->[lastframe currentframe _ _ flagPosAng] in let o->[h _ _ _] in let sz*currentframe/lastframe -> i in let mod sz*currentframe lastframe -> kq in let lastframe-kq-> kp in let endlist l i ->[p [q _]] in match p with (posAnchor [_ [xp yp zp] [ap bp cp]]-> match q with (posAnchor [_ [xq yq zq] [aq bq cq]]-> ( M3setObjVec session h [(xp*kp+xq*kq)/lastframe (yp*kp+yq*kq)/lastframe (zp*kp+zq*kq)/lastframe]; if flagPosAng then M3setObjAng session h [(ap*kp+aq*kq)/lastframe (bp*kp+bq*kq)/lastframe (cp*kp+cq*kq)/lastframe] else nil ) ) ) ) else /* trajectory without interpolation */ (...);; Let's explain (at least what I understood): - 'x' gives a link to the 3D object to be moved (-> o -> h), the number of positions in the plugin (sz) and the list of positions (l). - 'i' points to the previously reached position. This is computed from the number of defined positions -1, the current frame and the total number of frames. Example: 4 positions, current frame = 45, total frames = 120 (30 between each position: 120/4): 4x45/120 = 1.5, rounded down = 1, starting from 0. - 'kq' points to the frame reached between the previous and next position frames. This is relative to the total number of frames in fact, but that's the idea. - 'kp' points to the frames that'll be needed to reach the next position frame. Still the same idea of relativity. - 'p' points to the previous position - 'q' points to the next position Then, the object is moved according to the current frame to its new position, with the 'proper' orientation if needed. Let's use an example, moving an object along the x axis, from x1=10 to x2=20, during 40 frames. Let's say that we have a single move (list size = 2) and that the new computed frame is the 30th. i = (2-1) x 30 / 40 = 0 (rounded down) kq = 40 - 30 = 10 kp = (2-1) x 30 modulo 40 = 30 new_x = ((x1 x 10) + (x2 x 30)) / 40 = 17.5 (thus 3/4 of the distance which seems quite logical). The problems appear when you're trying to interpolate the orientations of the object using the same fixed formula. Basically, in the Scol language, angles are coded with values ranging from 0 to 65535 for angles ranging from 0° to near 360°. We may thus believe that angles in the C3D3 editor will be stored with values between 0 and 65535. But in fact the C3D3 uses the following values for angles: 0° = 0 180° = 32760 181° is translated as -179° 359° is translated as -1° 360° is translated as 0° (this is normal, I would say) Problem is that 270° is translated as -16396, with a negative value as any angle between 181° and 359°. So, when you rotate from 270° to 180°, the plugin doesn't make a -90° rotation but a rotation from -16396 to 32760, rotating 270° using the opposite rotating direction. This is only an example. Solution is to determine the shortest way from the source position orientation to the destination position orientation: - OptSingleAng() Determines the optimal path from one angle to the other. Using the C3D3 principles, this is computed through either the direct path, the same path adding 65536 (360°) or substracting this same value - rounding to absolute values. Example: moving from 270° (-16396) to 180° (32760) path1: 32760 - -16396 = 49156 path2: 32760 - -16396 + 65536 = 114692 path3: 32760 - -16396 - 65536 = -16380 = 16380(abs) = shortest path So we'll rotate from 32760 to 16380 instead of the above rotation. - OptimizeDestinationsAngle() Global function that calls OptSingleAng() for the 3 possible directions. - Changes in SlidePos2() ... if flagPosAng then ( let OptimizeDestinationsAngle ap aq bp bq cp cq -> [aq2 bq2 cq2] in M3setObjAng session h [(ap*kp+aq2*kq)/lastframe (bp*kp+bq2*kq)/lastframe (cp*kp+cq2*kq)/lastframe]; 0; ) ... Just applying the proper angle. Other references: - traj1_trajc.pkg: copy of the original client code, from official Trajectory plugin. - traj1_log.txt: log extracted from the original plugin showing the life of the 'i' above variable and the value of rotations. The bug can be seen when i = 2; format: BobLeGob: i angle Optimization: The problem with this method is that we permanently have to compute the best path although it could be computed only once for each move between two consecutive positions. Still working on this. Bob Le Gob