[Closed] controlling position of spline vertices with precalculated arrays
Hello there,
I have array data for 5 points which have a specfic position and also time dependent attribute. I have managed to place 5 objects and animate their position using an array, i am wondering how to do the same procedure but rather than controling individual objects, do the same with a spline. I am looking for resources/things i should look into as far as:
a) how to programmatically define the position of vertices in a spline
b) how to animate the height attribute of the vertices
I started this experimentation a while back, am just now coming back to the project; time to get back into maxscript! hopefully this time using python as well.
thanks for any help/advice!
presuming a spline of linear segments…
-- setKnotPoint = function to set a knot's position
-- $ = current selection, assume single Editable Spline (or Line) selected
-- 1 = First spline within that shape
-- i = 'i'th knot (vertex) on that spline
-- newPos = new position, a point 3. The 'height' is simply 'z' in that position
-- [-20,10,50] = [x,y,z] = -20 to the 'left', 10 'back' and 50 'up'.
setKnotPoint $ 1 i newPos
-- updateShape = function to update the shape so max won't go wonky
-- $ = same s before
updateShape $
If they’re not linear segments, you’ll also have to adjust the in/out vectors of the bezier handles.
Check the topic:
Value > MAXWrapper > Node > GeometryClass > Shape > SplineShape
if you want to animate a spline, you first have to assign controllers to all verts in the block controller
This can easily be done with
animateVertex $splinename #all
After that you can do two things… add keys to the controller of the vertex or use an animate on context and use the method Zeboxx2 described.
If you want to assign it directly through the controller:
master = $Line01
vert = 1
zTime = 1
zPos = 25
animateVertex master #all
theTrack = master[4][8] -- Get the block controller
theTrackIndex = 3 * ( vert - 1 ) + 2 -- The blockcontroller also holds the in/out controllers, we only want the pos controller so every third controller starting at 2
theKey = addNewKey theTrack[theTrackIndex].controller zTime
theValue = [0,0,zPos]
theKey.value = theValue
Goodluck!
-Johan
Thanks ZeBoxx2 & JHN!
I’ll be hackin at this today and hopefully i’ll get things to work and post some useful code!
(rather than a confusion driven question…)
It all makes sense except for the block controller, i just spent a few hours trying to dig up info about it and related functions like addNewKeyFrame.
if i type
master[4][8] into my listener window i get an error :S ??
basically, i really dont know how to use addNewKey so that its relative to the vertex movement.
Many thanks!!
Well, in my script I use the master variable as a reference to the selected object so if you have a spline selected use:
$[4][8]
or
master = selection[1] [i]-- better then $, because $ can be a selection or a single object[/i]
master[4][8]
Hope this helps some more, also try reading up on subsAnims.
-Johan
Hey JHN, ive been looking at this for too long, your last comment of subanims yeilded me no results in the few iterations, even though i think i theoretically understand it. here is my code, it allllmost works, it just doesnt actually put in the keyframe! Ive been working with a box, converting it to a an editable mesh.
v_3 = getVert thebox 3 -- [-12.5,12.5,0] (for my particular shape)
v_3.z = -9
update thebox
addNewKey thebox 0
animateVertex thebox #all
--------------------mb=trackviewnodes.global_tracks.block_control[1]
for i = 1 to 1 do
(
setVert thebox 3 v_3
addNewKey thebox.controller 5
addNewKey thebox.controller 5
--addNewKey thebox[1].controller 5 does not work, nor any other [] or [][] combo
--that i can think of, the problem i dont get is if im moving a vertex am i
--affecting all 4 of the matrix components??
update thebox
)
update thebox
i see it animating, but upon rewinding, everything goes back to normal… hope its a simple fix! thanks!
Yeah but I see now your animating a piece of geometry instead of a spline… the block controller is on another subanim…
chew on this
for i in 1 to $.baseObject.numsubs do print $baseObject[i]
for i in 1 to $[4].numsubs do print $[4][i]
for i in 1 to $.numsubs do
for j in 1 to $[i].numsubs do format "Track: % | subtrack : %
" $[i] $[i][j]
The thing that’s going wrong right now is that you’re trying to combine Zeboxx2’s technique and mine… But you should use only 1 of them.
What I don’t understand from your example is that you have a box, you sample a vertex position (in which space? world?) you move it down. Then you set the vert pos AND you add a key. If you use setVert you should use the “with animate on” clause. If you want to use the controller approach you will want to “inject” the coordinates straight into a controller key value… you don’t need setVert for that. That will “physically” set the vert pos. I don’t have more time right now, but will try to setup a example, if you can make clear what it is you exactly want, with what type of objects.
-Johan
Thanks for this! i will play with this code later today, i look forward to your example. it seems like something as simple as animating a vertex with script has a whole can of worms associated with it! I think once i understand this aspect of things it will be a major hurdle leaped in maxscript in general. I’ll be posting my updated attempt sooon.
Example that uses controllers
-- METHOD 1 : Animate by controller
max select all
delete selection
b = box()
convertToMesh b
-- offset the main pos a bit.
b.pos = [0,0,10]
mpc = b[4][1] -- Get "master point controller" different for mesh! (count the subtracks in the trackview)
--is identical to b.baseObject[1]
animateVertex b #all
-- How much offset
offset = 2.
-- Loop over time
for i in 1 to animationRange.end by 5 do
(
-- Loop over vertices
for j in 1 to mpc.numsubs do
(
-- In coordsys is very important to get the right values!! Otherwise it would return world coords and that would offset all verts!
pPos = in coordsys local getPointPos b j
--pPos = getPointPos b j -- uncomment this to see it in worldspace action now understand why I offset the box in Z.
theKey = addNewKey mpc[j].controller i
theVal =
[ \
(random (pPos.x - offset) (pPos.x + offset)), \ -- X
(random (pPos.y - offset) (pPos.y + offset)), \ -- Y
(random (pPos.z - offset) (pPos.z + offset)) \ -- Z
]
theKey.value = theVal
)
)
Please note that it’s very important you know what info gets into a key value. Right now I’m retreiving the original position of the vert and randomize it a bit, with the offset value.
The value you will put into the key cannot(!!!) be a world position… because all vertices are being offset by the node position, so the objectoffsetposition is the base for the vert position. Read up on “Using Node Transform Properties” in the mxs help.
So that’s the method for using keyframe values directly on controllers, the other method would be more like activate the animation on the verts and set their positions… like so:
-- METHOD 2 : Animate by offsetting verts
max select all
delete selection
b = box()
convertToMesh b
mpc = b[4][1] -- Get "master point controller" different for mesh! (count the subtracks in the trackview)
--is identical to b.baseObject[12]
animateVertex b #all
-- How much offset
offset = 2
with animate on
for i in 1 to animationRange.end by 5 do
(
-- Loop over vertices
for j in 1 to mpc.numsubs do
(
verts = #{j} -- meshop.setVert takes an bitarray as vertlist, so convert vertex count to bitarray
pPos = in coordsys local getPointPos b j
theVal =
[ \
(random (pPos.x - offset) (pPos.x + offset)), \ -- X
(random (pPos.y - offset) (pPos.y + offset)), \ -- Y
(random (pPos.z - offset) (pPos.z + offset)) \ -- Z
]
at time i meshop.setVert b verts theVal
)
)
If you want verts so follow objects in worldspace again you would have to take into account the object ofset like I mentioned before. Verts live in a local space, so a translation needs to happen before you can use them as if they were in world space.
Hope this helps!
-Johan