PDA

View Full Version : How to achieve the effect like Path Constrain using MAXScript?


Jausn
03-17-2009, 02:48 AM
Hello everyone!

I wanna animate a car.

I want to make the keys of position manually, and generate the car's rotation automatically.
I mean, first turn on Auto Key, second move the car to generate position keys, then the car rotates to follow the trajectory automatically, which is just like the effect of Path Constrain.

How can I achieve this?

Thank you!
Longing for answer!

Piflik
03-17-2009, 03:15 AM
That is just a random shot now, but I think you might be able to do that with a Rotation Script Controller, where you specify the Orientation Vector by the difference of the Position Vector of the current frame and the Position Vector of an earlier frame.

Mathieson
03-18-2009, 01:20 AM
Check out Shape Common Properties in the help.

You can use lengthTangent to get the directional vector for the tangent at a certain percentage along a spline's length. Use this to then generate a rotation value.

You can also use lengthInterp to get the position value of a certain percentage along a spline's length.

Hope that helps.

Jausn
03-18-2009, 09:33 AM
Thank you for your reply.

But I don't want a spline. I just wanna move the car manually not using a spline.

ZeBoxx2
03-18-2009, 12:51 PM
so basically you'd want the equivalent of...
1. going into trajectories mode
2. converting the trajectory to a spline
3. setting that spline as a path constraint with 'follow' on
4. bake the rotation out to actual keyframes
?

(I, too, thought he just meant he didn't want to use a path follow constraint - while still following a path, leading to this script controller >_<

nearestParam = nearestPathParam spl 1 obj.pos steps:200
obj.pos = pathInterp spl 1 nearestParam
obj.dir = pathTangent spl 1 nearestParam
1

)

Dimich
03-18-2009, 01:20 PM
I think I know what you are going for, and I have done it before on my reel (you can check it out here, near the end of the reel: http://dimitrykachkovski.com/Kachkovski_Dimitry_DemoReel.mov)

What you want is to get he motion of the object, and based on it's previous position get the directional vector. From this directional vector you can get the proper rotation of the car.

f = currentframe
LastF = currentframe - 1
dirVec = normalize ((at time f $.pos) - (at time LastF $.pos)

This will basically get you the direction, and then you just need to normalize the entire matrix through consecutive cross products.

Hope it helps.

Mathieson
03-18-2009, 04:21 PM
Ah okay, I didn't realize. I guess I paid too much attention to the subject line.

In that case, Phillip and Dimitry have provided some very good approaches. I would go down that path. (pun intended?)

Jausn
03-21-2009, 12:19 PM
Thank you for your answers. Could you show me more details about your method? ĎCause I still donít get how to turn your method into an executable MAXScript.
And hereís my script:

-- create an object
obj = box width:17 length:42 height:14
setTrajectoryOn obj true
-- animate the objectís position
animate on
(
at time 33 obj.pos = [50,100,0]
at time 66 obj.pos = [120,13,38]
at time 99 obj.pos = [100,-24,0]
)

-- automatically rotate the object
......(script that I donít know how to achive)

You can see I wanna rotate the object to follow its trajectory.
This is what I wanna do.

Piflik
03-21-2009, 12:31 PM
No, not a script...a 'Script Controller'

Go to the Curve Editor or the Motion Pannel and assign a 'Rotation Script' to the Rotation of the object. In there you write the code.

Jausn
03-22-2009, 09:26 AM
No, not a script...a 'Script Controller'

Go to the Curve Editor or the Motion Pannel and assign a 'Rotation Script' to the Rotation of the object. In there you write the code.


Yeah,thank you!
But what does the Script should be?
Could you show any detail?

Dimich
03-23-2009, 11:01 PM
Sorry for taking so long. I think I might post a small tutorial on my blog in the future just for the hell of it. But basically I make it in a way where I have a Custom attribute on the object that is rotating. The code for the attribute is this:
CustAttr = attributes RotVal
(
parameters RotValP
(
Rot type:#float default:0
)
)
custattributes.add $.baseobject CustAttr

When it comes to the actual script controller code, this should be it:
if currentTime == 0f do
(
Obj.RotVal.Rot = 0 --Obj should be a variable added in the Script controller pointing to the object that holds the custom attribute
)
p1 = at time currentTime Obj.pos
p2 = at time (currentTime-1) Obj.pos
dist = distance p1 p2
cir = (2*pi)*Obj.radius
ang = dist/cir
Obj.RotVal.Rot += degtorad(360*ang)

Sorry for taking so long, busy days at work :argh:

Jausn
03-24-2009, 03:44 AM
Thanks for your reply during the busy work!

But I'm cofused at this place:
cir = (2*pi)*Obj.radius

What does Obj.radius mean?
I guess that it's the radius of the object's trajectory,but there's no such property for a node as far as I know.

And using your method the object always rotates for a plus number,but sometimes it may rotate for a negative degree like -70.
So how do we get that the angle of its rotation is a plus number or a negative one?

Dimich
03-24-2009, 11:22 AM
O man, hahahaha, I completely messed this one up:) So sorry man, I posted a completely wrong part of what I wanted to show. This is for the wheel rotation, not for the actual object rotation. Sorry about that. So here goes my second attempt:)
if currenttime != 0f then --I prefer to have the rotation neutral at frame 0
(
YVec = normalize (Cnt.pos - (at time (currenttime-1) Cnt.pos)) --get normalize
ZVec = [0,0,1] --this is needed for a temporary up vector calculation
XVec = cross YVec Zvec --cross product of Y and Z gives us X
ZVec = cross XVec YVec --cross product of X and Y gives the orthogonal Z
tm = (matrix3 XVec YVec ZVec Obj.pos) -- this is our objects transform
tm.rotationpart --get the rotational part
)
else
(
quat 0 0 0 1
)

What I gave you was basically another part of having a car set-up, which would be the wheel rotation. Once again sorry:blush: shame on me! Anyways, this should do it for you:thumbsup:

EDIT: In fact, lemme attach the max file so that you can see it in action! (Its in Max 2k8 format)

Jausn
03-25-2009, 03:29 AM
Thank you!

I'm learning your method which looks very cool.

Jausn
03-25-2009, 05:27 AM
I got it, man!
The Vector Cross Product is very cool!
And I've also understood the meaning of Matrix3!
Thank you!

Dimich
03-25-2009, 09:20 AM
:applause: Good stuff dude! Glad I could help. Once you finish the rig, you should post it to show the results:) And yea, 3D math is quite a lot of fun! Just need to get into it.

Jausn
03-26-2009, 04:14 AM
:applause: Good stuff dude! Glad I could help. Once you finish the rig, you should post it to show the results:) And yea, 3D math is quite a lot of fun! Just need to get into it.

I suppose it would take quite a long time to finish my car rigging because this is just beginning,but I'll show it here when I get it done.
:lightbulb :lightbulb

Jausn
04-15-2009, 08:45 AM
Sorry for taking so long. I think I might post a small tutorial on my blog in the future just for the hell of it. But basically I make it in a way where I have a Custom attribute on the object that is rotating. The code for the attribute is this:
CustAttr = attributes RotVal
(
parameters RotValP
(
Rot type:#float default:0
)
)
custattributes.add $.baseobject CustAttr

When it comes to the actual script controller code, this should be it:
if currentTime == 0f do
(
Obj.RotVal.Rot = 0 --Obj should be a variable added in the Script controller pointing to the object that holds the custom attribute
)
p1 = at time currentTime Obj.pos
p2 = at time (currentTime-1) Obj.pos
dist = distance p1 p2
cir = (2*pi)*Obj.radius
ang = dist/cir
Obj.RotVal.Rot += degtorad(360*ang)

Sorry for taking so long, busy days at work :argh:


I've run with this script for the wheel and I figured that the wheel always rolled in one orientation whenever you played the animation forward or reverse.
You've ever found this problem?

Dimich
04-15-2009, 09:43 AM
It is not a problem, but rather expected. As the script evaluates with every event, including time scrubbing, the script is set to evaluate the same things, meaning going to the frame before the one you are on, getting the rotation there, and rotating more from it. But if you actually animate the root moving backwards, the wheel will rotate backwards as well. So unless there is some reason for needing the backwards time scrubbing for the rig, you have nothing to worry about. Or you can bake the animation. That will give you the solid fixed rotation on the wheels. But I don't really see why you'd need it, as you are very unlikely going to need the backward time.

Also, if you notice in the script, there is the if statement for frame 0f. This makes sure that if you do playback the animation, you always start rotating from zero.

Hope this answers your concern :)

Jausn
04-16-2009, 03:07 AM
You got that right.
When finished the animation we started rendering which is almost always a frame-by-frame and forward process so this is not an issue.
Thank you for your answer!

Jausn
04-16-2009, 03:36 AM
I think we could simplify your script a litte bit like this:
Obj.RotVal.Rot += dist/obj.radius -- this is a radian value

'Cause you can see your script:
cir = (2*pi)*Obj.radius
ang = dist/cir
Obj.RotVal.Rot += degtorad(360*ang)

And degtorad(360*ang) equal to:
degtorad(360*ang) = 2*pi*ang = 2*pi*dist/2*pi*Obj.radius = dist/obj.radius

Anything wrong with me?

Dimich
04-16-2009, 11:49 AM
Yup, seems like you are right. I just did this in a way I was thinking, but as I'm quite often blind to some simpler solutions at first, I never saw that before:) Thanks for showing me this:)

CGTalk Moderation
04-16-2009, 11:49 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.