Notifications
Clear all

[Closed] Ship/Particle Banking

I’m going all out with questions these days it seems. My latest question involves a large space battle/dogfight scene that is completely driven by PFlow. Needless to say, it is alot of work but i’m loving it. Seeing as how ships are flying around in this, you know that when simply having a particle (or instanced particles in this case) rotated using a simple ‘Speed Space Follow’, it will turn but only on one axis, making the animation quite nasty depending on what one is using it for. I need my ships to bank when they turn to try an make their animation more fluid and realistic. I mentioned this in the huge PFlow discussion thread but it was vaguely answered and pretty much ignored after that. I know how to go about it but not how to script it. Basically, the ship would be rotated on a second axis (the X-axis, maybe) depending on the rate of the turn. Maybe you scripters can help? Thanks alot in advance.

5 Replies

Been thinking about this, and I have an idea of how you could do it. I’ve never tested it myself (and since I am going on holidays I probably never will), but you should be able to figure it out. Keep in mind that I have never really used speed space follow, so I may not understand it completly.

As far as I know, speed space follow lets a particle orient towards something else. This would mean that one axis would be pointed towards it (we will use the z axis), so it is actually rotating about the other two axes (x and y). What you want is to add roll into it, so it would actually rotate about the z. This would be put into a script rotation right underneath the rotation 3d.

To calculate the roll, first we need to understand some things. Since it is a ship, if it was rotating ‘over the top’ (IE changing pitch), it would not do any banking. Only when it is yawing (rotating left and right) would it need to roll. This will play a part in a minute.

First, we need to get the change in rotation every frame. We want this as a unit vector, and since it is the z axis we are ‘pointing’, we want the change in it. The idea is get the new rotation, then apply that to the z axis. You should get something like:

oldRot = at time (currentFrame – 1) thisParticle.rotation
newRot = thisParticle.rotation
changeRot = newRot – oldRot
newZ = changeRot * #(0, 0, 1, 1) as vector4 – I have no idea how this would work actually. Maybe just an array with ‘as’, or construct a vector with 0,0,1. You figure it out

BTW, anything in **’s is something I don’t know the syntax for. You will have to figure it out yourself.

Anyways, next step. Now you have the rotation, you would need to find out how much of it is along the x axis. To do this, you would project the x axis (1,0,0) onto this new vector. The x value of the resulting vector would let you know how much it rotates. Something like
rotX = asin(projectX.x_value)

rotX should be the rotation you need to apply to your particle about the z axis now. You might need to invert it (make it negative if positive…) for it to work.

Sorry I cant help with the actual script, but if I show you the basic idea you should be able to do it yourself, or ask specific questions to get someone else to help you. Keep in mind that I have never tested this or used anything like it, it was all constructed in my head away from a computer. So there might be something wrong with it.

Also, if the particle rotates more than 90 degrees over 1 frame, it might not work correctly. You might have to script a special case for that. Take the dot product of the current rotation and the last frame’s rotation, and if it comes out negative it has rotated more than 90.

Hope this helps some. Good luck with this.

Well I stared at this for a long time and It’s pretty much all over my head. I’ve simply got

on Proceed pCont do
(
for i in 1 to count do
(
pCont.particleIndex = i
oldRot = at time (currentTime.frame – 1) pcont.getParticleID(i)
newRot = pcont.getParticleID(i)
changeRot = newRot – oldRot
newZ = changeRot #(0, 0, 1, 1) as vector4
rotX = asin(projectX.x_value)
)
)
and It won’t close because it’s complaining about that last ) there… Pardon me, but this is my first scripting so I really haven’t a clue where to start…

Not exactly sure what the problem is, but I can see a couple things.

–oldRot = at time (currentTime.frame – 1) pcont.getParticleID(i)
–newRot = pcont.getParticleID(i)

These should be getting the rotation matrix of the particle, not just the particle. Or else the subtraction later won’t work, or have any meaning.

Also,

–rotX = asin(projectX.x_value)

This is not actual code, it is psuedocode. I am not sure how to do it in maxscript. It says take the inverse sine of the x value of the vector gotten from projecting the x axis onto the the new vector. As you can see, a bit odd. Thinking about it, you might be able to use te x value of the changeRot…something like

–rotX = asin(changeRot.x_value)

I haven’t looked at this for a while though, so it might not actually make sense :shrug:. Anyways, you would have to apply this new rotation to the vector, to rotate it about the z axis.

Sorry I can’t really help you more. Right now I am focusing on C++, and I don’t want to confuse myself with two different languages and styles.

Well, I’ve started trying to figure this out again, but i’m still so very confused. I did find a bank & turn script in the maxscript examples folder. Script looks like this, but I still don’t even know how to work it:

– A bank-and-turn function that takes any animated object (not
– just one that is animated along a path) and will generate
– bank and turn keyframes, with controls similar to those
– in the path controller.
– John Wainwright

bx = box length:200 width:200 height:10 mapcoords:true
lengthsegs:16 widthsegs:16

function fly obj bank:on bankAmount:40 smoothness:5.0 dt:2f bankSteps:5 =
(
local tm = scaleMatrix obj.scale, local_r,
pt0 = at time (currentTime – dt) obj.pos,
pt1 = at time (currentTime + dt) obj.pos

tm.translation = obj.pos
tm.row1 = normalize (pt1 - pt0)
tm.row2 = cross [0,0,1] tm.row1
tm.row3 = cross tm.row1 tm.row2
if bank then 
(
    local pt2, v0, v1,
          cv = 0.0,
          t = currentTime - (bankSteps/2.0) * smoothness,
          terms = 0, 
          end_t = (getTimeRange obj.pos.controller).end
    pt1 = at time t obj.pos
    t += smoothness
    pt2 = at time t obj.pos
    t += smoothness
    for i in 1 to bankSteps do
    (
        if t > end_t then exit
        pt0 = pt1; pt1 = pt2
        pt2 = at time t obj.pos
        v0 = normalize (pt2 - pt1)
        v1 = normalize (pt1 - pt0)
        v0.z = v1.z = 0
        if pt0 == pt1 then exit
        cv += (cross v0 v1).z * bankAmount / length (pt1 - pt0)
        terms += 1
        t += smoothness
    )
    if terms > 0 then preRotateX tm ((cv/terms) * (180/pi))
)
obj.transform = tm

)

– this will place keyframes every 5 frames
animate on for t in 0 to 100 by 5 do at time t fly $box01

– this will place key frames at existing position keyframes,
– probably not enough
animate on for k in $box01.pos.keys do at time k.time fly $box01

– if you want to delete all the scale keys, use:
deleteKeys $box01.scale.controller

I attempted changing:

bx = box length:200 width:200 height:10 mapcoords:true
lengthsegs:16 widthsegs:16

to simply:

obj = $Box01

which was a box animated along a path. But it whined about “– Unknown property: “keys” in [169.091,-20.0649,0]

which pointed to the line under the “animate on for k in $box01.pos.keys do at time k.time fly $box01” line of code towards the end…

If i can figure this out, maybe it will help me with getting PFlow particles to bank. But in either case i’m still at a large loss… Any help would be great.

I’m positively afraid i’m going to have to bump this…