Notifications
Clear all

[Closed] PolyStepper script

Hi all,
I recently saw a very interesting free Cinema4D tool , called “Poly Stepper” by Simon Russell.
This is his tutorial: http://vimeo.com/45009976
I started to recreate this XPresso tool with maxscript using simple Box mesh an PFlow.
So far I have achieved this example

   
  -- create xray map function
 	fn xrayMap xname: clr1: clr2: clr3: =
 	(
 		local map = Gradient_Ramp name:xname Gradient_Type:6
 		map.Gradient_Ramp.Flag__1.Color = clr1
 		map.Gradient_Ramp.Flag__2.Color = clr2
 		map.Gradient_Ramp.Flag__3.Color = clr3
 		map
 	)
 	-- create xrayMaterial
 	xrayMtl = standardmaterial name:"xray" \
 	diffuseMap:(xrayMap xname:"xDiffuse" clr1:[110,220,255] clr2:[0,0,0] clr3:[125,160,240]) \
 	selfillumMap:(xrayMap xname:"xSelfillum" clr1:[255,255,255] clr2:[0,0,0] clr3:[127,127,127]) \
 	opacityMap:(xrayMap xname:"xOpacity" clr1:[255,255,255] clr2:[0,0,0] clr3:[127,127,127]) \
 	showInViewport:on
 	--create mesh (simble Box geometry)
 	ps = converttomesh (Box name:(uniquename "PolyStepper") lengthsegs:1 widthsegs:1 heightsegs:1 material:xrayMtl)
 	animatevertex ps #all
 	--create pfSource
 	pf = PF_Source Quantity_Viewport:100 Enable_Particles:on name:"VolumePFlow" Emitter_Length:40 Emitter_Width:40
 	pf.SetPViewLocation 0 0
 	particleFlow.BeginEdit()
 	ev1 = Event name:"VolumePFEvent"
 	ev1.setPViewLocation 0 80
 	op1 = Birth Emit_Start:0 Emit_Stop:0 amount:100
 	op2 = Position_Icon Distinct_Points_Only:on
 	op3 = Speed speed:10 variation:5 direction:0 Divergence:17.5 reverse:on
 	op4 = DisplayParticles type:1 color:[230,155,0]
 	op5 = RenderParticles()
 	particleFlow.EndEdit()
 	ev1.AppendAction op1
 	ev1.AppendAction op2
 	ev1.AppendAction op3
 	ev1.AppendAction op4
 	pf.AppendAction op5
 	pf.AppendInitialActionList ev1
 	-- set new timerange 0-1000
 	animationrange = (interval 0 1000)
 	-- assigne point3_Script on every vertex to be able to falow particles
 	format "ps=%
" ps
 	for v = 1 to ps.numverts do 
 	(
 		p3Script = ps[4][1][v].track = Point3_Script()
 		p3Script.addNode "_ps" ps
 		p3Script.addNode "_pf" pf
 		expStr = "if isValidNode _pf do at time f
"
 		expStr += "(
"
 		expStr += "   (_pf.getParticlePositionByID (random 1 (_pf.numParticles())))*(inverse _ps.transform)
"
 		expStr += ")"
 		p3Script.setExpression expStr
 	)
 	--create and assign empty_modifier to a box
 	addModifier ps (EmptyModifier name:"PolyStepMod")
 	-- define C-Attributes
 	polystepCA = attributes unfolderAttribute
 	(
 		parameters PRM_PStep rollout:PRM_PStep
 		(
 			Step type:#integer ui:spn_step default:0.0
 		)
 		rollout PRM_PStep "PolyStepper Parameters"
 		(
 			spinner spn_step "Speed:			" fieldwidth:60 Height:16 Align:#Left Type:#integer Range:[0,100,0]
 		)
 	)
 	custAttributes.add ps.modifiers[#PolyStepMod] polystepCA
 

Now i have a question;
How to control speed of animated vertex.(like “Speed” spinner in video-tutorial)?
thanks in advance

18 Replies
6 Replies
(@denist)
Joined: 11 months ago

Posts: 0

you are using RANDOM … but it’s not what the algorithm does. it’s a “stepped” move. every vertex goes to the next index position.

(@gazybara)
Joined: 11 months ago

Posts: 0

Yep. I used random method and now can’t slow down verts movement.
But i need this

(@denist)
Joined: 11 months ago

Posts: 0

as i see on the video the author doesn’t slow down the ‘stepping’. he can make it faster by skipping next index. but if you want to slow down the jumping just use some of particle properties… it’s the age for example.

(@gazybara)
Joined: 11 months ago

Posts: 0

Yep. That’s it. Thanks Denis.
What would be better to use: Script Controller or WireParams?

(@denist)
Joined: 11 months ago

Posts: 0

in general case the script controller has to be cheaper. but i’m thinking about a way of using a ‘particle’ script.

(@gazybara)
Joined: 11 months ago

Posts: 0

CustomAttributes and ‘particle’ script. Now begins the problem for me. I’m not good with that:rolleyes:

An ugly solution: use

sleep

before moving each vert

2 Replies
(@gazybara)
Joined: 11 months ago

Posts: 0

Solution that I planned is

  • For each vert i define array of random particles position at specific time
  • Then divide distance between two particle position using speed value
    But I think that there is a simpler solution
(@denist)
Joined: 11 months ago

Posts: 0

it’s not just ugly… it’s disgusting!

Try with

sleep

Execute the code from this post to see what sleep can do.

1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

Thanks for Bobo’s post. It’s fine but i when i put “sleep” in point3_script expression animated verts stay in place (at start position).

--point3_script expression:
 if isValidNode _pf do at time t
(
   vpos = (_pf.getParticlePositionByID (random 1 (_pf.numParticles())))*(inverse _ps.transform)
   max views redraw
   sleep 0.1
   vpos
)

guys! ‘sleep’ is a debug function in all programming languages. don’t use it for anything else.

1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

Can you at least explain to me the author’s procedure.:arteest:
I looked a little xpresso code e.i (node sheme, like cebas Thinking Particles) but not understand order of events. Cinema4D is cool software bat Max is the best after all.:bowdown:

here is a little toy for anyone who wants to play with “stepper” idea:


  try(destroydialog pfs_geo_Rollout) catch()
  global pfs
  global geo
  rollout pfs_geo_Rollout "PFS and GEO by denisT" 
  (
  	group "Startup: "
  	(
  		button delete_all "Delete All" width:180 offset:[0,0]
  	)
  	on delete_all pressed do undo "Delete All" on delete objects
  		
  	group "Particle Flow: "
  	(
  		checkbox showpart_ch "Show Particle Ticks" checked:on
  		checkbox numbering_ch "Show Particle ID" checked:on
  		spinner rate_sp "Rate: " range:[0,1e9,30] type:#integer fieldwidth:56
  		spinner speed_sp "Speed: " range:[0,1e9,100] type:#integer fieldwidth:56
  		spinner divergence_sp "Divergence: " range:[0,1e9,0] type:#integer fieldwidth:56
  		spinner life_sp "Life Span: " range:[0,1e9,30] type:#integer fieldwidth:56
  		label direction_lb "Direction:" across:2 align:#right offset:[-38,6]
  		dropdownlist direction_dd items:#("Vertical","Center Out","Random 3D","Random Horizontal") width:120 align:#right offset:[0,2]
  		button create_pfs "Create Particles" width:180 offset:[0,2]
  --		button show_pfs "Show Particles Toggle" width:180 offset:[0,-2]
  	)
  	on show_pfs pressed do undo "Show PF" on if isvalidnode (pfs = getnodebyname "_theParticles") do pfs.ishidden = not pfs.ishidden
  	
  	group "Geometry: "
  	(
  		checkbox showticks_ch "Show Vertex Ticks" checked:on
  		label type_lb "Type:" across:2 align:#right offset:[-38,6]
  		dropdownlist type_dd items:#("Sphere","Box","Plane","Line","Curve") width:120 align:#right offset:[0,2]
  		button create_geo "Create Geomerty" width:180 offset:[0,2]
  --		button show_geo "Show Geometry Toggle" width:180 offset:[0,-2]
  	)
  	on show_geo pressed do undo "Show GEO" on if isvalidnode (pfs = getnodebyname "_theGeometry") do geo.ishidden = not geo.ishidden
  	
  	local ops = #()
  	
  	fn getDirection = case direction_dd.selection of
  	(
  		1: 0
  		2: 2
  		3: 3
  		4: 4
  	)
  	on create_pfs pressed do --undo "Create" on 
  	(
  		if isvalidnode (pfs = getnodebyname "_theParticles") do delete pfs
  		theHold.Begin()
  		pfs = PF_Source name:"_theParticles" X_Coord:0 Y_Coord:0 Emitter_Length:40 Emitter_Width:40 \
  			Quantity_Viewport:100 Show_Logo:on Show_Emitter:on Emitter_Type:2 wirecolor:blue
  				
  --		particleFlow.BeginEdit()
  		op1 = Birth name:"_birth" Emit_Stop:(3000f).ticks rate:rate_sp.value type:1
  		op2 = Position_Icon()
  		op3 = Speed name:"_speed" speed:speed_sp.value variation:5 reverse:on divergence:divergence_sp.value direction:(getDirection())
  --		op4 = Age_Test name:"_age_test" test_value:(30f).ticks
  		op5 = DeleteParticles name:"_delete_particles" type:2 life_span:(life_sp.value as time).ticks
  		op6 = DisplayParticles name:"_display_particles" show_numbering:numbering_ch.state color:pfs.wireColor type:(if showpart_ch.state then 2 else 0)
  		op7 = RenderParticles name:"_render" type:3
  		ev1 = Event name:"_event"
  		ev1.SetPViewLocation (pfs.X_Coord) (pfs.Y_Coord+100)
  --		particleFlow.EndEdit()
  		
  		ev1.AppendAction op1
  		ev1.AppendAction op2
  		ev1.AppendAction op3
  --		ev1.AppendAction op4
  		ev1.AppendAction op5
  		ev1.AppendAction op6
  		pfs.AppendAction op7
  		pfs.AppendInitialActionList ev1
  --		pfs.activateParticles on
  		theHold.Accept "Make PF"
  		
  		ops = #(op1,op2,op3,op4,op5,op6,op7)
  		pfs
  	)
  	fn constrain value minimum maximum = (amax minimum (amin maximum value))
  
  	fn particleBindController index number node pf =
  	(
  		c = point3_script()
  		c.AddConstant "index" index
  		c.AddConstant "number" number
  		c.AddObject "pf" (NodeTransformMonitor node:pf)
  		c.AddNode"node" node
  		str = "(if isvalidnode pf and index <= (count = pf.numParticles()) then (pf.getParticlePosition (count - index + 1)) else [0,0,0])*(inverse node.transform)"
  		c.setExpression str
  		c
  	)
  	fn bindPoints node pf = 
  	(
  		suspendEditing()
  		animatevertex node #all
  		cc = for c in (getPointControllers node) where c != undefined collect c 
  		for k=1 to cc.count do replaceinstances cc[k] (particleBindController k cc.count node pf)
  		resumeEditing()
  		ok
  	)
  	on create_geo pressed do undo "Create theGeo" on 
  	(
  		if isvalidnode (geo = getnodebyname "_theGeometry") do delete geo
  		geo = case type_dd.selection of
  		(
  			1: converttomesh (geosphere segments:2)
  			2: converttomesh (box width_segs:1 length_segs:1 height_segs:1)
  			3: converttomesh (plane width_segs:4 length_segs:4) 
  			4: 
  			(
  				geo = converttosplineshape (helix turns:0.5)
  				open geo 1
  				geo
  			)
  			5: 
  			(
  				geo = converttosplineshape (ngon nsides:24 circular:on)
  				open geo 1
  				geo
  			)
  		)
  		geo.name = "_theGeometry"
  		geo.vertexTicks = showticks_ch.state
  		geo
  		
  		if isvalidnode (pfs = getnodebyname "_theParticles") do bindPoints geo pfs
  	)
  
  	fn updateGeo geo = if isvalidnode (geo = getnodebyname "_theGeometry") do for c in (getPointControllers geo) do c.update()
  	fn update = if iskindof pfs PF_Source do undo "Change PF" on
  	(
  		if isvalidnode (pfs = getnodebyname "_theParticles") do 
  		(
  			pfs._event._display_particles.type = if showpart_ch.state then 2 else 0
  			pfs._event._display_particles.show_numbering = numbering_ch.state
  			pfs._event._birth.rate = rate_sp.value
  			pfs._event._speed.speed = speed_sp.value
  			pfs._event._speed.divergence = divergence_sp.value
  			pfs._event._delete_particles.life_span = (life_sp.value as time).ticks
  			
  			pfs._event._speed.direction = getDirection()
  			
  			pfs.activateParticles on
  			updateGeo geo
  		)
  	)
  	
  	on showpart_ch changed state do update()
  	on numbering_ch changed state do update()
  	on rate_sp changed val do update()
  	on speed_sp changed val do update()
  	on divergence_sp changed val do update()
  	on life_sp changed val do update()
  	on direction_dd selected sel do update()
  	
  	on showticks_ch changed state do if isvalidnode (geo = getnodebyname "_theGeometry") do geo.vertexTicks = state
  )
  createdialog pfs_geo_Rollout width:200
  

PS: It’s a debug code (not optimized, not beautified, etc.). So please don’t use it as a sample how to write the max script code

to gazybara:
as you see I’ve agreed with the most your solutions …

1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

Thanks Denis
Ok, you add UI with most important parameters and produce almost same result as Simon Russell tool. Is not the point to create exactly the same tool, but get fluid movement of animated verts from one particle to another (like in posted image). What the tool need is distance interpolation between particle. ei
let say step = 5
on frame0 vert1 position = particle1 position
on frame5 vert1 position = particle2 position
but inbetween :
on frame1 vert1 position =(distance particle1 position particle2 position)*1/5
on frame2 vert1 position =(distance particle1 position particle2 position)*2/5

etc.

Is it difficult to achive such a movemet of the verts?
I attach a file as an example of how it should look like fluid-like movement of polystepper.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

it’s possible. but the goal is to control the geo point positions by the indexed particles. script the particles movement and get any geo deformation.