Notifications
Clear all

[Closed] Keyframe/cache vertex locations

I am creating a nice little script that lets an animated object change the vertex locations of another object. The purpose of this is so that you can have pre-cached animated footprints, craters etc.

 So far so good; It successfully animates the craters within the mesh in the viewport, but the only problem that I'm facing is that I cannot figure out how to keyframe the verticies so it's a transitional animation rather than the total progress of where I stop the script. The result i'm looking for is either caching it to a file as the script runs or have it similar to the older reactor versions where it simulated the mesh and added a keyframe for each and every frame till the simulation was finished. 
 I tried looking up all the obvious keywords in maxscript help but had no luck. Does anyone have any experience with this, I would really appreciate the help.

Here’s a demo of what it can do. (playing at 2.5x original speed)

16 Replies

here is a sample how to animate vertices:


(
 if (anodes = getNodebyname "AniMesh" all:on).count > 0 do delete anodes
 anode = Cylinder name:"AniMesh" smooth:off heightsegs:1 capsegs:1 sides:5 height:20 radius:10 mapcoords:on pos:[0,0,0]  
convertToMesh anode
 animateVertex anode #all
 at time 100f with animate on for v=1 to anode.numverts do 
 (
  pos = getproperty anode ("vertex_" + v as string)
  pos += random [-2,-2,-2] [2,2,2]
  setproperty anode ("vertex_" + v as string) pos
 )
)

Hey Denis, thanks for the help.
I tried implementing your script but was unsuccessful at getting it to work.

I have fixed the video so you can see what the script is doing but this is simulated within the viewport. What it’s doing is replicating modifiers at each frame and converting it to an editable mesh before it moves on to the next frame and replicates the modifiers again, thus making a steam of cavities in the mesh. What i want it to do is to be able to somehow save the positions of the vertices at the end of each frame so it can become a progressive animation. (if i played it back after the end of that video, all you would see is the animated sphere moving, the ground would remain the exact same as it did when i stopped the script.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

In your case because you are converting to mesh on every frame you have to use buffer. Bake animation (vertex positions) on every frame to the buffer, and copy buffer to the mesh at the end.


(
 /********* create sample scene and animation ****************/
 try (delete objects) catch()
 animationrange = interval 0 100
 p = plane name:"Terrain" length:200 width:100 pos:[0,0,0] lengthsegs:40 widthsegs:20 wirecolor:green
 convertToMesh p
 s = sphere name:"Press" radius:30 segs:32 transform:(matrix3 [0,0,1] [0,-1,0] [1,0,0] [0,-130,15]) wirecolor:orange
 s.position.track[2].track = linear_float()
 s.rotation.track[2].track = linear_float()
 at time 100f with animate on 
 (
  s.position.controller[2].value += 260.
  s.rotation.controller[2].value += (360.0*2*pi*s.radius/260.0)
 )
 /*****************************************************************/
 
 -- make buffer of original vertex positions and controller for vertex animation
 poss = for v=1 to p.numverts collect #(getVert p v, bezier_point3())
 
 modified = #()
 with animate on for t=0 to 100 while not keyboard.escpressed do
 (
  slidertime = t 
  for v=1 to p.numverts do
  (
   pos = poss[v][1]
   dist = distance pos s.pos
   if dist < s.radius do
   (
	r = ray [pos.x,pos.y,-s.radius] [0,0,1]
	d = intersectRay s r
	if d != undefined and d.pos.z < poss[v][2].value.z do
	(
	 -- add new value to correspondent vertex controller
	 poss[v][2].value = d.pos
	 modified[v] = t
	)
	)
   if modified[v] == undefined do poss[v][2].value = poss[v][1]
  )
 )
 -- make all vertices of terrain animatable
 animateVertex p #all
 -- It adds Master_Point_Controller to the base object and Bezier_Point3 controller for every vertex
 
 -- copy controllers from buffer to baseobject in order of vertex index
 for v=1 to p.numverts where modified[v] != undefined do (p.baseobject[#Master_Point_Controller][v].track = poss[v][2])
 
 update p
-- slidertime = 0
 gc()
)


In my sample I’m baking only really modified vertices to make the process faster.

I don’t even know what to say Denis, you make maxscript look more powerful than I realized it was . Your latest code looks more usable in my script and i’m going to try to fit it in and hope it works. Thanks again, I’ll update the status later.

I feel like I’m so close but It keeps giving me the No “get” function for undefined error in the line

for v=1 to B.numverts where modified[v] != undefined do (B.baseobject[#Master_Point_Controller][v].track = poss[v][2])
 
2 Replies
(@denist)
Joined: 11 months ago

Posts: 0

what is undefined? poss? Poss is a buffer which you have to fill up. (see my sample)

(@karnageddon)
Joined: 11 months ago

Posts: 0

From what I can gather from the MXS Listener the problem seems to be in code

(B.baseobject[#Master_Point_Controller][v].track = poss[v][2])

Pos 1627

I have poss defined and collecting as per your sample. This happens at the launch of the script window; before I can even press the button to run the script code. Would it be easier if I PM’d you the clean/modified(using your sample) codes?

it will be much easier for me… attach your code and will take a look

attach your script, i’ll take a look

Hmm odd posting issue. Anyways here’s the scene attachment, the code has been PM’d to you.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

rename ground box to “Terrain” and moving sphere to “Press” and run my new code


(
p = getnodebyname "Terrain"
converttomesh p -- to make it undoable
s = getnodebyname "Press" 
animateVertex p #all
upvertices = #()
 
-- collect only verts with its normal UP as index and position value
for v=1 to p.numverts do
(
if dot (getnormal p v) [0,0,1] > 0 do append upvertices #(v, getVert p v)
)
 
step = 0.5 -- step for baking (every half frame)
with undo off
(
with animate on for t = animationrange.start to animationrange.end by step while not keyboard.escpressed do
(
slidertime = t 
at time t for v in upvertices do
(
	pos = getvert p v[1]
	dist = distance pos s.pos
	if dist < s.radius do
	(
	 r = ray [pos.x,pos.y,0] [0,0,1]
	 d = intersectRay s r
	 if d != undefined and d.pos.z < pos.z do
	 (
	 meshop.movevert p v[1] (d.pos-pos)
	 if v[3] == undefined do v[3] = t
	 )
	)
)
)
with animate on for v in upvertices where v[3] != undefined do at time (v[3]-step)
(
pos = getvert p v[1]
meshop.movevert p v[1] (v[2]-pos)
)
)
update p
slidertime = 0
gc light:on
)

That works great Denis, but the problem is that it can only use a sphere as a “press” object because of the process to re-build the terrain that you have used.
I was using modifiers originally because it allowed the user to assign very complex and organic models which also have sub-animations; to do the work as well and give them the option of controlling the falloff range and dirt pileup around the land being excavated (all to be implemented later, the user will also be able to pick the object and terrain seperately, right now i’m just experimenting till I can get the script working and unfortunately the keyframe animating process is the only one I cannot figure out on my own).

Is it even possible to use the vertex buffering method you are suggesting with the process my original script is using? I’m at a complete loss with vertex buffering as I cannot find any tutorials or books that explain it and this is one of those things MXS Help was unable to guide me through.

you can use any geometry class (not only sphere). Just change lines


--dist = distance pos s.pos
--if dist < s.radius do
if (pos.x >= s.min.x and pos.x <= s.max.x) and (pos.y >= s.min.y and pos.y <= s.max.y) do

Page 1 / 2