[Closed] how do you increment a value in an transform script controller?
Hi guys,
I am running a rather strange personal project that involves a chain cannon on the end of an IK arm. Now the IK handle moves the arm which aims the chain cannon. But additionally, the chain cannon must be able to spin around its own x axis in order to fire.
The aiming is easily controlled through the rig and parenting. The GunBarrel sits in a sub group. controlling the local rotation around the x axis of this sub group spins the barrel nicely.
The trouble is that the animator wants me to include a rate of fire. We have a Pointer that is acting as a character controller, which a load of custom attributes. The animator wants to be able to set a rate of fire custom attribute. So he can animate it from 0 (barrel doesnt spin) up to a high spin rate and then back down to zero again.
I thought to do this by incrementing the x rotation by the rate of fire value. So if the rate of fire is 2 (for example) then each time the expression evaluates it adds 2 to the current rotation. (Maybe with an if statement to reset it to an initial value at frame 0)
I was going to do this with a transformation script
--Rotates the transformation locally around the X axis by the angle variable FireRate
CurrentTrans = $GunBarrel.transform
preRotateX CurrentTrans $CharacterControl.FireRate
--This returns a new rotated transformation matrix that I want the gun barrel to now use
Now this hits me with all these Illegal self referencing issues! So my question is, if you want to simply add a value to a tracks current value each time the run time expression evaluates, how can you find out what the starting value is without illegally self referencing it! Effectively I want to be able to do something like this in pseudo code:
--What is the equivalent of doing this in a run time expression on a script controller!?
--To perform this eachtime the expression evaluates
GunBarrelRotation = GunBarrelRotation + FireRate
--or
GunBarrelRotation += FireRate
I have looked into weak referencing it, by storing a custom attribute with a nodeTransformMonitor on the Character Controller that points at the GunBarrel and then finding the transform from:
nodeTransformMonitor.node.transform
But this is still hitting me with with an Illegal self reference.
There must be a very simple way to do this, but I am unfortunately completely over looking it as I have not used script controllers and expressions very often at all…
I hope this dilema makes sense! Any help would be massively appreciated!
Cheers guys,
Rich
I’ve run into similar self referencing issues before. From the sounds of it you don’t need to be monitoring the gun barrel’s transform at all though, just a custom attribute for the rate of fire and then a script controller on the gun barrel’s X rotation with the expression “rateOfFire * F”.
Let me know how this works. I may have misunderstood.
Mat is going in the right direction there. A float script is the way to handle this. Don’t know why you are getting the circular problem unless I looked at it.
I think that something like this might be closer to what you are looking for.
degToRad ((360/6)*rate*f)
Where 6 is the number of barrels that you have. If rate is 2 you will get two shots off each frame. If you want that per second then do…
degToRad (((360/6)*rate*f)/30.0)
Assuming you are working at 30 FPS.
I have the feeling this isn’t going to work. You will need to store a last value I think and add to it. The reason for this is it will start to mess up once it is winding back down again. Probably will start spinning backwards.
Yeah you’re right Paul, it doesn’t work for the slowdown, it does just unwind. I’m going to play around with it a little bit.
Got an incremental system working and the gun barrel slows down properly, but it is a bit hacky and has some issues.
Since the value is being determined incrementally instead of absolutely the value is just continually being added to whenever the expression is evaluated. This is creating some in-definite animation, so if you scrub forwards or backwards it will spin the same direction either way. If you scrub back and forth over the same 10 frames or so it will just continue spinning, which is essentially the same problem. The spinning speed seems to vary depending on how fast you scrub the timeline/playback. You’ll also get strange re-drawing of the animation curve on the script controller if you move your track view window around.
So anyways, its working but definitely not the best solution. Pretty gross actually. Probably going to play around a bit more.
I uploaded the file I was messing around with. Download it here.
Here is the expression I used in the script controller.
newVal = lastVal + rateOfFire
this.SetConstant #lastVal (mod newVal 360)
degToRad newVal
Where lastVal is a declared variable in the script controller and assigned as a constant.
That doesn’t work well like that Mat. Better to create a DA def and add it to the script controller. Add a local variable in it called lastVal, DON’T use a parameter block variable as it is slower to write to. Then use
this.theDef.lastVal=currentVal
Because scrubbing backwards is still considered a change in time you should also store lastFrame in the def and invert the math depending if the time is higher or lower then the currentTime.
Hi Paul and Mat,
Thanks so much for looking into this. You guys picked up on why I was trying to separate this process from frame/time very early on, cause it messes up bad when you try and slow the barrel down.
I completely understand the need for the switch on the maths when you run the frames backwards, that should be doable by storing the last frame as you mentioned. Should this be combined with an initialising value at frame 0?
However, I am still a bit new to this script controller stuff and the sentence regarding “create a DA def and add it to the script controller” confused me a bit. Are you talking about adding an attribute in the parameter editor to the script controller and then referencing that? Or is that what you are trying to say to avoid?
If you could explain this terminology and the line
this.theDef.lastVal=currentVal
a little more, then I would be really grateful. I have a bit of maxscript experience, so I hopefully will be able to understand it.
Also Mat, I am only running Max 9, I could not open your scene, and I would really like to look at it, have you saved it in a newer version of Max? Sorry to be such a pain.
Thanks again guys, this is all really appreciated
Rich
Aside:
The reason I am pursuing this, is cause this barrel rotation I have already linked to a particle system that recognises when the barrels align to fire, and emits a particle at the appropriate time. These then detect collisions with scene geomtry and spark etc on impact. Since there are going to be a few guns the animator wants to just control direction and fire rate and the rest of the system will procedurally update. It is working so far Except this bit!
I don’t know any elegant way to achieve this (unless you think that a motor/dynamics setup is elegant…), but I’ve tried similar things in the past. My experience is that it’s probably a bad idea to use this kind of setup, as it can easily result in unpredictable/unreproducable animation where different rendered sequences fail to match up. I’d just stick to doing it the hard way, which shouldn’t really be that hard after all.
Besides the script controller solution wouldn’t a multiplier track to the rotation track suffice?
You could just set a default rotation rate and with relative repeat out of range and apply a multiplier track to animate the amount… just copy/instance the controller to a custom attribute… I’ll bet it’s the fastest solution
-Johan