Ok, but do you mean the short code or the original attach code? The short code still looks the same ran in front view, I could be wrong though –
Unmaximized –
>> #(264742P, 15010910P, 15010910P, "ViewPanel", "", 0P, 15010910P, 15010910P)
#(264734P, 264742P, 264742P, "Label", "Perspective", 0P, 15010910P, 15010910P)
#(264 736P, 264742P, 264742P, "Label", "Left", 0P, 15010910P, 15010910P)
#(264738P, 264742P, 264742P, "Label", "Front", 0P, 15010910P, 15010910P)
#(264740P, 264742P, 264742P, "Label", "Top", 0P, 15010910P, 15010910P)
#(23729000P, 264742P, 264742P, "VptSplitterBar", "", 0P, 15010910P, 15010910P)
#(57805734P, 264742P, 264742P, "VptSplitterBar", "", 0P, 15010910P, 15010910P)
OK
Maximized –
>> #(264742P, 15010910P, 15010910P, "ViewPanel", "", 0P, 15010910P, 15010910P)
#(264740P, 264742P, 264742P, "Label", "Front", 0P, 15010910P, 15010910P)
#(264734P, 264742P, 264742P, "Label", "Perspective", 0P, 15010910P, 15010910P)
#(264736P, 264742P, 264742P, "Label", "Left", 0P, 15010910P, 15010910P)
#(264738P, 264742P, 264742P, "Label", "Top", 0P, 15010910P, 15010910P)
OK
The attach code ran in front view yields –
OK
CreateMessagesAssembly()
dotNetObject:PickSupport
makeParam()
findActiveLabel()
pickPatchAttach()
-- Error occurred in windowpos(); filename: ; position: 1737; line: 50
-- Frame:
-- p: undefined
-- hwnd: undefined
-- called in findActiveLabel(); filename: ; position: 2078; line: 61
-- Frame:
-- windowpos: windowpos()
-- d3ds: #()
-- lbls: #(264734P, 264736P, 264738P, 264740P)
-- p: undefined
-- hwnd: 264742P
-- called in pickPatchAttach(); filename: ; position: 2540; line: 77
-- Frame:
-- bt: 44174336P
-- pp: undefined
-- ps: undefined
-- XY: undefined
-- node: $source
-- WM_LBUTTONDOWN: undefined
-- WM_LBUTTONUP: undefined
-- pv: undefined
-- patch: Editable Patch
-- hwnd: undefined
-- mesh: undefined
-- called in anonymous codeblock; filename: ; position: 3286; line: 103
-- Frame:
-- target: $target
-- source: $source
-- Runtime error: No method found which matched argument list
Nice! It does work, I’ll have to figure out out to integrate that with my other poly, mesh, and spline attachment function libraries. When I release them I’ll give you credit, thanks! I’m almost done with my version, when I’m finished I’ll post that as well. I’ll have to compare the evaluation times on these. Is there a method of getting precise evaluation times in maxscript, other than just using a stop watch? Maybe when a block is done, or by checking if max is responding or not would be a good way for this?
you can do the same to attach splines. it works almost for everything that needs picking a node in the viewport.
timestemp() before and after.
That’s interesting to know, although I just used addAndWeld for attaching selected splines together. I’ll have to try that timestamp function.
Who knows what and where Autodesk changes things under the hood right now… My main beef is with older things like edit mesh and patch. I think that if you are going to keep older things in max for whatever legacy reasons, then UPDATE THEM! Or at least give better access to them in maxscript… I don’t really use edit mesh for modeling, but patches still can have their uses from time to time. I think it would be really nice to have the same ribbon tools for patches as well, which is why I’m trying to create a lot of them myself, but it definitely seems like a challenge. Anyways that’s my rant for today.
Okay so I finally finished my version, which works decently. I haven’t recorded the times on this, and I’ve only tried it on a few objects. I figured it was worth a try because it seems like your function is dependent on the version, and if autodesk moves things around for 2014, then your function ends up getting broken. And I don’t know anything really about dot net to constantly update it for my other attachment scripts. I would have to say that the set of scripts is for max 2013 only, which I think would be a major drawback.
Anyways, here’s the function –
fn AttachPatch Obj:$ AttachNode:undefined =
(
if (Obj != undefined and AttachNode != undefined) then
(
if (classof Obj != Editable_Patch) then
(
if (classof Obj == Editable_Poly or classof Obj == PolyMeshObject or classof Obj == Editable_Mesh) then
(
select Obj ; modPanel.addModToSelection (Turn_to_Patch ()) ; macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch, retain quads
) else macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch
) -- Convert current object to patch if its not already a patch
if (classof AttachNode != Editable_Patch) then
(
if (classof AttachNode == Editable_Poly or classof AttachNode == PolyMeshObject or classof AttachNode == Editable_Mesh) then
(
select AttachNode ; modPanel.addModToSelection (Turn_to_Patch ()) ; macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch, retain quads
) else macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch
) -- Convert attached object to patch if its not already a patch
Loops2Sided1 = #{} -- Closed loops with only 2 edges
Loops2Sided2 = #{} -- Closed loops with only 2 edges
for i = 1 to (patch.getNumEdges Obj) do
(
local Edges1 = ((patch.getVertEdges Obj ((patch.getEdgeVert1 Obj i) + 1)) as bitarray) -- Get edges from first vertex
local Edges2 = ((patch.getVertEdges Obj ((patch.getEdgeVert2 Obj i) + 1)) as bitarray) -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then Loops2Sided1 += (Edges1 * Edges2) -- Get both edges
) -- Get 2-sided closed loops on current object
for i = 1 to (patch.getNumEdges AttachNode) do
(
local Edges1 = ((patch.getVertEdges AttachNode ((patch.getEdgeVert1 AttachNode i) + 1)) as bitarray) -- Get edges from first vertex
local Edges2 = ((patch.getVertEdges AttachNode ((patch.getEdgeVert2 AttachNode i) + 1)) as bitarray) -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then Loops2Sided2 += (Edges1 * Edges2) -- Get both edges
) -- Get 2-sided closed loops on attached object
patch.deletePatchParts Obj Loops2Sided1 #{} -- Delete 2-sided loops on current object to avoid vertex count mismatch
patch.deletePatchParts AttachNode Loops2Sided2 #{} -- Delete 2-sided loops on attached object to avoid vertex count mismatch
AllVerts1 = #() -- Initial vertex array
AllVecPositions1 = #() -- Initial position array
AllVertTypes1 = #() -- Initial handle array
AllVerts2 = #() -- Initial vertex array
AllVecPositions2 = #() -- Initial position array
AllVertTypes2 = #() -- Initial handle array
if ((patch.getNumVerts Obj) >= 3) then
(
AllVerts1 = #{1..(patch.getNumVerts Obj)} as array -- Get all vertices
AllVecPositions1 = (for i = 1 to AllVerts1.count collect (for j = 1 to (patch.getVertVecs Obj i).count collect (patch.getVec Obj (patch.getVertVecs Obj i)[j]))) as array -- Get 3d array of handle positions of current object
AllVertTypes1 = (for i = 1 to AllVerts1.count collect patch.getVertType Obj i) as array -- Get array of vertex tangent types of current object
) -- If there is at least three vertices in the current object i.e. a face exists
if ((patch.getNumVerts AttachNode) >= 3) then
(
AllVerts2 = #{1..(patch.getNumVerts AttachNode)} as array -- Get all vertices
AllVecPositions2 = (for i = 1 to AllVerts2.count collect (for j = 1 to (patch.getVertVecs AttachNode i).count collect (patch.getVec AttachNode (patch.getVertVecs AttachNode i)[j]))) as array -- Get 3d array of handle positions of attached node
AllVertTypes2 = (for i = 1 to AllVerts2.count collect patch.getVertType AttachNode i) as array -- Get array of vertex tangent types of attached node
) -- If there is at least three vertices in the attached object i.e. a face exists
AllVerts3 = AllVerts1 + AllVerts2 -- Add vertice selections
AllVecPositions3 = AllVecPositions1 + AllVecPositions2 -- Add positions together
AllVertTypes3 = AllVertTypes1 + AllVertTypes2 -- Add vert types together
Steps = getPatchSteps Obj -- Get patch steps of original object
ShowInterior = patch.getShowInterior Obj
setPatchSteps Obj 0 -- Set patch steps of current object to 0
setPatchSteps AttachNode 0 -- Set patch steps of attached node to 0
for i = 1 to AllVerts2.count do AllVerts2[i] += AllVerts1.count -- Offset vertice indexes
select Obj ; macros.run "Modifier Stack" "Convert_to_Poly" -- Convert to editable poly, using turn to poly mod in order to retain quads
select AttachNode ; macros.run "Modifier Stack" "Convert_to_Poly" -- Convert to editable poly, using turn to poly mod in order to retain quads
Obj.deleteIsoVerts() -- Delete isolated vertices
polyop.attach Obj AttachNode -- Attach node to current object
select Obj -- Select original object
modPanel.addModToSelection (Turn_to_Patch ()) ; macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to editable patch, using turn to patch mod in order to retain quads
patch.update Obj -- Update patch
if ((patch.getNumVerts Obj) >= 3 and AllVecPositions3.count == (patch.getNumVerts Obj) and AllVerts3.count == (patch.getNumVerts Obj)) then
(
for i = 1 to (patch.getNumVerts Obj) do
(
if (AllVecPositions3[i] != undefined and AllVecPositions3[i].count == (patch.getVertVecs Obj i).count) then
(
for j = 1 to (patch.getVertVecs Obj i).count do
(
if (AllVecPositions3[i][j] != undefined) then patch.setVec Obj (patch.getVertVecs Obj i)[j] AllVecPositions3[i][j] -- Return handles to what they were previously
) -- Loop through handles
) -- If vertices match and vert's handle numbers match
) -- Loop through vertices
) -- If vertex counts match
if ((patch.getNumVerts Obj) >= 3 and AllVertTypes3.count == (patch.getNumVerts Obj)) then (for i = 1 to (patch.getNumVerts Obj) do (if (AllVertTypes3[i]) != undefined do patch.changeVertType Obj i (AllVertTypes3[i]))) -- Return vertex tangent types to what they were previously
setPatchSteps Obj Steps -- Set patch steps to what they were previously
patch.setShowInterior Obj ShowInterior
patch.update Obj -- Update patch
return Obj
) -- If objects exist
)
A couple of things to note, I had to make it so that the function deletes edges that make up a 2 sided loop i.e. edges that form 2 sided cylinders. So when you convert a teapot to patch and run the function using the teapot as the attach node, the handle and spout end up getting deleted. It was something that I couldn’t figure out a way around. This is because the geometry gets weird when you end up with double sided faces in edit poly. Also, you end up with a higher vertex count afterwards, since you can’t weld edges together with double sided faces. So if you use this function try to avoid those cases. Another thing I noticed is that sometimes, if you run the function and undo, then the patch steps on the source object end up staying at 0.
This is the single node version, I also made a function to loop through a selection of objects –
fn AttachSelectedPatch Sel:(selection as array) =
(
if (Sel != undefined) then
(
Object1 = Sel[1] -- Get first object in selection
ObjectSel = for i = 1 to Sel.count where (Sel[i] != Object1) collect Sel[i] -- Get selected objects excluding the first one
for i = 1 to ObjectSel.count do AttachPatch Obj:Object1 AttachNode:ObjectSel[i] -- Attach objects
patch.update Object1 ; CenterPivot Object1 ; WorldAlignPivot Object1 ; select Object1 -- Select object, update it, and fix its transforms
return Object1 -- Get object
) -- If objects exist
)
It will probably be really slow for a large selection of objects because it loops through the selection and runs the attach function for each node. I plan on trying to make this method faster by just having one function, which is a multi-node version which somehow appends the position and vertex type arrays from each object, and just attaches them in edit poly and reapplies them after going back to patch.
If you know of any ways of making this faster and more efficient, please let me know.
Success! I was able to make one function to attach multiple patches. Just as I thought I got the first object, and looped through the rest of the selection. Got the first objects positions and vert types, and appended each object’s positions and types to those arrays. then I attached those same objects in edit poly, then converted to patch and reapplied those positions. I fixed some problems I missed and made it a little more efficient.
fn AttachObjectsPatch AttachNodes:(selection as array) AttachName:(uniquename ((selection as array)[1].name)) =
(
if (AttachNodes != undefined and AttachNodes.count != 0) then
(
Object1 = AttachNodes[1] -- Get first object in selection
ObjectSel = for i = 1 to AttachNodes.count where (AttachNodes[i] != Object1) collect AttachNodes[i] -- Get selected objects excluding the first one
AllVecPositions = #() -- Initial position array
AllVertTypes = #() -- Initial handle array
select Object1 -- Select first object
if (classof Object1 != Editable_Patch) then
(
if (classof Object1 == Editable_Poly or classof Object1 == PolyMeshObject or classof Object1 == Editable_Mesh) then
(
modPanel.addModToSelection (Turn_to_Patch ()) ; macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch, retain quads
) else macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch
) -- Convert first object to patch if its not already a patch
Steps = getPatchSteps Object1 -- Get patch steps of first object
ShowInterior = patch.getShowInterior Object1 -- Get show interior edges
Loops2Sided = #{} -- Closed loops with only 2 edges
for i = 1 to (patch.getNumEdges Object1) do
(
local Edges1 = ((patch.getVertEdges Object1 ((patch.getEdgeVert1 Object1 i) + 1)) as bitarray) -- Get edges from first vertex
local Edges2 = ((patch.getVertEdges Object1 ((patch.getEdgeVert2 Object1 i) + 1)) as bitarray) -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then Loops2Sided += #{((patch.getEdgeVert1 Object1 i) + 1), ((patch.getEdgeVert2 Object1 i) + 1)} -- Get both edges
) -- Get 2-sided closed loops on first object
patch.deletePatchParts Object1 Loops2Sided #{} -- Delete 2-sided loops on first object to avoid vertex count mismatch
setPatchSteps Object1 0 -- Set patch steps of first object to 0
AllVertsNum = (patch.getNumVerts Object1) -- Get vertex number of first object
if (AllVertsNum >= 3) then
(
AllVecPositions = (for i = 1 to AllVertsNum collect (for j = 1 to (patch.getVertVecs Object1 i).count collect (patch.getVec Object1 (patch.getVertVecs Object1 i)[j]))) as array -- Get 3d array of handle positions of first object
AllVertTypes = (for i = 1 to AllVertsNum collect patch.getVertType Object1 i) as array -- Get array of vertex tangent types of first object
) -- If there is at least three vertices in the first object i.e. a face exists
macros.run "Modifier Stack" "Convert_to_Poly" -- Convert to editable poly, using turn to poly mod in order to retain quads
for i = 1 to ObjectSel.count do
(
if (classof ObjectSel[i] != Editable_Patch) then
(
select ObjectSel[i] -- Select current object
if (classof ObjectSel[i] == Editable_Poly or classof ObjectSel[i] == PolyMeshObject or classof ObjectSel[i] == Editable_Mesh) then
(
modPanel.addModToSelection (Turn_to_Patch ()) ; macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch, retain quads
) else macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to patch
) -- Convert current object to patch if its not already a patch
local Loops2Sided1 = #{} -- Closed loops with only 2 edges
local AllVertsNum1 = (patch.getNumVerts ObjectSel[i]) -- Get vertex number of current object
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 Loops2Sided1 += #{((patch.getEdgeVert1 ObjectSel[i] i) + 1), ((patch.getEdgeVert2 ObjectSel[i] i) + 1)} -- Get both edges
) -- Get 2-sided closed loops on current object
patch.deletePatchParts ObjectSel[i] Loops2Sided1 #{} -- Delete 2-sided loops on attached object to avoid vertex count mismatch
if (AllVertsNum1 >= 3) then
(
local AllVecPositions1 = (for j = 1 to AllVertsNum1 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 AllVertTypes1 = (for j = 1 to AllVertsNum1 collect patch.getVertType ObjectSel[i] j) as array -- Get array of vertex tangent types of current node
AllVertsNum += AllVertsNum1 -- Add vertice selections
AllVecPositions += AllVecPositions1 -- Add positions together
AllVertTypes += AllVertTypes1 -- Add vert types together
) -- If there is at least three vertices in the current object i.e. a face exists
setPatchSteps ObjectSel[i] 0 -- Set patch steps of current node to 0
) -- Loop through object selection
select Object1 ; macros.run "Modifier Stack" "Convert_to_Poly" -- Select first object and convert to poly
for i = 1 to ObjectSel.count do polyop.attach Object1 ObjectSel[i] -- Attach objects to first object
Object1.deleteIsoVerts() -- Delete isolated vertices
modPanel.addModToSelection (Turn_to_Patch ()) ; macros.run "Modifier Stack" "Convert_to_Patch" -- Convert to editable patch, using turn to patch mod in order to retain quads
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
) -- Loop through handles
) -- If vertices match and vert's handle numbers match
) -- Loop through vertices
) -- If vertex counts match
if ((patch.getNumVerts Object1) >= 3 and AllVertTypes.count == (patch.getNumVerts Object1)) then (for i = 1 to (patch.getNumVerts Object1) do (if (AllVertTypes[i]) != undefined do patch.changeVertType Object1 i (AllVertTypes[i]))) -- Return vertex tangent types to what they were previously
setPatchSteps Object1 Steps -- Set patch steps to what they were previously
patch.setShowInterior Object1 ShowInterior -- Set show interior edges to what it was previously
patch.update Object1 -- Update patch
CenterPivot Object1 ; WorldAlignPivot Object1 -- Fix object's transforms
Object1.name = AttachName -- Update patch and fix its transforms
return Object1 --Get node
) -- If objects exist
)
Its a little slower than I would've wanted, but its not too bad. I did timestamp tests using my first method and my second method and also your pick method. Here are the results on my machine attaching 100 spheres -
Method 1 - Single attach, getting and resetting vertex handles, function ran on each object looping through selection.
Method 1 = 68.3 seconds
Method 2 - Multiple attach, getting and resetting vertex handles, appending arrays.
Method 2 = 10.6 seconds
Method 3 - Multiple attach, picking objects in viewport.
Method 3 = 6.8 seconds
Although the pick method is the fastest, I did notice a problem. After a running this on large numbers of selections -
with redraw off
(
viewport.resetAllViews()
ObjectSel1 = (selection as array)
target = ObjectSel1[1]
sources = for i = 1 to ObjectSel1.count where (ObjectSel1[i] != target) collect ObjectSel1[i]
convertto target Editable_Patch
select target
max modify mode
pickPatchAttach sources
)
It looks like its missing about a third of the objects. -
[[img] http://img694.imageshack.us/img694/7474/patchattachingerror.jpg[/img]]( http://img694.imageshack.us/img694/7474/patchattachingerror.jpg[/img]]( g"/> /)
I tried then, reselected the attached patches then selecting the rest and trying to evaluate again. I did this over and over a bunch of times. It attached a couple of spheres, but eventually stopped attaching anything…Not sure what’s going on, but maybe this method isn’t so good for a large selection…
check a c++/sdk solution http://forums.cgsociety.org/showpost.php?p=7508910&postcount=27
Yeah…that is way over my head, much more then your picking method. I have very limited c++ knowledge. I’ve written some basic mental ray shaders in c++, but not much beyond that. Do you have to compile anything with that? How do you call that in a function? I tried evaluating it and the listener spits out –
-- Error occurred in anonymous codeblock; filename: ; position: 35; line: 1
-- Syntax error: at ,, expected <factor>
-- In line: def_visible_primitive(patchAttach, "
Yeah I probably could just use convertto for converting to poly, but I need to use the Turn_to_Patch modifier before conversion to convert a mesh with quads to a patch with quads, otherwise using convertto node Editable_Patch converts the whole model to tri patches. Is there a conversion function that I’m missing, which keeps quads?
I was thinking though, maybe you could use a hybrid of our two methods by finding which nodes have closed 2-sided edge loops, and using the your method for those, and using my method for the rest. Or using mine, if the amount of nodes used, is over say, 20.
you don’t need all these stack operations. just simply use
if iskindof node Editable_Patch then node else convertto node Editable_Patch
if iskindof node Editable_Poly then node else convertto node Editable_Poly
convertto returns undefined if it can’t convert to the specified class.
also i don’t see any reason to select every processing node.
Yeah that’s true, I’m going back in my multi-attach function, and make it so that the only object that’s selected, is the first node, which everything gets attached to. I switched to using –
addModifier node (Turn_to_Patch ()) ; convertto node Editable_Patch
to convert to patch, in order to not have to select anything, and keep quad faces. This will speed the function up a lot, thanks denis.
it seams like your attach doesn’t work right. try this setup:
delete objects
target = Quadpatch name:"target" pos:[-10,0,0] length:10 lengthsegs:4 width:10 widthsegs:4
convertto target Editable_Patch
source = Quadpatch pos:[0,0,0] length:8 lengthsegs:2 width:8 widthsegs:2
convertto source Editable_Patch
patch.setvert source 5 [0,0,4]
patch.update source
-- AttachPatch obj:target attachnode:source
Use this function instead –
fn AttachObjectsPatch AttachNodes:(selection as array) AttachName:(uniquename ((selection as array)[1].name)) =
(
if (AttachNodes != undefined and AttachNodes.count != 0) then
(
Object1 = AttachNodes[1] -- Get first object in selection
ObjectSel = for i = 1 to AttachNodes.count where (AttachNodes[i] != Object1) collect AttachNodes[i] -- Get selected objects excluding the first one
AllVecPositions = #() -- Initial position array
AllVertTypes = #() -- Initial handle array
select Object1 -- Select first 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
Steps = getPatchSteps Object1 -- Get patch steps of first object
ShowInterior = patch.getShowInterior Object1 -- Get show interior edges
Loops2Sided = #{} -- Closed loops with only 2 edges
for i = 1 to (patch.getNumEdges Object1) do
(
local Edges1 = ((patch.getVertEdges Object1 ((patch.getEdgeVert1 Object1 i) + 1)) as bitarray) -- Get edges from first vertex
local Edges2 = ((patch.getVertEdges Object1 ((patch.getEdgeVert2 Object1 i) + 1)) as bitarray) -- Get edges from second vertex
if ((Edges1 * Edges2).numberset == 2) then Loops2Sided += #{((patch.getEdgeVert1 Object1 i) + 1), ((patch.getEdgeVert2 Object1 i) + 1)} -- Get both edges
) -- Get 2-sided closed loops on first object
patch.deletePatchParts Object1 Loops2Sided #{} -- Delete 2-sided loops on first object to avoid vertex count mismatch
setPatchSteps Object1 0 -- Set patch steps of first object to 0
AllVertsNum = (patch.getNumVerts Object1) -- Get vertex number of first object
if (AllVertsNum >= 3) then
(
AllVecPositions = (for i = 1 to AllVertsNum collect (for j = 1 to (patch.getVertVecs Object1 i).count collect (patch.getVec Object1 (patch.getVertVecs Object1 i)[j]))) as array -- Get 3d array of handle positions of first object
AllVertTypes = (for i = 1 to AllVertsNum collect patch.getVertType Object1 i) as array -- Get array of vertex tangent types of first object
) -- If there is at least three vertices in the first object i.e. a face exists
convertto Object1 Editable_Poly ; update Object1 -- Convert to poly and update
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
local Loops2Sided1 = #{} -- Closed loops with only 2 edges
local AllVertsNum1 = (patch.getNumVerts ObjectSel[i]) -- Get vertex number of current object
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 Loops2Sided1 += #{((patch.getEdgeVert1 ObjectSel[i] i) + 1), ((patch.getEdgeVert2 ObjectSel[i] i) + 1)} -- Get both edges
) -- Get 2-sided closed loops on current object
patch.deletePatchParts ObjectSel[i] Loops2Sided1 #{} -- Delete 2-sided loops on attached object to avoid vertex count mismatch
if (AllVertsNum1 >= 3) then
(
local AllVecPositions1 = (for j = 1 to AllVertsNum1 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 AllVertTypes1 = (for j = 1 to AllVertsNum1 collect patch.getVertType ObjectSel[i] j) as array -- Get array of vertex tangent types of current node
AllVertsNum += AllVertsNum1 -- Add vertice selections
AllVecPositions += AllVecPositions1 -- Add positions together
AllVertTypes += AllVertTypes1 -- Add vert types together
) -- If there is at least three vertices in the current object i.e. a face exists
setPatchSteps ObjectSel[i] 0 -- Set patch steps of current node to 0
) -- Loop through object selection
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
) -- Loop through handles
) -- If vertices match and vert's handle numbers match
) -- Loop through vertices
) -- If vertex counts match
if ((patch.getNumVerts Object1) >= 3 and AllVertTypes.count == (patch.getNumVerts Object1)) then (for i = 1 to (patch.getNumVerts Object1) do (if (AllVertTypes[i]) != undefined do patch.changeVertType Object1 i (AllVertTypes[i]))) -- Return vertex tangent types to what they were previously
setPatchSteps Object1 Steps -- Set patch steps to what they were previously
patch.setShowInterior Object1 ShowInterior -- Set show interior edges to what it was previously
patch.update Object1 -- Update patch
CenterPivot Object1 ; WorldAlignPivot Object1 -- Fix object's transforms
Object1.name = AttachName -- Update patch and fix its transforms
return Object1 --Get node
) -- If objects exist
)
It seems to work fine on the two quad patches. The only patches it doesn’t work good with is geometry with 2 sides, like the handle on a teapot –
btw. the c++ attach function attached 100 quad patches for 0.7 sec. you function after some optimization does the same for 30 secs.
I have very limited c++ knowledge. I’ve written some basic mental ray shaders in c++, but not much beyond that. Do you have to compile anything with that? How do you call that in a function? I tried evaluating it and the listener spits out
you would need to create a dlx plugin to extend mxs using ms visual studio (version used depends on max version you need to compile for). The most difficult part is setting up the initial project for the build. Once it’s created the process is mostly painless, but it’s definitely worth it. (thisis quite old now but mostly still valid if you are interested in taking it further).