[Closed] Attach node to patch
I think I’m pretty happy with my version now. I did some more optimizations and added an argument to attach current nodes, all geometry nodes, or geometry – current nodes. I also made it so that any 2 sided loops get subdivided before converting to edit poly. I was able to get the function to attach 100 patches in 0.911 seconds, which I guess is not too bad.
Here’s the function –
fn AttachObjectsPatch Sel:(selection as array) SelType:#Current AttachName:(uniquename ((selection as array)[1].name)) =
(
if (Sel != undefined and Sel.count != 0) then
(
AllNodeSel = (geometry as array) -- Get all objects
InvNodeSel = for i in AllNodeSel where ((finditem Sel i) == 0) collect i -- Inverted selection
NodeSel = #() -- Initial selection
if (SelType == #Current) then NodeSel = Sel else -- Selection
if (SelType == #Inverse) then NodeSel = InvNodeSel else -- Inverted selection
if (SelType == #All) then NodeSel = AllNodeSel -- All objects
Object1 = NodeSel[1] -- Get first object in selection
ObjectSel = NodeSel -- Node selection
AllVertsNum = 0 -- Initial vertex count
AllVecPositions = #() -- Initial position array
AllVertTypes = #() -- Initial handle array
if (classof Object1 == Editable_Poly or classof Object1 == PolyMeshObject or classof Object1 == Editable_Mesh) then addModifier Object1 (Turn_to_Patch ()) -- Use turn to patch mod to keep quads
convertto Object1 Editable_Patch -- Convert to patch
ShowInterior = patch.getShowInterior Object1 -- Get show interior edges on first object
Steps = getPatchSteps Object1 -- Get patch steps of first object
for i = 1 to ObjectSel.count do
(
if (classof ObjectSel[i] == Editable_Poly or classof ObjectSel[i] == PolyMeshObject or classof ObjectSel[i] == Editable_Mesh) then addModifier ObjectSel[i] (Turn_to_Patch ()) -- Use turn to patch mod to keep quads
convertto ObjectSel[i] Editable_Patch -- Convert to patch
if ((patch.getNumVerts ObjectSel[i]) >= 3) then
(
local PoleVerts = #{} -- Vertices with 8 edges and 4 faces, usually on teapot patches
local SubDEdges = #{} -- Edges used for subdivision
for j = 1 to (patch.getNumEdges ObjectSel[i]) do
(
local Edges1 = ((patch.getVertEdges ObjectSel[i] ((patch.getEdgeVert1 ObjectSel[i] j) + 1)) as bitarray) -- Get edges from first vertex
local Edges2 = ((patch.getVertEdges ObjectSel[i] ((patch.getEdgeVert2 ObjectSel[i] j) + 1)) as bitarray) -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then SubDEdges += (Edges1 * Edges2) -- Get both edges
) -- Get 2-sided closed loops on current object
for j = 1 to (patch.getNumVerts ObjectSel[i]) do
(
local VertEdges = patch.getVertEdges ObjectSel[i] j as bitarray -- Edges from vertex
local VertFaces = patch.getVertPatches ObjectSel[i] j as bitarray -- Faces from vertex
if (VertEdges.numberset == 8 and VertFaces.numberset == 4) then
(
local FaceVerts = #{} -- Vertices from faces, excluding vertex at pole
for k = 1 to VertFaces.numberset do (for l = 1 to (patch.getNumVerts ObjectSel[i]) where ((patch.getVertPatches ObjectSel[i] l as bitarray)[(VertFaces as array)[k]] == true) do appendifunique FaceVerts l) -- Get the vertices from the face selection
FaceVerts -= #{j} -- Subtract pole vertex
append PoleVerts j -- Add vertex to bitarray
for k = 1 to FaceVerts.numberset do append SubDEdges ((((patch.getVertEdges ObjectSel[i] (FaceVerts as array)[k]) as bitarray) * VertEdges) as array)[1] -- Get edges minus unwanted edges
) -- Add edges to subdiviision bitarray
)
if (SubDEdges.numberset > 0) then
(
ObjectSel[i].selectedvertices = PoleVerts -- Select pole verts
ObjectSel[i].selectededges = SubDEdges -- Select edges for subdivision
patch.subdivideEdges ObjectSel[i] false -- Subdivide edges
PoleVerts = ObjectSel[i].selectedvertices as bitarray -- Get vertex selection after subdivision
)
local VecPositions = (for j = 1 to (patch.getNumVerts ObjectSel[i]) collect (for k = 1 to (patch.getVertVecs ObjectSel[i] j).count collect (patch.getVec ObjectSel[i] (patch.getVertVecs ObjectSel[i] j)[k]))) as array -- Get 3d array of handle positions of current node
local VertTypes = (for j = 1 to (patch.getNumVerts ObjectSel[i]) collect patch.getVertType ObjectSel[i] j) as array -- Get array of vertex tangent types of current node
if (PoleVerts.numberset > 0) then (for j = 1 to PoleVerts.numberset do VertTypes[((PoleVerts as array)[j])] = #coplanar) -- Chagne pole vertices to coplanar
AllVertsNum += (patch.getNumVerts ObjectSel[i]) -- Add vertice selections
AllVecPositions += VecPositions -- Add positions together
AllVertTypes += VertTypes -- Add vert types together
setPatchSteps ObjectSel[i] 0
) -- If there is at least three vertices in the current object i.e. a face exists
) -- Loop through object selection
select Object1 ; convertto Object1 Editable_Poly ; update Object1 -- Select first object, onvert to poly and update
for i = 1 to ObjectSel.count do polyop.attach Object1 ObjectSel[i] -- Attach objects to first object
Object1.deleteIsoVerts() -- Delete isolated vertices
addModifier Object1 (Turn_to_Patch ()) ; convertto Object1 Editable_Patch -- Use turn to patch mod to keep quads and convert to patch
patch.update Object1 -- Update patch
if ((patch.getNumVerts Object1) >= 3 and AllVecPositions.count == (patch.getNumVerts Object1) and AllVertsNum == (patch.getNumVerts Object1)) then
(
for i = 1 to (patch.getNumVerts Object1) do
(
if (AllVecPositions[i] != undefined and AllVecPositions[i].count == (patch.getVertVecs Object1 i).count) then
(
for j = 1 to (patch.getVertVecs Object1 i).count do (if (AllVecPositions[i][j] != undefined) then patch.setVec Object1 (patch.getVertVecs Object1 i)[j] AllVecPositions[i][j]) -- Return handles to what they were previously
) -- If vertices match and vert's handle numbers match
) -- Loop through vertices
for i = 1 to (patch.getNumVerts Object1) where (AllVertTypes[i] != undefined) do patch.changeVertType Object1 i AllVertTypes[i] -- Return vertex tangent types to what they were previously
) -- If vertex counts match
setPatchSteps Object1 Steps ; patch.setShowInterior Object1 ShowInterior ; CenterPivot Object1 ; WorldAlignPivot Object1 ; Object1.name = AttachName-- Reset values, fix its transforms, and rename
patch.update Object1 -- Update patch
return Object1 --Get node
) -- If objects exist
)
very good. actually it beats my c++ version! where is the problem of c++ function? it’s DoAttach.
i looked into the SDK code and got that they update internal patch data every time after attach. there is no way to disable this update. so when the patch grows it updates slower, slower, and slower.
in your multi-attach function you updates only once when you convert from poly to patch.
editable poly updates data much faster than patch. because its code and structures are most modern.
i cleaned your code a little to help me easier play with it… also i removed some unnecessary updates and selections
here is it:
fn AttachObjectsPatch Sel:(selection as array) SelType:#Current AttachName:(uniquename ((selection as array)[1].name)) =
(
max create mode
if (Sel != undefined and Sel.count != 0) then
(
AllNodeSel = geometry as array -- Get all objects
InvNodeSel = for i in AllNodeSel where ((finditem Sel i) == 0) collect i -- Inverted selection
sources = case SelType of
(
#Current: Sel -- Selection
#Inverse: InvNodeSel -- Inverted selection
#All: AllNodeSel -- All objects
default: #()
)
target = sources[1] -- Get first object in selection
if not iskindof target Editable_Patch do
(
addmodifier target (Turn_to_Patch()) -- Use turn to patch mod to keep quads
convertto target Editable_Patch -- Convert to patch
)
AllVertsNum = 0 -- Initial vertex count
AllVecPositions = #() -- Initial position array
AllVertTypes = #() -- Initial handle array
ShowInterior = patch.getShowInterior target -- Get show interior edges on first object
Steps = getPatchSteps target -- Get patch steps of first object
for source in sources do
(
if not iskindof source Editable_Patch do
(
addmodifier source (Turn_to_Patch ()) -- Use turn to patch mod to keep quads
convertto source Editable_Patch -- Convert to patch
)
if ((patch.getNumVerts source) >= 3) then
(
local PoleVerts = #{} -- Vertices with 8 edges and 4 faces, usually on teapot patches
local SubDEdges = #{} -- Edges used for subdivision
for j = 1 to (patch.getNumEdges source) do
(
local Edges1 = (patch.getVertEdges source ((patch.getEdgeVert1 source j) + 1)) as bitarray -- Get edges from first vertex
local Edges2 = (patch.getVertEdges source ((patch.getEdgeVert2 source j) + 1)) as bitarray -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then SubDEdges += (Edges1 * Edges2) -- Get both edges
) -- Get 2-sided closed loops on current object
for j = 1 to (patch.getNumVerts source) do
(
local VertEdges = patch.getVertEdges source j as bitarray -- Edges from vertex
local VertFaces = patch.getVertPatches source j as bitarray -- Faces from vertex
if (VertEdges.numberset == 8 and VertFaces.numberset == 4) then
(
local FaceVerts = #{} -- Vertices from faces, excluding vertex at pole
for k = 1 to VertFaces.numberset do (for l = 1 to (patch.getNumVerts source) where ((patch.getVertPatches source l as bitarray)[(VertFaces as array)[k]] == true) do appendifunique FaceVerts l) -- Get the vertices from the face selection
FaceVerts -= #{j} -- Subtract pole vertex
append PoleVerts j -- Add vertex to bitarray
for k = 1 to FaceVerts.numberset do append SubDEdges ((((patch.getVertEdges source (FaceVerts as array)[k]) as bitarray) * VertEdges) as array)[1] -- Get edges minus unwanted edges
) -- Add edges to subdiviision bitarray
)
if (SubDEdges.numberset > 0) then
(
source.selectedvertices = PoleVerts -- Select pole verts
source.selectededges = SubDEdges -- Select edges for subdivision
patch.subdivideEdges source false -- Subdivide edges
PoleVerts = source.selectedvertices as bitarray -- Get vertex selection after subdivision
)
local VecPositions = (for j = 1 to (patch.getNumVerts source) collect (for k = 1 to (patch.getVertVecs source j).count collect (patch.getVec source (patch.getVertVecs source j)[k]))) as array -- Get 3d array of handle positions of current node
local VertTypes = (for j = 1 to (patch.getNumVerts source) collect patch.getVertType source j) as array -- Get array of vertex tangent types of current node
if (PoleVerts.numberset > 0) then (for j = 1 to PoleVerts.numberset do VertTypes[((PoleVerts as array)[j])] = #coplanar) -- Chagne pole vertices to coplanar
AllVertsNum += (patch.getNumVerts source) -- Add vertice selections
AllVecPositions += VecPositions -- Add positions together
AllVertTypes += VertTypes -- Add vert types together
setPatchSteps source 0
) -- If there is at least three vertices in the current object i.e. a face exists
) -- Loop through object selection
convertto target Editable_Poly
for source in sources do polyop.attach target source -- Attach objects to first object
target.deleteIsoVerts() -- Delete isolated vertices
addmodifier target (Turn_to_Patch())
convertto target Editable_Patch -- Use turn to patch mod to keep quads and convert to patch
--patch.update target -- Update patch
if ((patch.getNumVerts target) >= 3 and AllVecPositions.count == (patch.getNumVerts target) and AllVertsNum == (patch.getNumVerts target)) then
(
for i = 1 to (patch.getNumVerts target) do
(
if (AllVecPositions[i] != undefined and AllVecPositions[i].count == (patch.getVertVecs target i).count) then
(
for j = 1 to (patch.getVertVecs target i).count do (if (AllVecPositions[i][j] != undefined) then patch.setVec target (patch.getVertVecs target i)[j] AllVecPositions[i][j]) -- Return handles to what they were previously
) -- If vertices match and vert's handle numbers match
) -- Loop through vertices
for i = 1 to (patch.getNumVerts target) where (AllVertTypes[i] != undefined) do patch.changeVertType target i AllVertTypes[i] -- Return vertex tangent types to what they were previously
) -- If vertex counts match
setPatchSteps target Steps ; patch.setShowInterior target ShowInterior ; CenterPivot target ; WorldAlignPivot target ; target.name = AttachName-- Reset values, fix its transforms, and rename
patch.update target -- Update patch
return target --Get node
) -- If objects exist
)
it didn’t make the code faster…
now is about your problems. the first is big memory usage. for big patches i couldn’t complete the attachment because of out of memory. that’s the bottleneck.
the second problem is the loosing of tvHandles (which are MapVerts) .
but as i said more important is to solve the memory issue.
Well I’m glad that my version turns out to not be a waste of time. Although my version you reworked did crash max for me, so I’m not really sure what’s causing that.
I’m not really sure how I can make my version any less memory hungry. I would guess though, that if you are modeling with patches, odds are that you won’t need tons of vertices to define your models. And I can’t think of cases where you would need over tens of thousands of patches in one object. Hopefully though, some of the minor changes I just made today to the function will help a little as far as memory goes.
fn AttachObjectsPatch Sel:(selection as array) SelType:#Current AttachName:(uniquename ((selection as array)[1].name)) =
(
if (Sel != undefined and Sel.count != 0) then
(
AllObjectSel = (geometry as array) -- Get all objects
InvObjectSel = for i in AllObjectSel where ((finditem Sel i) == 0) collect i -- Inverted selection
ObjectSel = #() -- Initial selection
if (SelType == #Current) then ObjectSel = Sel else -- Selection
if (SelType == #Inverse) then ObjectSel = InvObjectSel else -- Inverted selection
if (SelType == #All) then ObjectSel = AllObjectSel -- All objects
Object1 = ObjectSel[1] -- Get first object in selection
AllVecPositions = #() -- Initial position array
AllVertTypes = #() -- Initial vertex type array
AllPatchTypes = #() -- Initial patch type array
if (classof Object1 == Editable_Poly or classof Object1 == PolyMeshObject or classof Object1 == Editable_Mesh) then addModifier Object1 (Turn_to_Patch ()) -- Use turn to patch mod to keep quads
convertto Object1 Editable_Patch -- Convert to patch
ShowInterior = patch.getShowInterior Object1 -- Get show interior edges on first object
Steps = getPatchSteps Object1 -- Get patch steps of first object
for Object2 in ObjectSel do
(
if (classof Object2 == Editable_Poly or classof Object2 == PolyMeshObject or classof Object2 == Editable_Mesh) then addModifier Object2 (Turn_to_Patch ()) -- Use turn to patch mod to keep quads
convertto Object2 Editable_Patch -- Convert to patch
if ((patch.getNumVerts Object2) >= 3) then
(
local PoleVerts = #{} -- Vertices with 8 edges and 4 faces, usually on teapot patches
local SubDEdges = #{} -- Edges used for subdivision
for j = 1 to (patch.getNumEdges Object2) do
(
local Edges1 = ((patch.getVertEdges Object2 ((patch.getEdgeVert1 Object2 j) + 1)) as bitarray) -- Get edges from first vertex
local Edges2 = ((patch.getVertEdges Object2 ((patch.getEdgeVert2 Object2 j) + 1)) as bitarray) -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then SubDEdges += (Edges1 * Edges2) -- Get both edges
) -- Get 2-sided closed loops on current object
for j = 1 to (patch.getNumVerts Object2) do
(
local VertEdges = patch.getVertEdges Object2 j as bitarray -- Edges from vertex
local VertFaces = patch.getVertPatches Object2 j as bitarray -- Faces from vertex
if (VertEdges.numberset == 8 and VertFaces.numberset == 4) then
(
local FaceVerts = #{} -- Vertices from faces, excluding vertex at pole
for k = 1 to VertFaces.numberset do (for l = 1 to (patch.getNumVerts Object2) where ((patch.getVertPatches Object2 l as bitarray)[(VertFaces as array)[k]] == true) do appendifunique FaceVerts l) -- Get the vertices from the face selection
FaceVerts -= #{j} -- Subtract pole vertex
append PoleVerts j -- Add vertex to bitarray
for k = 1 to FaceVerts.numberset do append SubDEdges ((((patch.getVertEdges Object2 (FaceVerts as array)[k]) as bitarray) * VertEdges) as array)[1] -- Get edges minus unwanted edges
) -- Add edges to subdiviision bitarray
) -- Loop through vertices
if (SubDEdges.numberset > 0) then
(
Object2.selectedvertices = PoleVerts -- Select pole verts
Object2.selectededges = SubDEdges -- Select edges for subdivision
patch.subdivideEdges Object2 false -- Subdivide edges
PoleVerts = Object2.selectedvertices as bitarray -- Get vertex selection after subdivision
patch.update Object2
) -- If there are any edges to subdivide
local VecPositions = for j = 1 to (patch.getNumVerts Object2) collect (for k = 1 to (patch.getVertVecs Object2 j).count collect (patch.getVec Object2 (patch.getVertVecs Object2 j)[k])) -- Get array of handle positions of current node
local VertTypes = for j = 1 to (patch.getNumVerts Object2) collect patch.getVertType Object2 j -- Get array of vertex tangent types of current node
local PatchTypes = for j = 1 to (patch.getNumPatches Object2) collect patch.getPatchInteriorType Object2 j -- Get array of patch interior types of current node
if (PoleVerts.numberset > 0) then (for j = 1 to PoleVerts.numberset do VertTypes[((PoleVerts as array)[j])] = #coplanar) -- Change pole vertices to coplanar
AllVecPositions += VecPositions -- Add vector positions together
AllVertTypes += VertTypes -- Add vert types together
AllPatchTypes += PatchTypes -- Add patch types together
setPatchSteps Object2 0
) -- If there is at least three vertices in the current object i.e. a face exists
) -- Loop through object selection
select Object1 ; convertto Object1 Editable_Poly -- Select first object, onvert to poly and update
for i = 1 to ObjectSel.count do polyop.attach Object1 ObjectSel[i] -- Attach objects to first object
Object1.deleteIsoVerts() -- Delete isolated vertices
addModifier Object1 (Turn_to_Patch ()) ; Object1.modifiers[#Turn_to_Patch].useSoftSelection = 0 ; convertto Object1 Editable_Patch -- Use turn to patch mod to keep quads and convert to patch
for i = 1 to (patch.getNumVerts Object1) where (AllVecPositions[i] != undefined and AllVecPositions[i].count == (patch.getVertVecs Object1 i).count) do
(
local VertVecs = patch.getVertVecs Object1 i -- Get handle from vertex
for j = 1 to VertVecs.count where (AllVecPositions[i][j] != undefined) do patch.setVec Object1 VertVecs[j] AllVecPositions[i][j] -- Set handles positions
) -- Return tv vertex positions to what they were previously
for i = 1 to (patch.getNumVerts Object1) where (AllVertTypes[i] != undefined) do patch.changeVertType Object1 i AllVertTypes[i] -- Return vertex tangent types to what they were previously
for i = 1 to (patch.getNumPatches Object1) where (AllPatchTypes[i] != undefined) do patch.changePatchInteriorType Object1 i AllPatchTypes[i] -- Return patch interior types to what they were previously
setPatchSteps Object1 Steps ; patch.setShowInterior Object1 ShowInterior ; CenterPivot Object1 ; WorldAlignPivot Object1 ; Object1.name = AttachName-- Reset values, fix its transforms, and rename
patch.update Object1 -- Update patch
return Object1 --Get node
) -- If objects exist
)
[/i]The main things I changed -[i]
- Went from 3 updates to 1, there was an update before converting to poly, one after conversion, and another one after conversion back to patch and resetting everything. I just kept the last one.
- I used variable Object2 to reference the current node in ObjectSel loop.
- Cleaned up method for resetting vertex handles.
- Added array for resetting interior types on each patch face
- 100 spheres attached in 0.5 seconds!
[/i]The first two, it looks like you improved in your reworked version, so again I’m not sure why yours crashes max.
And yes I did notice that there are no tv handles after attachment. I actually have never unwrapped a patch object before, so I didn’t even know about them! I don’t even know how you can manually get them back. So I decided to try looping through the number of map verts, and getting their positions, then looping through the resulting patch and setting their positions, but when I chacked in unwrap, it was a huge mess… This is probably the same reason I needed to loop through each patch vertex to get the corresponding vectors, and reset them that way, because the handle order changes for the whole patch object, after conversion.
This is what I tried using -[i]
AllTVPositions = #() -- Initial tv map vertex position array
local TVPositions = for j = 1 to (patch.getNumMapVerts Object2 1) collect (patch.getMapVert Object2 1 j) -- Get array of tv map vertex positions of current node
AllTVPositions += TVPositions -- Add tv positions together
for i = 1 to (patch.getNumMapVerts Object1 1) where (AllTVPositions[i] != undefined) do patch.setMapVert Object1 1 i AllTVPositions[i] -- Return tv map vertex positions to what they were previously
[/i]I’m not sure if I’m missing anything, but I don’t see a way of getting tv handles from a vertex. I looked in the MS reference and saw [i]patch.getMapPatch <obj> <map_chan> <index> What is the index? is that a patch number? It seems to always return a 4 number array, are those the handles or vertices?
Any ideas as to how I can store and reset the map handles?
Hmmm…This is quite odd, I can’t figure out how to get back the patch map handles at all, they are totally gone after converting from poly…You can’t even edit them them at all in edit patch or uvw unwrap. I tried using
$.modifiers[#Unwrap_UVW].getHandleGeomIndexFromFace 1 1
in uvw unwrap and no matter what face or handle index I use it always returns 0. But if I try it on a patch that hasn’t been converted from poly it does return a different number.
Does anyone know how to reset the map handles? Very very odd…
i remember this problem. until some last version of max when you tried to do anything with patch handles (either manually or from script) in the Unwrap_UVW the max just crashed. maybe the bug was fixed but no methods to work with handles were added.
in the SDK there is TVPatch Class which has all methods to work with map coordinates. But it’s not exposed to MXS.
Oh well …I guess I’ll just have note that as a limitation, when I release it with other scripts for now. Although this might not even matter since you still have the same uv layout, and depending on the geometry and mapping you have on it, there might not be any difference in the shape of the uv faces. You would mainly notice the affect of not having the handles, if you had planar maps on the top and bottom of a cylinder. Anyways, thanks for your help denis.
Also, if you are interested, I also finished my DetachAllPatchElements script –
fn DetachAllPatchElements Sel:(selection as array) SelType:#Current =
(
if (Sel != undefined) then
(
ObjArray = #() -- Initial object array
AllObjectSel = (geometry as array) -- Get all objects
InvObjectSel = for i in AllObjectSel where ((finditem Sel i) == 0) collect i -- Inverted selection
ObjectSel = #() -- Initial selection
if (SelType == #Current) then ObjectSel = Sel else -- Selection
if (SelType == #Inverse) then ObjectSel = InvObjectSel else -- Inverted selection
if (SelType == #All) then ObjectSel = AllObjectSel -- All objects
for i = 1 to ObjectSel.count do
(
local Object1 = ObjectSel[i] -- Get current object
if (classof Object1 == Editable_Poly or classof Object1 == PolyMeshObject or classof Object1 == Editable_Mesh) then addModifier Object1 (Turn_to_Patch ()) -- Use turn to patch mod to keep quads
convertto Object1 Editable_Patch -- Convert to patch
while (patch.getNumPatches ObjectSel[i]) != 0 do
(
local AllFaceSel = #{1..(patch.getNumPatches Object1)} -- Get all geometry
local NewObj = undefined -- Initial new object node
Element = #{1} -- Initial element face array
for j = 1 to (patch.getNumPatches Object1) do
(
local OldFaceNum = Element.numberset -- Get past selection
local Verts = #{}
for k = 1 to Element.numberset do (for l = 1 to (patch.getNumVerts Object1) where ((patch.getVertPatches Object1 l as bitarray)[(Element as array)[k]] == true) do appendifunique Verts l) -- Get vertices from faces
for k = 1 to Verts.numberset do Element += (patch.getVertPatches Object1 (Verts as array)[k] as bitarray) -- Get faces from vertices
if (Element.numberset == OldFaceNum) then exit -- Exit if selection doesn't change
) -- Grow faces to element
local NewObjName = uniquename (Object1.name) -- Get a new name for object
NewObj = copy Object1 name:NewObjName -- Clone object and give it a new name
patch.deletePatchParts Object1 #{} Element -- Delete selected faces on current object
patch.deletePatchParts NewObj #{} (AllFaceSel - Element) -- Delete unselected faces on new object
CenterPivot NewObj ; WorldAlignPivot NewObj ; NewObj.wirecolor = (color (random 0 255) (random 0 255) (random 0 255)) -- Fix new object's transforms, and give it a new wire color
setSelectionLevel NewObj #Object ; patch.update NewObj ; patch.update Object1 -- Go out of sub-object level, update current object, and update new object
append ObjArray NewObj -- Add to array
) -- Keep detaching elements to new objects until there is nothing left
delete Object1 -- Delete old empty object
) -- Loop over object selection
select ObjArray -- Select detached objects
return ObjArray -- Get array of detached objects
)
)
It works on multiple objects, and it uses a copy, and delete method to detach the faces. Now you can keep on attaching and detaching the same selected patch objects forever!
Minor update – I changed the default option in turn to patch, Use Soft Selection, so that soft selection is off after everything’s done. I update the post to include the change. –
addModifier Object1 (Turn_to_Patch ()) ; Object1.modifiers[#Turn_to_Patch].useSoftSelection = 0 ; convertto Object1 Editable_Patch -- Use turn to patch mod to keep quads and convert to patch