Notifications
Clear all

[Closed] plexus WIP

This is the start of a plexus maxscript. It’s a work in progress, rather rough draft right now. Check it out. Open to suggestions and feature requests.


clearlistener()
delete objects

numCtrls = 20
numBranches = 5
ctrls = for c = 1 to numCtrls collect (point cross:true box:false pos:[random -50 50, random -50 50, random 0 50] wirecolor:yellow size:5)
plexusData = #()

fn getRandomNode nodes:#() excluded:#() =
(
	useableNodes = for node in nodes where (findItem excluded node) == 0 collect node
	count = random 1 useableNodes.count
	return useableNodes[count]
)

sp = splineshape pos:[0,0,0] wirecolor:blue name:(uniqueName "Plexus_")
for ctrl in ctrls do
(
	for b = 1 to numBranches do
	(
		addNewSpline sp
		spIndex = numSplines sp
		addKnot sp spIndex #corner #line ctrl.pos
		randomCtrl = getRandomNode nodes:ctrls excluded:#(ctrl)
		addKnot sp spIndex #corner #line randomCtrl.pos
			
		append plexusData #(ctrl,randomCtrl)
	)	
)
updateShape sp

fn wireKnotToCtrl knot: index: target: =
(
	if knot != unsupplied do
	(
		scriptCtrl = point3_script ()
		sp[4][8][knot].controller = scriptCtrl
		scriptCtrl.addTarget "control" plexusData[index][target][3]
		scriptCtrl.setExpression "control.pos" 
		scriptCtrl.getTarget "control" --Get the Target Track as SubAnim value
		scriptCtrl.getTarget "control" asObject:true --Get as Object
	)
)

/* Controlable Knots */
animateVertex sp #all
knotA = 2; knotB = 5
for k = 1 to plexusData.count do
(
	/* Knot A */
	wireKnotToCtrl knot:knotA index:k target:1
	wireKnotToCtrl knot:knotB index:k target:2
	
	/* Increment for each knot controller */
	knotA += 6; knotB += 6
)

/* Animation Ctrls */
sp.showFrozenInGray = false
sp.isfrozen = true
animationRange = interval 0f 144f
for t = animationrange.start to animationrange.end by 12 do
(
	with animate on at time t
	(
		for ctrl in ctrls do ctrl.pos = [random -50 50, random -50 50, random 0 50]
	)
)

9 Replies

Nice,
you could make the movement more organic by adding a slight wobble to the keyframes

for t = animationrange.start to animationrange.end by 12 do
(
		for ctrl in ctrls do 
		(
			local theTime = random (t-6) (t+6)
			with animate on at time theTime (ctrl.pos = [random -50 50, random -50 50, random 0 50])
		)
)

Nice touch grabjacket

Hey John,
Why don’t you use splineIKs instead?
Have you tested it with more control objects? i tried with 200 and the viewport performance drops dramatically.

Suggestions:

  1. Loading a point cloud to create the plexus object
  2. Selecting a geometry as point cloud with ability to skip nth Vertex
  3. setting number of knots per branch (currently it’s 2 – one at the start, one at the end)
  4. Adding Position Noise controllers on the control objects
  5. A master controller for the points to set the weight of the noise controller
  6. adding a flex modifier on the plexus object.
1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

This solution will eat a lot of memory. Probably bast way for plexus-like behavior is usage of cebas TP. Also Flex modifier have huge problem when “start animaton range” have value below 0.

Yeah I had created one once already using the spline ik. It still had performance issues and I wanted to see how this method proved to work. Seemingly there is no real solid method out there, especially if there are a lot of objects.

 em3

Thanks dude, this is awesome! It definitely gets the idea machine working. I will try to post some follow up ideas.

Hi, very nice script! Like the others…

It would be cool if the position of the points could “loop” at the and of time.

Hope to see updates

 JHN

You don’t need script controllers, you can just instance the position controllers of the nulls to the knots. As long as plexus is on world zero and nulls also have world as parent. I’ll bet performance will be better as well.

-Johan

I thought about giving thickness to those splines basing on distance between control points, but it needs each line to be separate shape. This is my approach, but it’s pretty slow unfortunately.

numK = 20

for i = 1 to numK do geosphere pos:[random -20.0 20.0, random -20.0 20.0, random -20.0 20.0] wirecolor:(Color (random 155 155) (random 0 55) (random 0 55)) segs:5 radius:(random 1.0 2.0) name:("ctrl"+i as string)
ctrls = for i = 1 to numK collect (getnodebyname ("ctrl"+i as string))

for t = animationrange.start+30 to animationrange.end+30 by 30 do
(
		for ctrl in ctrls do
		(
			local theTime = random (t-10) (t+10)
			with animate on at time theTime (ctrl.pos = [random -50 50, random -50 50, random 0 50])
		)
)

distmax = 35.0
thickmax = 2.5

for i = 1 to ctrls.count do
(
	for j = i+1 to ctrls.count do
	(
		sp = splineShape pos:[0,0,0] render_renderable:true render_displayRenderMesh:true wirecolor:(Color (random 150 255) (random 150 255) (random 150 255))

		scr = float_script()
		str = stringstream ""
		format ("dist = distance $"+ctrls[i].name+".pos $"+ctrls[j].name+".pos") to:str
		format ("
if dist>"+distmax as string+" then return 0.0 else return ((1.0-(dist/"+distmax as string+"))*"+thickmax  as string+")") to:str
		str = str as string
		scr.setExpression str
		sp.render_thickness.controller = scr

		addNewSpline sp
		addKnot sp 1 #corner #line ctrls[i].pos
		addKnot sp 1 #corner #line ctrls[j].pos
		updateShape sp
		animateVertex sp #all
		
		local lista = #()
		append lista (ctrls[i])
		append lista (ctrls[j])
		spm = Spline_IK_Control linkTypes:2 helper_list:lista
		addModifier sp spm
		ep = Edit_Poly()
		addModifier sp ep
	)
)