Hi all!
In a few occasions lately I ve been in the need of going back to a subdiv mesh and manually remove the edges generated by subdivision, in order to get the base cage back.
It's not a very hard thing to do really - just a matter of selecting every other edge loops, and removing them. The result is pretty much what 'reconstruct subdiv' does in Zbrush.
I know that in theory one should always keep the base mesh somewhere, but even when being very careful there is always a time when this comes up. Basically, manually selecting things like here :

My question is, do you guys know of some maxscript doing just that : user selects an edgeloop, and the script selects every other parallel edge loop from there ? It would be even better if one could select 2 edges forming an L branch somewhere on a mesh, and get all the subdivision-generated edges from that. But thats just icing on the cake !
Ideas?
As usual, this is a valid question for Max, Maya or any other app...
Replies
macroScript IC_SelectSubDivNet category:"IllusionCatalyst Tools" buttonText:"SelectSubDivNet" tooltip:"IC.SelectSubDivNet" ( on execute do ( if (Filters.Is_EditPoly()) do ( local theNode = selection[1] local theBase = theNode.baseObject local baRefVert = polyOp.getVertSelection theBase if (baRefVert.numberSet == 1) do ( local baOldEdgeSel = #{} local baNewEdgeSel = polyOp.getEdgesUsingVert theBase baRefVert local baEdgeVerts = #{} local baEdgeFaces = #{} local baExtEdges = #{} local baNewGridVerts = #{} while (baNewEdgeSel.numberSet != baOldEdgeSel.numberSet) do ( if (keyboard.escPressed) do throw "**Esc Pressed**" baEdgeVerts = polyOp.getVertsUsingEdge theBase baNewEdgeSel baEdgeFaces = polyOp.getFacesUsingEdge theBase baNewEdgeSel baExtEdges = (polyOp.getEdgesUsingVert theBase baEdgeVerts) - (polyOp.getEdgesUsingFace theBase baEdgeFaces) baNewGridVerts = (polyOp.getVertsUsingEdge theBase baExtEdges) - baEdgeVerts baOldEdgeSel = baNewEdgeSel baNewEdgeSel += polyOp.getEdgesUsingVert theBase baNewGridVerts ) polyOp.setEdgeSelection theBase baNewEdgeSel subObjectLevel = 2 ) ) ) )*Head explodes*
So awesome. Thanks Sync!
SyncViewS' script works perfectly though. So simple, too!
I might look into doing this script for Maya too, I needed it recently. Reconstruct Subdiv for any mesh!
MoP: Do it! Every program should have something like this
Try this : apply the meshsmooth alright. unselect all the edges. Close Max. Open Max. Open your scene. Go to edge mode. Huh what do you do now ?
Mop : Pers technique can be used to make tire treads, bumpy stuff on gun handles and so on. Once you got that selection of edges bases on the original cage flow you can make very cool stuff by just moving it along the normals.
Or more likely someone else models it
macroScript IC_SelectSubDivNet category:"IllusionCatalyst Tools" buttonText:"SelectSubDivNet" tooltip:"IC.SelectSubDivNet" ( function getEPolyEdgesUsingFace theNode theEditPoly baFaces = ( local baEdges = #{} local iFaceDeg = 0 for iFace in baFaces do ( iFaceDeg = theEditPoly.getFaceDegree iFace node:theNode for iSide = 1 to iFaceDeg do baEdges[theEditPoly.getFaceEdge iFace iSide node:theNode] = true ) return baEdges ) on execute do ( if (Filters.Is_EPoly()) do ( local theNode = selection[1] local theBase = theNode.baseObject if (getCommandPanelTaskMode() != #modify) do setCommandPanelTaskMode #modify local theEditObj = modPanel.getCurrentObject() local baOldEdgeSel = #{} local baNewEdgeSel = #{} local baEdgeVerts = #{} local baEdgeFaces = #{} local baExtEdges = #{} local baNewGridVerts = #{} if (classOf theEditObj == Editable_Poly) then ( local baRefVert = polyOp.getVertSelection theBase if (baRefVert.numberSet == 1) do ( baNewEdgeSel = polyOp.getEdgesUsingVert theBase baRefVert while (baNewEdgeSel.numberSet != baOldEdgeSel.numberSet) do ( if (keyboard.escPressed) do throw "**Esc Pressed**" baEdgeVerts = polyOp.getVertsUsingEdge theBase baNewEdgeSel baEdgeFaces = polyOp.getFacesUsingEdge theBase baNewEdgeSel baExtEdges = (polyOp.getEdgesUsingVert theBase baEdgeVerts) - (polyOp.getEdgesUsingFace theBase baEdgeFaces) baNewGridVerts = (polyOp.getVertsUsingEdge theBase baExtEdges) - baEdgeVerts baOldEdgeSel = baNewEdgeSel baNewEdgeSel += polyOp.getEdgesUsingVert theBase baNewGridVerts ) polyOp.setEdgeSelection theBase baNewEdgeSel subObjectLevel = 2 ) ) else if ((classOf theEditObj) == Edit_Poly) then ( local baRefVert = theEditObj.getSelection #Vertex node:theNode if (baRefVert.numberSet == 1) do ( theEditObj.getEdgesUsingVert &baNewEdgeSel baRefVert node:theNode local baEdgesFromVerts = #{} local baEdgesFromFaces = #{} local baAddEdges = #{} while (baNewEdgeSel.numberSet != baOldEdgeSel.numberSet) do ( if (keyboard.escPressed) do throw "**Esc Pressed**" theEditObj.getVertsUsingEdge &baEdgeVerts baNewEdgeSel theEditObj.getFacesUsingEdge &baEdgeFaces baNewEdgeSel theEditObj.getEdgesUsingVert &baEdgesFromVerts baEdgeVerts baEdgesFromFaces = getEPolyEdgesUsingFace theNode theEditObj baEdgeFaces baExtEdges = baEdgesFromVerts - baEdgesFromFaces theEditObj.getVertsUsingEdge &baNewGridVerts baExtEdges baNewGridVerts -= baEdgeVerts baOldEdgeSel = baNewEdgeSel theEditObj.getEdgesUsingVert &baAddEdges baNewGridVerts baNewEdgeSel += baAddEdges ) theEditObj.setSelection #Edge baNewEdgeSel node:theNode theEditObj.setEPolySelLevel #Edge ) ) ) ) )I'll add a progress bar since it gets a bit slow on larger meshes, then release it tomorrow after more testing. Should be pretty handy!
Ideally I'd like to do a proper "reconstruct subdiv" like ZBrush has but I'm not entirely sure where to start. I guess you have to start by dividing the total number of polys in the mesh by 4 to check that it's actually been subdivided at all?
And about the original post : I really mean on a collapsed mesh, of course it's not a problem at all when the source cage is still available ... that's why your 'tadaaaa here's how to do it' post made me laugh. It's cool tho, had a long day!
macroScript IC_SelectSubDivNet category:"IllusionCatalyst Tools" buttonText:"SelectSubDivNet" tooltip:"IC.SelectSubDivNet" ( rollout rolSelectSubDivNet "Select Sub Div Net" ( label lb_1 "Analysing Geometry..." align:#center offset:[0,0] progressBar pbStatus width:100 height:9 color:[0,197,0] align:#center offset:[0,0] label lb_2 "Press ESC to cancel" align:#center offset:[0,0] ) function getEPolyEdgesUsingFace theNode theEditPoly baFaces = ( local baEdges = #{} local iFaceDeg = 0 for iFace in baFaces do ( iFaceDeg = theEditPoly.getFaceDegree iFace node:theNode for iSide = 1 to iFaceDeg do baEdges[theEditPoly.getFaceEdge iFace iSide node:theNode] = true ) return baEdges ) on execute do ( if (Filters.Is_EPoly()) do ( createDialog rolSelectSubDivNet 120 57 style:#(#style_toolwindow, #style_sysmenu, #style_resizing) local theNode = selection[1] local theBase = theNode.baseObject if (getCommandPanelTaskMode() != #modify) do setCommandPanelTaskMode #modify local theEditObj = modPanel.getCurrentObject() local baOldEdgeSel = #{} local baNewEdgeSel = #{} local baEdgeVerts = #{} local baEdgeFaces = #{} local baExtEdges = #{} local baNewGridVerts = #{} local baRefVert = #{} local iNumTestEdges = 0 local bTest = true if (classOf theEditObj == Editable_Poly) then ( iNumTestEdges = ( (polyOp.getNumEdges theBase) - ((polyOp.getOpenEdges theBase).numberSet) ) * .5 baRefVert = polyOp.getVertSelection theBase if (baRefVert.numberSet == 1) do ( baNewEdgeSel = polyOp.getEdgesUsingVert theBase baRefVert while (baNewEdgeSel.numberSet != baOldEdgeSel.numberSet) do ( if (keyboard.escPressed) do ( bTest = false exit ) rolSelectSubDivNet.pbStatus.value = ((baOldEdgeSel.numberSet * 100 / iNumTestEdges) as Integer) baEdgeVerts = polyOp.getVertsUsingEdge theBase (baNewEdgeSel - baOldEdgeSel) baEdgeFaces = polyOp.getFacesUsingEdge theBase (baNewEdgeSel - baOldEdgeSel) baExtEdges = (polyOp.getEdgesUsingVert theBase baEdgeVerts) - (polyOp.getEdgesUsingFace theBase baEdgeFaces) - baOldEdgeSel baNewGridVerts = (polyOp.getVertsUsingEdge theBase baExtEdges) - baEdgeVerts baOldEdgeSel = baNewEdgeSel baNewEdgeSel += polyOp.getEdgesUsingVert theBase baNewGridVerts ) if (bTest == true) do ( polyOp.setEdgeSelection theBase baNewEdgeSel subObjectLevel = 2 ) ) ) else if ((classOf theEditObj) == Edit_Poly) then ( iNumTestEdges = ( (theEditObj.getNumEdges node:theNode) - ((theEditObj.getOpenEdges node:theNode).numberSet) ) * .5 baRefVert = theEditObj.getSelection #Vertex node:theNode if (baRefVert.numberSet == 1) do ( theEditObj.getEdgesUsingVert &baNewEdgeSel baRefVert node:theNode local baEdgesFromVerts = #{} local baEdgesFromFaces = #{} local baAddEdges = #{} while (baNewEdgeSel.numberSet != baOldEdgeSel.numberSet) do ( if (keyboard.escPressed) do ( bTest = false exit ) rolSelectSubDivNet.pbStatus.value = ((baOldEdgeSel.numberSet * 100 / (iNumTestEdges as Float)) as Integer) theEditObj.getVertsUsingEdge &baEdgeVerts (baNewEdgeSel - baOldEdgeSel) theEditObj.getFacesUsingEdge &baEdgeFaces (baNewEdgeSel - baOldEdgeSel) theEditObj.getEdgesUsingVert &baEdgesFromVerts baEdgeVerts baEdgesFromFaces = getEPolyEdgesUsingFace theNode theEditObj baEdgeFaces baExtEdges = baEdgesFromVerts - baEdgesFromFaces - baOldEdgeSel theEditObj.getVertsUsingEdge &baNewGridVerts baExtEdges baNewGridVerts -= baEdgeVerts baOldEdgeSel = baNewEdgeSel theEditObj.getEdgesUsingVert &baAddEdges baNewGridVerts baNewEdgeSel += baAddEdges ) if (bTest == true) do ( baNewEdgeSel.count = theEditObj.getNumEdges node:theNode theEditObj.setSelection #Edge baNewEdgeSel node:theNode theEditObj.setEPolySelLevel #Edge ) ) ) try ( destroyDialog rolSelectSubDivNet ) catch () ) gc light:true ) )