Notifications
Clear all

[Closed] Flippin Flipper

So I recently came across some cool tools for making flipping animation and from those tools I’ve become inspired to make ones myself and not only that but make it in a collaborative environment with the community. In doing this I’d love to get everyone’s ideas and improvements along the way so we can make a solid and free tool for everyone to use and play with. My inspiration came from http://www.scriptspot.com/3ds-max/scripts/flaps and this http://vimeo.com/49746483 . The goal is to take these tools and not only recreate them but vastly improve upon them with new implemented ideas. Anyone is more than welcome to jump in and supply ideas, improvements upon scripts, code snippets, or anything else that would help improve this tool.

So lets begin!..

First thing I’d like to do is narrow down the super basic methodology of how this operates.
My initial thought was that he was exploding the object’s polygon’s into individual objects…on second thought I do believe he is just doing all the animation within the editable poly object. He appears to be however ‘splitting’ all edges. From there its going polygon by polygon rotating each one from it’s edge.

So the first step is getting something basic like this to work and then we will add all the fun gadgets and controls.

24 Replies

Part one: Edge splitting.


clearlistener()
curSel = selection as array

for i = 1 to curSel.count do (
	obj = curSel[i]
	edgeCount = polyop.getNumEdges obj
	edgeList = (for s = 1 to edgeCount collect s)
	
	polyop.splitEdges obj edgeList
)


clearlistener()

/*------------------Snapshot/copy the original mesh and collapse to editable poly---------------*/
curSel = for o in (getCurrentSelection()) where superclassof o == GeometryClass collect (
	convertTo (snapshot o) editable_poly
)

/*------------------Split all polygons into seperate elements for each object---------------*/
for i = 1 to curSel.count do (
	obj = curSel[i]
	edgeCount = polyop.getNumEdges obj
	edgeList = (for s = 1 to edgeCount collect s)
	
	polyop.splitEdges obj edgeList
)

curSel.wirecolor = yellow
select curSel

it might help:



fn sharedEdge node f1 f2 = 
(
	ee = (polyop.getedgesusingface node f1)*(polyop.getedgesusingface node f2)
	(ee as array)[1]
)
fn setPivotRotation obj point =
(
	worldAlignPivot obj
	local rot = inverse point.rotationpart
	
	animate off in coordsys local obj.rotation *= rot
	obj.objectoffsetrot *= rot
	obj.objectoffsetpos *= rot
	obj.objecttransform
)
fn getFlipTM node face edge flipnode: = 
(
	vv = polyop.getedgeverts node edge 
	normal = polyop.getfacenormal node face
	center = (polyop.getvert node vv[1] + polyop.getvert node vv[2])/2
	side = normalize (polyop.getvert node vv[2] - polyop.getvert node vv[1])
	
	front = normalize (cross side normal)
	tm = matrix3 front side normal center
	if isvalidnode flipnode do 
	(
		setPivotRotation flipnode tm
		flipnode.pivot = center
	)
	tm
)
fn getFaceGrowing node = if iskindof node Editable_Poly do
(
	fn getNeighbours node face exclude:#{} shareEdges:on = 
	(
		ee = polyop.getedgesusingface node face
		ff = (polyop.getfacesusingedge node ee) - exclude
		if shareEdges do
		(
			for f in ff where (ee*(polyop.getedgesusingface node f)).isempty do ff[f] = off
		)
		ff
	)
	
	faces = #()
	done = #{}
	ff = node.selectedfaces as bitarray
	done = copy ff
	group_id = 0
	while not ff.isempty do
	(
		old = copy done
		group_id += 1
		for f in ff do
		(
			neighbours = getNeighbours node f exclude:done
			nn = #(f, neighbours, group_id)
			--format "%
" nn

			join done neighbours
			append faces nn
		)
		ff = done - old
	)
	faces
)
delete objects
n = 5
p = converttopoly (plane widthsegs:n lengthsegs:n isseelcted:on)
--seed 0
p.selectedfaces = #{random 1 p.numfaces,random 1 p.numfaces,random 1 p.numfaces} 
flips = getFaceGrowing p

s = 8
tt = [0,s]
by_group = off
for ff in flips do 
(
	for f in ff[2] do
	(
		t = if by_group then (tt + ff[3]*s) else (tt += ff[3]*s)
		e = sharedEdge p ff[1] f
		polyop.detachFaces p f name:("f" + formattedprint f format:"03d") delete:off asNode:on
		n = objects[objects.count]
		tm = getFlipTM p f e flipnode:n
		addnewkey n.rotation.controller t[1] 
		addnewkey n.rotation.controller t[2] 
		n.rotation.controller[2].keys[1].value = if dot (cross (polyop.getfacecenter p f - polyop.getfacecenter p ff[1]) tm[3]) tm[2] > 0 then 180 else -180
		n.rotation.controller[2].keys[2].value = 0

		n.visibility = Boolean_Float()
		addnewkey n.visibility.controller (t[1]-1) 
		addnewkey n.visibility.controller t[1]
		n.visibility.controller.keys[1].value = 0
		n.visibility.controller.keys[2].value = 1
	)
)
polyop.deletefaces p (p.faces as bitarray - p.selectedfaces as bitarray)
update p

i didn’t do any optimization. (!!!)

Hey Denis,
Thanks for the huge contribution of nearly the entire basic foundation to the script. Great work, rather really quick turn around.

So the optimization begins.

Bugs to fix:

  • Running this on a teapot we notice the rotation of each poly can be incorrect and doesn’t appear to line up.

it’s not a bug. the current code just doesn’t support not flat geometry. i always rotate on -180(or 180) deg. which is correct for flat geometry only.

I understand what your saying, I guess I meant the ‘bug’ as something to aware of that’s all. And something which needs attention.

Returns the angle between two objects who are made up of only 1 polygon each.

fn getAngleBetweenFaces objA objB =
(
	faceA = polyop.getFaceNormal objA 1
	faceB = polyop.getFaceNormal objB 1
	
    theAngle = acos(dot (normalize faceA) (normalize faceB))
		
	if theAngle < 0 then (
		theAngle = 360 - theAngle
	)
	normAngle = 180 - theAngle
	return normAngle
)

getAngleBetweenFaces selection[1] selection[2]



here is not flat version:


fn sharedEdge node f1 f2 = 
(
	ee = (polyop.getedgesusingface node f1)*(polyop.getedgesusingface node f2)
	(ee as array)[1]
)
fn setPivotRotation obj point =
(
	worldAlignPivot obj
	local rot = inverse point.rotationpart
	
	animate off in coordsys local obj.rotation *= rot
	obj.objectoffsetrot *= rot
	obj.objectoffsetpos *= rot
	obj.objecttransform
)
fn getFlipTM node face edge flipnode: = 
(
	vv = polyop.getedgeverts node edge 
	normal = polyop.getfacenormal node face
	center = (polyop.getvert node vv[1] + polyop.getvert node vv[2])/2
	side = normalize (polyop.getvert node vv[2] - polyop.getvert node vv[1])
	
	front = normalize (cross side normal)
	tm = matrix3 front side normal center
	if isvalidnode flipnode do 
	(
		flipnode.pivot = center
		setPivotRotation flipnode tm
	)
	tm
)
fn getFaceGrowing node = if iskindof node Editable_Poly do
(
	fn getNeighbours node face exclude:#{} shareEdges:on = 
	(
		ee = polyop.getedgesusingface node face
		ff = (polyop.getfacesusingedge node ee) - exclude
		if shareEdges do
		(
			for f in ff where (ee*(polyop.getedgesusingface node f)).isempty do ff[f] = off
		)
		ff
	)
	
	faces = #()
	done = #{}
	ff = node.selectedfaces as bitarray
	done = copy ff
	group_id = 0
	while not ff.isempty do
	(
		old = copy done
		group_id += 1
		for f in ff do
		(
			neighbours = getNeighbours node f exclude:done
			nn = #(f, neighbours, group_id)
			--format "%
" nn

			join done neighbours
			append faces nn
		)
		ff = done - old
	)
	faces
)

fn getAngleBetween up1 up2 side =
(
	ang = acos (dot up1 up2)
	act = (dot (cross up1 side) (cross up2 side)) <= 0 	
	
	if not act then 180-ang else 360-ang
)

delete objects
n = 20
--p = converttopoly (plane widthsegs:n lengthsegs:n isselected:on)
--p = converttopoly (teapot handle:off lid:off spout:off isselected:on)
p = converttopoly (geosphere segments:2 isselected:on)
--p = converttopoly (box widthsegs:n lengthsegs:n heightsegs:n isselected:on)
seed 0
--fetchmaxfile quiet:on
max select all
p = $
p.selectedfaces = #{random 1 p.numfaces,random 1 p.numfaces,random 1 p.numfaces} 
--p.selectedfaces = #{random 1 p.numfaces} 
flips = getFaceGrowing p

s = 10
tt = [0,s]
by_group = off
max create mode
slidertime = 0
nodes = #()
for ff in flips do 
(
	for f in ff[2] do
	(
		t = if by_group then (tt + ff[3]*s) else (tt += ff[3]*s)
		e = sharedEdge p ff[1] f
		polyop.detachFaces p f name:("f" + formattedprint f format:"03d") delete:off asNode:on
		n = objects[objects.count]
		--n.wirecolor = random white black
		ptm = getFlipTM p ff[1] e
		tm = getFlipTM p f e flipnode:n

		c = n.rotation.controller = Rotation_List()
		a = c.available.controller = Euler_XYZ()
		c.active = c.count

		addnewkey a[2].controller t[1] 
		addnewkey a[2].controller t[2] 
		ang = getAngleBetween ptm[3] tm[3] tm[2]
		act = dot (cross (polyop.getfacecenter p f - polyop.getfacecenter p ff[1]) tm[3]) tm[2] < 0
		ang = if act then ang-360 else 360-ang
		a[2].controller.keys[1].value = ang

		n.visibility = Boolean_Float()
		v = n.visibility.controller
		addnewkey v (t[1]-1) 
		addnewkey v t[1]
		v.keys[1].value = 0
		v.keys[2].value = 1
	)
)
polyop.deletefaces p (p.faces as bitarray - p.selectedfaces as bitarray)
update p

Great.
These are the controls I’m looking to add. What other ideas do you guys have for controls…

Controls:
Supports a multiple selection of objects
If no edge selection is made then randomly select starting edges.

  • Option for X-number of random starting edges if user doesn’t want to select any

Time Settings:

  • Start/End frame

  • Starting delay (the time ‘paused’ between each starting flipper)
    0.0 = means all starting flippers begin at the same time
    1.0 = means flipper(2) starts 1 frame after flipper(1) & flipper(3) starts 1 frame after flipper(2)…

  • Flipping durtion (180 degree based) Larger angles = longer time, Shorter Angles = shorter time

  • Flipping Offset (the time between each flipped polygon) only useable if not using Start/End frame
    0.0 = means next flip starts as soon as the previous ends
    1.0 = means next flip starts 1 frame after the previous one ends
    -1.0 = means the next flip starts 1 frame before the previous one ends

  • Age (time in which the polygon remains visible after completing its rotation)

Flipping Options:

  • UseFaceAngle
  • Offset = subtracts from the original face rotation angle. Results in having less of a rotation than it originally did. (Only available when using faceAngle)
  • Set Rotation Angle = a set angle in which the all faces will rotate no matter what.
  • Pivot (center or edge)
  • Scaling option going from 0.0% at its starting rotation and then 100% at it’s end rotation with ease in curves.
Page 1 / 3