PolySplitRing Tool - Script idea


#1

Hi,
A friend just showed me the PolySplitRing tool in Maya, and boy, do I wish we had that in Max !

Basically, it allows you to insert Edge Loops at the position of the mouse. Really neat !

I am trying to have a go at it…
but I need help (specially for the preview/mouse parts)

So, How to do this in max ???
pseudo code:

  1. get the object under the mouse
  2. get the face under the mouse
  3. get the faces’ edge closest to the mouse
  4. ring select the edge
  5. divide the edges using the position of the mouse between the edgeVerts
  6. connect the new vertices
fn divideEdges obj val = (
obj.SelectEdgeRing()
RingEdges=(polyop.getEdgeSelection obj) as array
polyop.setEdgeSelection obj #()
polyop.setVertSelection obj #()
for e in RingEdges do obj.divideEdge e val select:true
obj.ConnectVertices()
)

What would be the best implementation for this ? a Tool, a MouseTrack ?

the CleanCut script ( http://www.scriptspot.com/rhyde/cleancut.html ) can be good base to start

If any of you script gurus want to have a go at it, I’m sure the max community would appreciate this tool !

Any hints, infos, code etc… most welcome !


#2

We just had a long thread at Polycount about this:

http://boards.polycount.net/showthread.php?t=58089

I didn’t get a chance to contribute anything significant, but if anyone here comes up with a better solution than what that other guy did, please post it there, or I can do it.


#3

I know this doesn’t help with scripting but… Polyboost has this tool. (and more) http://www.polyboost.com/

go to Features, Modeling, then scroll down to Poly Draw.


#4

Thx for the input.
The thread @ polycount is very interesting !

I hope to post something in a few days…


#5

You may want to look at the IllusionCatalyst Draw Loop tool. It appears that it may do what you want, and is free.

-Eric


#6

Hi guys,
IllusionCatalyst (version 1.1.1) can insert an edge loop only in the middle of edge crossed, by using the Draw tool and pressing SHIFT. I already coded an update which allows to insert the loop anywhere according to the crossing edge position. Unfortunately it doesn’t have a preview feature. I tried to get something with gw viewport drawing, but came up to nothing good. I guess the SDK can provide a better way, like the hint dashed line got in the standard cut tool. If you like my set of instruments and consider this feature fundamental, I can pack up a small new release.

p.s.
Thanks Eric for remembering and pointing out my tools.

  • Enrico

#7

Hi Enrio
I just tried you scripts !!! WAY cool !!!
and open source… WoW !! thx a bunch

I shamelessly stole code from CleanCut…

well, I managed to get the object, then the face, then the edge
and I can show a preview, BUT, I can’t get the preview to update with the mouse moving…
(though the real function inserts the loop at the mouse point…
also, There is a problem when edges are not ordered…

maybe that can give someone an idea…
NOTE: VERY BUGGY AND NOT FINISHED


---------------------------------------------
---- Mosttly inspired from Cleancut:
---- [http://www.scriptspot.com/rhyde/cleancut.html](http://www.scriptspot.com/rhyde/cleancut.html)
----------------------------------------------
macroScript Insert_Loop
category:"Zbuffer"
(
 global rcvb -- the redraw callback
 unRegisterRedrawViewsCallback  rvcb
 local thresh
 local RingEdges
 local Edge_Percent=0.5
 local PolyObj
 local MeshObj
 local PolyIndex
 local EdgeIndex
 local clickPoint
 local FirstClick=true
 -- From CLeanCut
 fn getPolyIndexFromTri msh poly tri =
 (
  triverts = (meshop.getVertsUsingFace msh tri) as array
  result = undefined
  allVertsFaces = #()
  for item in triverts do
  (
   append allVertsFaces ((polyOp.getFacesUsingVert poly item) as array)
  )
  for item in allVertsFaces[1] do
  (
   if (((findItem allVertsFaces[2] item) != 0) and ((findItem allVertsFaces[3] item) != 0)) do
   (
	result = item
   )
  )
  result
 )

 fn GetPosAlongEdges obj edges val =
 (
  local pos=#()
  for edg in edges do
  (
   v=polyop.getEdgeVerts obj edg
   sort v
   p1=Polyop.getVert obj v[1]
   p2=Polyop.getVert obj v[2]
   append pos (p1+((p2-p1)*val))
  )
  pos
 )
 -- From CleanCut
 fn autoThreshold obj samples:5 factor:8 =
 (
  seed(random (random 1 65535) (random 1 65535))
  alength = 0
  for i in 1 to samples do
  (
   rnd_idx = random 1 obj.numFaces
   fac = obj.faces[rnd_idx].index
   edg = (polyOp.getFaceEdges obj fac as array)[1]
   e_verts = polyOp.getEdgeVerts obj edg as array
   alength += (distance (polyOp.getVert obj e_verts[2]) (polyOp.getVert obj e_verts[1]))
  )
  thresh = ((alength/samples)/factor)
 )

 fn isClosedRing obj edges =
 (
  res=false
  faces1 = polyop.getEdgeFaces obj edges[1]
  faces2 = polyop.getEdgeFaces obj edges[edges.count]
  for i in faces2 do if finditem faces1 i !=0 do res=true
  res
 )
 -- the redraw Callback
 fn highlightEdges =
 (
  l_col = green
  gw.setColor #line l_col
  local pos=GetPosAlongEdges PolyObj RingEdges Edge_Percent
  posPairs=#()
  for i=1 to (pos.count-1) do
  (
   append posPairs #(pos[i], pos[i+1])
  )
  if (isClosedRing PolyObj RingEdges) do append posPairs #(pos[pos.count], pos[1])
  for edg in posPairs do
  (
   pt1 = edg[1]
   pt2 = edg[2]
   v = (pt2 - pt1)
   v_len = length v
   sz = thresh/30
   vm = matrixFromNormal (normalize v)
   vm.translation = pt1
   gw.setTransform vm
   for i in 0 to 90 by 30 do
   (
	x = sz * (cos i)
	y = sz * (sin i)
	gw.polyline #([x,y,0], [x,y,v_len]) false
	gw.polyline #([-x,-y,0], [-x,-y,v_len]) false
	gw.polyline #([-x,y,0], [-x,y,v_len]) false
	gw.polyline #([x,-y,0], [x,-y,v_len]) false
   )
  )
  gw.enlargeUpdateRect #whole
  gw.updateScreen()
 )
 -- pointer to the redraw callback function
 fn rvcb = highlightEdges()
 -- does the real thing
 fn divideEdges obj val =
 (
  undo "InsertLoop" on
  (
   obj.SelectEdgeRing()
   polyop.setEdgeSelection obj #()
   polyop.setVertSelection obj #()
   for e in RingEdges do obj.divideEdge e val select:true
   obj.ConnectVertices()
  )
 )
 -- find the closest edge to the mouse with the face index
 fn FindClosestEdge f pt =
 (
  FaceEdges=polyop.getFaceEdges PolyObj f
  closest=999999
  idx=undefined
  for edg in FaceEdges do
  (
   EdgeVerts=polyop.getEdgeVerts PolyObj edg
   EdgePos=((polyop.getVert PolyObj EdgeVerts[1]) + (polyop.getVert PolyObj EdgeVerts[2]))/2.0
   d=distance pt EdgePos
   if d<closest do (closest=d; idx=edg)
  )
  idx
 )
 -- the Mouse Track function - only preview
 fn DoInsertLoop msg ir obj faceNum shift ctrl alt =
 (
  case msg of
  (
   #freemove:(if FirstClick then #continue else #stop)
   #mousePoint:( -- user clicked once
	if FirstClick then
	(
	 unRegisterRedrawViewsCallback  rvcb
	 PolyIndex = getPolyIndexFromTri MeshObj PolyObj faceNum
	 EdgeIndex=FindClosestEdge PolyIndex ir.pos
	 polyop.setEdgeSelection PolyObj EdgeIndex
	 PolyObj.SelectEdgeRing()
	 RingEdges=(polyop.getEdgeSelection PolyObj) as array
	 polyop.setEdgeSelection PolyObj #()
	 FirstClick=false
	 RegisterRedrawViewsCallback  rvcb
	 #continue
	)
	else
	(
	 divideEdges PolyObj Edge_Percent
	 if isValidNode MeshObj do delete MeshObj
	 unRegisterRedrawViewsCallback rvcb
	 #stop
	)
   )
   #mouseMove:( -- user clicked and is moving the mouse
	if FirstClick do
	(
	 unRegisterRedrawViewsCallback  rvcb
	 clickPoint=ir.pos
	 PolyIndex = getPolyIndexFromTri MeshObj PolyObj faceNum
	 EdgeIndex=FindClosestEdge PolyIndex ir.pos
	 polyop.setEdgeSelection PolyObj EdgeIndex
	 PolyObj.SelectEdgeRing()
	 RingEdges=(polyop.getEdgeSelection PolyObj) as array
	 polyop.setEdgeSelection PolyObj #()
	 FirstClick=false
	 RegisterRedrawViewsCallback  rvcb
	)
	v1=polyop.getVert PolyObj ((polyop.GetEdgeVerts PolyObj EdgeIndex)[1])
	v2=polyop.getVert PolyObj ((polyop.GetEdgeVerts PolyObj EdgeIndex)[2])
	-- Buggy - need to check the direction of the edge
	-- Edge_Percent=1-((distance ir.pos v1)/length (v2-v1))
	Edge_Percent=((distance ir.pos v1)/length (v2-v1))
	if Edge_Percent<0 do Edge_Percent=0
	if Edge_Percent>1 do Edge_Percent=1
	--   unregisterRedrawViewsCallback rvcb
	--   registerRedrawViewsCallback rvcb
	-- redrawViews()
	--highlightEdges()
	--#continue
   )
   #mouseAbort:
   (
	if isValidNode MeshObj do delete MeshObj
	unregisterRedrawViewsCallback rvcb
	return #stop
   )
  )
  #continue
 )
 ------------------------------------------------------------------------------
 if selection[1] != undefined do
 if classof selection[1].baseObject == Editable_Poly do
 (
  local obj=selection[1]
  PolyObj=selection[1]
  MeshObj = snapshot obj
  hide MeshObj
  autoThreshold PolyObj factor:12
  mouseTrack on:MeshObj trackCallback:DoInsertLoop
  unRegisterRedrawViewsCallback  rvcb
  if isValidNode MeshObj do delete MeshObj
 )
)

please help me improve this mess :wink:


#8

Hi Zbuffer,
I’m on it, currently integrating IllusionCatalyst code into your script. The function to get polygon from face mesh isn’t accurate, because it doesn’t consider the case where three vertices from the same mesh face belong to two polygons. By now I made it draw an edge loop according to the second mouse click position and not in the middle, but doesn’t show right and updating preview yet. I’ll post some messy code too as soon as it start working someway, then we’ll go for optimization to solve heavy calculation issues, a simple recursive function is involved.

  • Enrico

#9

Cool !
i’m leaving for a few days…
I’ll try to post some update then…
Hope you can get this sorted out !
Merry Xmas to all


#10

Hi guys,
I’m glad to share IC_PolySplitRing script. This is my 3ds Max version of the most required Maya tool. Get it freely from IllusionCatalyst website in the MaxScript page.

The script has been thoroughly tested, anyhow please report any issue.
Thank you, enjoy!

  • Enrico

#11

Just downloaded it. If this works as intended, this will be my new favourite tool. :love:


#12

Very useful tool ~
unfortunately it can’t show end result with modifier now,but better than none.:applause:


#13

Nice one, thank you!!!

Maybe an option where you could specify whether the preview would show through shaded object or not, would make it even better: if the geometry is dense, the preview line will make the positioning of the new loop difficult.

Thanks again - amazing tool!

-Kimmo


#14

Thank you guys,
I got in mind some new features like showing the preview loop according to face normals (hide backfacing) and choosing colors for preview. On a first look, they would require some major modifications to the code, but I guess I’ll give it a try. In the meantime I found and corrected a small bug that prevented the tool quit with right mouse button click. The updated version is on the IllusionCatalyst website as usual. Please help me by reporting any bug. Thank you.

  • Enrico

#15

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.