Notifications
Clear all

[Closed] Align and Size a Plane() to EPoly Quads…

could you post the image that shows how planes should be aligned and deformed in your sample?

Attached is an example … on the left is where the planes are aligned to quads only… whereas on the right is how those planes should be.

4 Replies
(@denist)
Joined: 11 months ago

Posts: 0

is it not easier to equally divide the quad and flatten it?

(@wallworm)
Joined: 11 months ago

Posts: 0

It’s something I thought about… but the functions I am using already presume Plane() primitives as input objects (later down the road) … so if I can figure out how to properly apply the FFD it will serve to 1) save me recoding other things and 2) teach me a little more about how the FFD works.

(@denist)
Joined: 11 months ago

Posts: 0

does it mean that you want to find a solution yourselves?

(@wallworm)
Joined: 11 months ago

Posts: 0

Well I would like help… as I’ve already pounded my head on the issue quite a bit. Sometimes seeing a solution is just as educational as figuring it out.

Because I could not figure out how to properly align the FFD control points, I started down another avenue (which is promising but has one major problem). I decided that I could just detach the faces as individual objects and tesselate them to my needs as the tesselation can create the same kind of geometry*.

*The problem is that the ordering of the vertices is very important and must match those of a Plane() that is converted to EPoly (where the bottom row is verts 1…5, row 2 is 6…10, etc). Unfortunately, when I use tessellate, that ordering is entirely wrong. And I know of no way to re-order verts.

So my next step was to do that tesselation and also create a plane (which is where the code below stops). The next step is going to be mapping the verts from tesselated quads to corresponding verts in the Plane… then moving the plane verts to those positions and deleting the tessellated mesh. That seems like a lot of steps (and depends on the tessellation providing consistent vertex ordering… which I have to test and figure out).

In the end, I am leaning toward the FFD being the easiest method (except that I cannot properly place the FFD control points… which is why I have been experimenting with other ideas).


 
 
clearlistener()
a = Box length: 64 width:64 height:64 
a.wirecolor = green
tp = Taper amount:-0.7
addmodifier a tp
convertToPoly a
power = 2
for p = 1 to polyop.getNumFaces a  do (
 newName = UniqueName "CutFace"
 polyop.detachFaces a #{p} asNode:true delete:false name:(newName) 
 thenode = getNodeByName newName
 thenode.wirecolor = red
 thenode.tesselateBy = 0
 thenode.tessTension = 0.0
 
 base = 1
 for its = 1 to power do (
  polyop.tessellateByFace thenode #all
  base *= 2 -- set the lengthsegs of plane below
 )
  vv = polyop.getfaceverts a p
  v1 = polyop.getvert a vv[1]
  v2 = polyop.getvert a vv[2]
  v3 = polyop.getvert a vv[3]
  v4 = polyop.getvert a vv[4]
  
  front = normalize (v1-v2)
  side = normalize (v2-v3)
  
  up = normalize (cross front side) 
  side = normalize (cross up front) 
  tm = matrix3 front side up v1
  
  w = (v2*(inverse tm)).x
  l = (v3*(inverse tm)).y
  tm = pretranslate tm [w/2, l/2, 0]
   
  p = plane width:w length:l widthsegs:base lengthsegs:base transform:tm
  p.name = uniqueName "PlaneAligned"
  p.wirecolor = blue
 
  convertToPoly p
)

 

i did it with FFD. do you want to see?

2 Replies
(@wallworm)
Joined: 11 months ago

Posts: 0

Yes, please do share!

(@denist)
Joined: 11 months ago

Posts: 0

  fn worldPointToFFD p ffd pos = 
  (
  	otm = p.objecttransform
  	mtm = (getModContextTM p ffd)*ffd.lattice_transform.value
  	bmin = getModContextBBoxMin p ffd
  	bmax = getModContextBBoxMax p ffd
  
  	v = (pos * (inverse otm) * mtm - bmin)/(bmax - bmin)
  	v.z = 0
  	v
  )
  fn alignPlaneToQuad node:selection[1] face:undefined planeDimension:[1,1] = if iskindof node Editable_Poly do 
  (
  	if face == undefined and node.selectedfaces.count > 0 do face = node.selectedfaces[1].index 
  	if face != undefined and (vv = polyop.getfaceverts node face).count == 4 do
  	(
  		v1 = polyop.getvert node vv[1]
  		v2 = polyop.getvert node vv[2]
  		v3 = polyop.getvert node vv[3]
  		v4 = polyop.getvert node vv[4]
  		
  		front = normalize (v1-v2)
  		side = normalize (v2-v3)
  		up = polyop.getfacenormal node face
  		center = polyop.getfacecenter node face
  		
  		tm = orthogonalize (matrix3 front side up center)
  		
  		tm = pretranslate tm [0.5, 0.5, 0]
  		p = plane width:1 length:1 widthsegs:planeDimension.x lengthsegs:planeDimension.y transform:tm
  		ffd = FFDBox deformType:1 tension:25.0 continuity:0.0
  		setDimensions ffd [2,2,2]
  		animateall ffd
  		addmodifier p ffd
  		modpanel.setcurrentobject ffd
  		ffd.control_point_1 = ffd.control_point_5 = worldPointToFFD p ffd v3
  		ffd.control_point_2 = ffd.control_point_6 = worldPointToFFD p ffd v4
  		ffd.control_point_3 = ffd.control_point_7 = worldPointToFFD p ffd v2
  		ffd.control_point_4 = ffd.control_point_8 = worldPointToFFD p ffd v1
  		p
  	)
  )
  
  /*
  delete objects
  b = box length:64 width:64 height:32
  addmodifier b (taper amount:-0.7)
  convertToPoly b
  --polyop.deletefaces b #{1..5}
  update b
  max modify mode
  for f in b.faces do alignPlaneToQuad node:b face:f.index planeDimension:[4,4]
  */
  

all FFD operations have to be in Modify Panel. you can find a code in this forum how to disable the panel redraw.

Denis… you a true Master! Thank you for your expertise

Now I have to absorb it.

Can you explain the function worldPointToFFD ? what is this line:


for k=1 to 3 where not (bit.isFinite v[k]) do v[k] = 0
 

This is when max prints 1.23456e-5 or 1.#INF. In this case bit.isFinite sets the value of the variable to 0.

1 Reply
(@wallworm)
Joined: 11 months ago

Posts: 0

Wow… I wish I knew that a year ago. I have had problems detecting 1.#INF in a couple circumstances in the past.

That’s OK. That it works is all I care about and it’s up to the user to be mindful of not applying this to a 10,000 quad object In my own use, it will generally only be processing a few dozen quads at a time at most… so it works just great!

Thank you again!

PS. When are you going to Program the Matrix interface (from the movie) where we can all just download knowledge!?!?

i’ve changed this line. i set only v.z to ZERO. which only makes sense. bbox in Z axis is 0

3 Replies
(@denist)
Joined: 11 months ago

Posts: 0

the thing becomes more complicated if we try to align to not flatten quad. the algorithm stops work in this case:


 delete objects
 b = box length:64 width:64 height:32
 addmodifier b (taper amount:-0.7)
 addmodifier b (bend angle:45)
 convertToPoly b
 --polyop.deletefaces b #{1..5}
 update b
 
 max modify mode
 pp = for f in b.faces collect alignPlaneToQuad node:b face:f.index planeDimension:[4,4]
 
(@wallworm)
Joined: 11 months ago

Posts: 0

Yes… this is definitely an issue … that is something for me to consider later as this helpful as is for the moment.

(@denist)
Joined: 11 months ago

Posts: 0

the old algorithm stops, but the new one works great.
there are some hints:

do we really need to align the plane to the quad if we use FFD anyway?

if we nevertheless want to have the ‘aligned-like’ transform for our plane could we do it after the FFD applied?

but you have to understand that it’s really slow(!) algorithm. any moving FFD points is slow!

here is a result of the new algorithm:

1 Reply
(@wallworm)
Joined: 11 months ago

Posts: 0

Are the FFD modified Planes still Planar in this? That would be spectacular! For what I needed this the planes must remain planar or they won’t be valid geometry for the game engine exporter. If so, I’d love to see the new algorithm!

BTW, I’ve updated the WW Credits to reflect your contribution with this specific script. I also shared mention of your excellence in the 1.869 entry into the changelog.

Your consistent and insightful help is always deeply appreciated Denis!

i want to give some time for anyone else to twist his brain…

thanks!

Page 2 / 2