Home Technical Talk

Split loop/insert loop script in max

polycounter lvl 18
Offline / Send Message
Slum polycounter lvl 18
So, I'm looking for a script in max that will function similar to "split loop" in Silo, or a similar feature I've seen used in maya.

In silo, you click an edge, hold a key down and move the mouse to slide where the loop will end up. Release the key to commit. Otherwise, it just splits the loop at the center (just like max Connect). Quick vid to see what I mean:

http://vimeo.com/2452071

To accomplish the same thing in Max, I usually I do this:
1)select edge
2)ring select
3)connect options/slide

which works great, but is way slower. I've also seen something in maya, where you just click the edge with the mouse and it inserts a loop at the cursor (no sliding).

I believe polyboost does this, but I was hoping to not shell out $150 for only one feature.

Replies

  • pior
    Offline / Send Message
    pior grand marshal polycounter
    I second that!
    I was wondering if such thing was available for Max ... yesterday!
  • reiro
    Offline / Send Message
    reiro polycounter lvl 10
    I was wondering aswell ;)
  • IronHawk
    Offline / Send Message
    IronHawk polycounter lvl 10
    third here. I know there is CSSlide http://ground-studios.com/stuff/meshtools/meshtools_eng.htm so really an addon to that script would be all thats needed I think.
  • Rob Galanakis
    Thanks for the link Ironhawk! I made the minor modifications needed (actually I re-wrote it for an hour and then decided to take a look... didn't want to figure out how to sort the verts, I was 'sliding' towards the edges randomly).

    http://www.robg3d.com/temp/csConnectAndSlide.ms

    Just run the script and you should get a Macro under "csPolyTools" called "Connect and Slide"
  • DInusty
    Offline / Send Message
    DInusty polycounter lvl 17
    OMG Rob the second coming! thanks ^_^

    What version of max is this for?

    one thing u should know is that if u space out and use the macro without a edge selected it crashes the max viewport. :/

    i dont know how scripting works but i think what you would have to tell it to do is select the edge that ur clicking on and then run the rest of the script.
  • Rob Galanakis
    Darn, stupid error. Should be fixed.

    Max 6 and up, I think... definitely max 8 and up though.

    Just a note, if you have multiple edges selected when you do this, it doesn't really work right... this is just a problem with the way the 'slide' tool is implemented in csPolyTools, and not something I'm going to rewrite right now.
  • IronHawk
    Offline / Send Message
    IronHawk polycounter lvl 10
    F'n nice Rob thanks!
  • Slum
    Offline / Send Message
    Slum polycounter lvl 18
    Sweet rob! Thanks! This is super awesome. Would it be possible to have the 'default' (no slide) behavior place the loop at the mouse cursor?
  • Rob Galanakis
    Yes but it'd be vastly more complex... I am currently getting ready for a big project launch at my site, but once that is up and running, I hope to do more community request script features; I'll add this somewhere at the top of the list. So you may have to wait a couple weeks (months?), but you're going to see some really revolutionary changes in how the MXS scripting community works.
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Slum wrote: »
    Sweet rob! Thanks! This is super awesome. Would it be possible to have the 'default' (no slide) behavior place the loop at the mouse cursor?


    Maybe someone can get this to work 100% of the time. http://www.bryancavett.com/edgeSlice.ms

    I'm getting the length of the first edge and a point clicked on the edge. Getting a percent from it and using it on the slide option for the connect command. Then I run a edge ring and connect with the new slide settings. Sometimes it works right and sometimes when i get a negative number for the percent(which is how the slide numbers work) it adds it to the positive side even though the percent variable says its negative.

    Anyways its almost there.

    Run the script and you will see a new category called "BCTools"

    Make sure 3d snap mode is on with edges picked. (I cant find out how to set it up in MXS)
    Select one edge and run it.
    Left click where you want to cut the edge.

    Here it is inline if you don't wanna d/l
    macroScript edgeSlice
    category: "BCTools"
    (
    	--Make sure 3d snaps are on and set to edge mode
    	--Works on one edge and auto rings and connects
    	fn edgeSlice msg ir obj faceNum shift ctrl alt =
    	(
    		if msg == #mousePoint then
    		(
    			local irPos =ir.pos
    			local edgeVerts
    			local edgeVector
    			local selectedEdges
    			local percent
    			for i = 1 to polyop.getNumEdges $ do
    			(
    				selectedEdges = polyop.getEdgesByFlag $ 1
    				if (findItem selectedEdges i) != 0 then
    				(
    					edgeVerts = polyop.getEdgeVerts $ i
    					edgeVector = polyop.getVert $ edgeVerts[2] - polyop.getVert $ edgeVerts[1]
    					clickVector =  irPos - polyop.getVert $ edgeVerts[1]
    					percent = (length clickVector)/(length edgeVector)
    					percent = (percent * 200) - 100
    					--print percent
    					$.EditablePoly.SelectEdgeRing ()
    					$.connectEdgeSlide = percent as integer
    					$.EditablePoly.ConnectEdges ()
    				)
    			)
    		)
    		else
    		(
    			if msg == #mouseAbort then #stop else #continue
    		)
    	)
    	
    	if selection.count == 1 and classOf selection[1].baseobject == Editable_Poly and subobjectlevel == 2 then
    	(
    		with undo on
    		(
    			mouseTrack node:$ snap:#3d trackCallback:edgeSlice()
    		)
    	)
    )
    
  • Rob Galanakis
    $.connectEdgeSlide

    My GOD I cannot believe I missed that. I really hate Editable Poly maxscript stuff. This is the umpteenth time I've looked for other ways to do things when the answer was hidden in one of the 25 sections with editable poly commands. God I hate you Max.
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    I think the problem with my code is that the edge slide changes which way it handles positive and negative values. So sometimes it works and sometimes it doesn't. I think it depends on vert order or newer geometry or someting... Who knows.

    Is there a way I can test the new vert positions based on a tolerance to my original hitpoint position? I thought maybe I could test the angle of their vectors from the origin or something. But then there is the problem of how do I undo that code and redo it with an inverse value of the percent. try() catch()? I cant seem to get this working. Any help would be appreciated.
  • CodeFather
    Offline / Send Message
    CodeFather polycounter lvl 15
    Polyboost has this nice tool called ShiftLoop, which behave just like the split loop in silo
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    I added some tests to fix the problems I had with my initial code and updated the version on my site. I tried to get it to work with whatever edge you had under your cursor but couldn't get it working. You just have to select an edge and then run the script and click a point on the edge.
    macroScript edgeSlice
    category: "BCTools"
    (
    	--updated Dec-8-2008
    	--Make sure 3d snaps are on and set to edge mode
    	--Works on one edge and auto rings and connects
    	fn edgeSlice msg ir obj faceNum shift ctrl alt =
    	(
    		if msg == #mousePoint then
    		(
    			local irPos = ir.pos
    			local edgeVerts
    			local edgeVector
    			local clickVector
    			local selectedEdges
    			local percent
    			local found = false
    			local flip = true
    			while not found do
    			(
    				for i = 1 to polyop.getNumEdges $ do
    				(
    					edgeVerts = polyop.getEdgeVerts $ i
    					edgeVector = polyop.getVert $ edgeVerts[2] - polyop.getVert $ edgeVerts[1]
    					clickVector =  irPos - polyop.getVert $ edgeVerts[1]
    					selectedEdges = polyop.getEdgesByFlag $ 1
    					if (findItem selectedEdges i) != 0 then
    					(
    						percent = (length clickVector)/(length edgeVector)
    						percent = ((percent * 200) - 100) as integer
    						found = true
    					)
    				)
    			)
    			try
    			(
    				with undo on
    				(
    					$.EditablePoly.SelectEdgeRing ()
    					$.connectEdgeSlide = percent
    					$.EditablePoly.ConnectEdges ()
    					$.baseobject.EditablePoly.ConvertSelection #Edge #Vertex
    					newVerts = (polyop.getVertsByFlag $ 1) as array
    					for k = 1 to newVerts.count do
    					(
    						vertPos = polyop.getVert $ newVerts[k]
    						theAngle = acos(dot (normalize vertPos) (normalize irPos))
    						if theAngle < 0.4 then
    						(
    							flip = false
    						)
    					)
    					if flip then
    					(
    						try(test.pos = [0,0,0]) catch(throw())
    					)
    				)
    			)
    			catch
    			(
    				max undo
    				polyop.setEdgeSelection $ selectedEdges
    				$.EditablePoly.SelectEdgeRing ()
    				$.connectEdgeSlide = -percent
    				$.EditablePoly.ConnectEdges ()
    			)
    		)
    		else
    		(
    			if msg == #mouseAbort then #stop else #continue
    		)
    	)
    	
    	if selection.count == 1 and classOf selection[1].baseobject == Editable_Poly and subobjectlevel == 2 then
    	(
    		oldEndResult = showendresult
    		showendresult = false
    		oldSnap = snapmode.active
    		oldType = snapmode.getOSnapItemActive 5 3
    		snapMode.active = true
    		snapmode.setOSnapItemActive 5 3 true
    		mouseTrack node:$ snap:#3d trackCallback:edgeSlice()
    		snapMode.active = oldSnap
    		snapmode.setOSnapItemActive 5 3 oldType
    		showendresult = oldEndResult
    	)
    )
    
  • Slum
    Offline / Send Message
    Slum polycounter lvl 18
    DUDE, thanks so much. That is wicked. I almost wrote this myself, but I thought I'd ask some of you more astute max scripters first. :)

    If Rob and Bryan joined forces, we'd have a case of epic win on our hands here.
  • adam
    Offline / Send Message
    adam polycounter lvl 20
    In that video, wouldn't Edge Connect + Move w/ Constrain to Edge work just as easily? Perhaps not on more complex shapes, but certainly on the more primitive ones.
  • j_bradford
    Offline / Send Message
    j_bradford polycounter lvl 17
    Polyboost has a feature called swiftloop. You simply click where you want the edge loop to be, and it places it. You can then immediately hold down alt and slide it to wherever along the normal. Holding down ctrl will also auto-select edge loops. Holding down shift when placing the edgeloop will also conform the loop to the meshflow.

    It's very intuitive.

    [edit] Oops, I saw at the bottom you mentioned already knowing about this with polyboost. My bad :\
  • Slum
    Offline / Send Message
    Slum polycounter lvl 18
    Adam: yeah, it does work. As I unsuccessfully tried to explain to people on IRC, there are already tons of ways to get this same job done, obviously. The standard max tricks have worked for me (and many others!) for years. The whole point in this tool is that its super-lightning-fast. Why create a loop and move it, when you can create it in the correct spot the first time?
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Let me know if there are bugs(I'm sure there are) or if it doesn't work the way you want... I'll try to fix it. Its kind of a hack.

    Hope it helps your workflow.

    The code is kinda hacky to... Rob probably knows a better way of doing this.

    Edit: Also I can make the ctrl, alt, and shift buttons do something different when they are held down as you left click.

    Something like split the edge 50/50 when ctrl is held down.
  • pior
    Offline / Send Message
    pior grand marshal polycounter
    (I'm with you Slum, never give up!)
    Maya's implementation of this tool is actually very, surprinsingly good!
  • IronHawk
    Offline / Send Message
    IronHawk polycounter lvl 10
    Adam.. a true slide is way more useful then edge constraints on anything but a box really =p
  • Ghostscape
    Offline / Send Message
    Ghostscape polycounter lvl 13
    j_bradford wrote: »
    Polyboost has a feature called swiftloop. You simply click where you want the edge loop to be, and it places it. You can then immediately hold down alt and slide it to wherever along the normal. Holding down ctrl will also auto-select edge loops. Holding down shift when placing the edgeloop will also conform the loop to the meshflow.

    It's very intuitive.

    [edit] Oops, I saw at the bottom you mentioned already knowing about this with polyboost. My bad :
    CodeFather wrote: »
    Polyboost has this nice tool called ShiftLoop, which behave just like the split loop in silo

    I can't find this tool anywhere in polyboost? I'd assume it'd be in the modeling tools?
    edit: going through the list of commands it looks like its buried in polydraw! time to bind this sucker.
  • Slum
    Offline / Send Message
    Slum polycounter lvl 18
    Bryan: I've had some time to test this guy out, and I've found a few issues. Occasionally the slide value will invert, so the loop will drop down on the opposite side of the ring.

    Also, it's not resetting the 'connect' dialog options, so if you happen to have your connect options set with like 3 segments + pinch + slide, it totally wacks out the edgeSlice. In fact, last night this happened, I reset the connect values to zero, then Max crashed when running the script. Hasn't happened again yet, though.
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Sorry about that Slum. Ill see if I can sort it all out. The inverted values should of been fixed if you have the latest version but then again it might be based on the scale of your scene. I'm using a tolerance to test and see if its flipped or not. The only real way to fix this is to do the math cut it myself instead of relying on the connect command.

    It will also wig out if you click on an edge that is not the one you have selected since it tests the hit point on the length of the selected edge to determine the percent.... maybe I should just cap the percent if you click on a different edge.

    Resetting the connect dialog should be easy.

    By the way... I'm kind of a noob when it comes to doing more complex things in MXS. Anything beyond simple automation, if/then statements , or loops and my coding really gets hacky. If any of you guys can get it working better then I can see what I did wrong!
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Ok I believe I got most of those bugs and some others I found all fixed! Found a better way of detecting if the edges got flipped by max so that should work. I also added the functionality of splitting it 50/50 if ctrl is held down.

    Let me know if you find more. http://www.bryancavett.com/edgeSlice.ms

    quick edit: found one more bug and updated

    edit 2:One more ninja edit
    macroScript edgeSlice
    category: "BCTools"
    (
    	--updated Dec-9-2008
    	--Make sure 3d snaps are on and set to edge mode
    	--Works on one edge and auto rings and connects
    
    	fn edgeSlice msg ir obj faceNum shift ctrl alt =
    	(
    		if msg == #mousePoint then
    		(
    			local irPos = ir.pos
    			local edgeVerts
    			local edgeVector
    			local clickVector
    			local selectedEdges
    			local percent
    			local percentFloat
    			local found = false
    			local flip = true
    			while not found do
    			(
    				for i = 1 to polyop.getNumEdges $ do
    				(
    					edgeVerts = polyop.getEdgeVerts $ i
    					edgeVector = polyop.getVert $ edgeVerts[2] - polyop.getVert $ edgeVerts[1]
    					clickVector =  irPos - polyop.getVert $ edgeVerts[1]
    					selectedEdges = polyop.getEdgesByFlag $ 1
    					if (findItem selectedEdges i) != 0 then
    					(
    						percent = (length clickVector)/(length edgeVector)
    						percent = ((percent * 200) - 100) as integer
    						if abs(percent) > 100 then percent = 0
    						found = true
    					)
    				)
    			)
    			try
    			(
    				with undo on
    				(
    					$.baseobject.EditablePoly.SelectEdgeRing ()
    					if ctrl == true then $.connectEdgeSlide = 0 else $.connectEdgeSlide = percent
    					$.baseobject.EditablePoly.ConnectEdges ()
    					$.baseobject.EditablePoly.ConvertSelection #Edge #Vertex
    					newVerts = (polyop.getVertsByFlag $ 1) as array
    					for k = 1 to newVerts.count do
    					(
    						vertPos = (polyop.getVert $ newVerts[k])
    						averagePos = length ((vertPos - irPos)/2)
    						if averagePos < 0.1 then
    						(
    							flip = false
    						)
    					)
    					if flip then
    					(
    						try(test.pos = [0,0,0]) catch(throw())
    					)
    				)
    			)
    			catch
    			(
    				max undo
    				polyop.setEdgeSelection $ selectedEdges
    				$.baseobject.EditablePoly.SelectEdgeRing ()
    				if ctrl == true then $.connectEdgeSlide = 0 else $.connectEdgeSlide = -percent
    				$.baseobject.EditablePoly.ConnectEdges ()
    				$.baseobject.EditablePoly.ConvertSelection #Edge #Vertex
    			)
    		)
    		else
    		(
    			if msg == #mouseAbort then #stop else #continue
    		)
    	)
    	
    	if selection.count == 1 and classOf selection[1].baseobject == Editable_Poly and subobjectlevel == 2 then
    	(
    		edgeSel = (polyop.getEdgesByFlag $.baseobject 1) as array
    		if edgeSel.count > 1 then messageBox "edgeSlice does not work on multiple edges!" Title:"Edge Slice Error"
    		if edgeSel.count == 0 then messagebox "edgeSlice requires a selected edge!" Title:"Edge Slice Error"
    		if 	edgeSel.count == 1 then
    		(
    			showendresult = false
    			oldSnap = snapmode.active
    			oldType = snapmode.getOSnapItemActive 5 3
    			oldPinch = $.connectEdgePinch
    			oldSlide = $.connectEdgeSlide
    			oldSegs = $.connectEdgeSegments
    			$.connectEdgePinch = 0
    			$.connectEdgeSlide = 0
    			$.connectEdgeSegments = 1
    			snapMode.active = true
    			snapmode.setOSnapItemActive 5 3 true
    			mouseTrack node:$ snap:#3d trackCallback:edgeSlice()
    			snapMode.active = oldSnap
    			snapmode.setOSnapItemActive 5 3 oldType
    			$.connectEdgePinch = oldPinch
    			$.connectEdgeSlide = oldSlide
    			$.connectEdgeSegments = oldSegs
    		)
    	)
    )
    
  • ArtsyFartsy
    I'm still confused as to why this is not the same thing as the slice plane tool under 'edit geometry' for the poly. And the quickslice button also allows you to change the angle on the fly.


    I guess the slice plane does have the drawback that it will slice through any parts of the mesh it touches, so it would be really hard to add resolution to a single chair leg for example, but how often does that come up?
  • pior
    Offline / Send Message
    pior grand marshal polycounter
    Hi Bryan, don't know if this is of any help but I got that when running your script:

    edgenoslice.gif

    Also is there any reason to do it as a MS as opposed to a mcr? It looks like executing the ms actually created the corresponding mcr in my UI/Macroscript folder. I don't know if this is common practice anyways (just found it a bit confusing)

    On a side note, I can run Rob's version just fine!
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Pior:That part of the code is getting and setting the edge snap check box... not sure why its throwing that error. I tried to reproduce it on my machine but could not. I've tested this in 2008 and 2009, which version is throwing the error?

    The reason why its a .ms instead of a .mcr is so you can run it once and let max place the macroscript where it needs to be placed. All new macroscipts that are ran from a .ms file get placed in the my documents max folder instead of where the base max folder is. It's something I heard bobo from cgtalk explain.
  • Slum
    Offline / Send Message
    Slum polycounter lvl 18
    Thats weird pior.. It works just fine for me on two different machines running Max 9.
  • pior
    Offline / Send Message
    pior grand marshal polycounter
    Oh this was tested on max8! Maybe that's why. What does this version do, that Robs does not?
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    I don't have a copy of max8 around. I believe everything I'm using works in max 8 but maybe not.

    I've found another bug.... its the same scale bug I thought I fixed. If you make a box that is 1000 units tall or wide then my checking to see if the edges are flipped breaks down.... need to find a proper way to scale the value I'm using for the tolerance.

    Ill keep you guys posted... hopefuly I'll get it there. Sorry for all the changes and bugs :(
  • Slum
    Offline / Send Message
    Slum polycounter lvl 18
    pior: it inserts a loop where you click the cursor.

    bryan: dont worry about it dude, thanks for getting it even this far. I've only had buggy issues in maybe 3 of the 400 times I used it the other day.
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    Bryan: You could use bounding box info from the object to scale your tolerance, I have used this before for similar things (basically the info that Utilities -> Measure returns). Can't remember offhand what the maxscript is, should be fairly easy to find in the help though.
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Mop: Yes I was looking at that last night. $.min and $.max to get the corners. The scale issue goes beyond that though. I'm trying to test the location of the original hit point and one of the newly created verts to see how close they are... if the vert is further than my tolerance then the connect got flipped. This would be easy if the slide value could be a float instead of an integer! The original hitpoint and one of the newly created verts would be directly on top of each other with a distance of 0.0 between them. Converting the percent to an integer causes another problem. I need to figure out how much to add back to the position to make up for that.
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    Ok I found a super simple way to prevent the edge flipping without messing with the scale. Atleast I hope I did... it seems to work on my end. This is probably the last time I'll update the script unless you guys find a glaring issue. Anyway d/l again for a much more reliable version.
    http://www.bryancavett.com/edgeSlice.ms
    macroScript edgeSlice --silentErrors:true
    category: "BCTools"
    (
    	--updated Dec-11-2008
    	--Make sure 3d snaps are on and set to edge mode
    	--Works on one edge and auto rings and connects
    	fn edgeSlice msg ir obj faceNum shift ctrl alt =
    	(
    		if msg == #mousePoint then
    		(
    			local irPos = ir.pos
    			local edgeVerts
    			local edgeVector
    			local clickVector
    			local selectedEdges
    			local percent
    			local found = false
    			while not found do
    			(
    				for i = 1 to polyop.getNumEdges $ do
    				(
    					edgeVerts = polyop.getEdgeVerts $ i
    					edgeVerts = sort edgeVerts
    					edgeVector = polyop.getVert $ edgeVerts[2] - polyop.getVert $ edgeVerts[1]
    					clickVector =  irPos - polyop.getVert $ edgeVerts[1]
    					selectedEdges = polyop.getEdgesByFlag $ 1
    					if (findItem selectedEdges i) != 0 then
    					(
    						percent = (length clickVector)/(length edgeVector)
    						percentDiff = percent - percent as integer
    						percent = ((percent * 200) - 100) as integer
    						if abs(percent) > 100 then percent = 0
    						found = true
    					)
    				)
    			)
    			$.baseobject.EditablePoly.SelectEdgeRing ()
    			if ctrl == true then $.connectEdgeSlide = 0 else $.connectEdgeSlide = percent
    			$.baseobject.EditablePoly.ConnectEdges ()
    		)
    		else
    		(
    			if msg == #mouseAbort then #stop else #continue
    		)
    	)
    	
    	if selection.count == 1 and classOf selection[1].baseobject == Editable_Poly and subobjectlevel == 2 then
    	(
    		edgeSel = (polyop.getEdgesByFlag $.baseobject 1) as array
    		if edgeSel.count > 1 then messageBox "edgeSlice does not work on multiple edges!" Title:"Edge Slice Error"
    		if edgeSel.count == 0 then messagebox "edgeSlice requires a selected edge!" Title:"Edge Slice Error"
    		if 	edgeSel.count == 1 then
    		(
    			showendresult = false
    			local oldSnap = snapmode.active
    			local oldType = snapmode.getOSnapItemActive 5 3
    			local oldPinch = $.connectEdgePinch
    			local oldSlide = $.connectEdgeSlide
    			local oldSegs = $.connectEdgeSegments
    			$.connectEdgePinch = 0
    			$.connectEdgeSlide = 0
    			$.connectEdgeSegments = 1
    			snapMode.active = true
    			snapmode.setOSnapItemActive 5 3 true
    			mouseTrack node:$ snap:#3d trackCallback:edgeSlice()
    			snapMode.active = oldSnap
    			snapmode.setOSnapItemActive 5 3 oldType
    			$.connectEdgePinch = oldPinch
    			$.connectEdgeSlide = oldSlide
    			$.connectEdgeSegments = oldSegs
    		)
    	)
    )
    
  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    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
Sign In or Register to comment.