SME: GetSelectedNodes done right....


#1

A minor headache, thought this was worth a share…

https://davewortley.wordpress.com/2017/11/15/sme-slating-the-right-nodes/

(code looks better here than on my blog)


fn getSelectedFromSME =
(
   --The Problem with the SME and 3dsmax in general is that maps/materials can share the same name, and to get the selected materials from the SME we need to reference by name... this can easily cause problems with complex material sub-trees.
   --Below is a function which does a dirty work-around of this by temporarily giving every map a unique name, then collecting the selection of mats/maps, then renaming back to original names.
   
   --Get all the node names in SME
   smeNames = (for i = 1 to (sme.getView (sme.activeView)).GetNumNodes() collect ((sme.getView (sme.activeView)).getNode i).name)
      
   --let's see if we have clashing material/map names in the SME before we bother doing dirty tricks
   if (makeUniqueArray smeNames).count == smeNames.count then
   (
      --If no clashes we can use the standard method for getting the selected nodes by looking at the trackview and finding the name
      selNodes = (sme.GetView (sme.activeView)).getselectednodes()
      selectedNodesNames = for o in selNodes collect o.name

      selectedMaps = #()
      for i = 1 to trackViewNodes[#sme][sme.activeView].numSubs do
      (
         if (superclassof trackViewNodes[#sme][sme.activeView][i].reference == textureMap or superclassof trackViewNodes[#sme][sme.activeView][i].reference == material) and finditem selectedNodesNames trackViewNodes[#sme][sme.activeView][i].reference.name != 0 do
            append selectedMaps trackViewNodes[#sme][sme.activeView][i].reference
      )

      selectedMaps
   )
   else
   (
      --if not, we need to work out which are nodes which have the same name, create a list of these
      allItems = makeUniqueArray smeNames
      for i = 1 to allItems.count do (deleteitem smeNames (finditem smeNames allItems[i]))
      clashNames = (makeUniquearray (smeNames))
      
      --we'll use this array to keep a record of which we changed
      changeID = #()
      
      --loop through all the nodes in the SME
      for i = 1 to trackViewNodes[#sme][sme.activeView].numSubs do
      (
         --if we find one which has a clashing name.....
         if (finditem clashNames trackViewNodes[#sme][sme.activeView][i].reference.name) != 0 do
         (
            --add it to our change ID with the index and original name
            append changeID (datapair v1:i v2:trackViewNodes[#sme][sme.activeView][i].reference.name)
            
            --set the name to a unique name using what will hopefully be a safe name
            trackViewNodes[#sme][sme.activeView][i].reference.name += ("_________________________________" + i as string)
            
         )
      )
   
      --Now we can get the selected names and all names will be unique
      selNodes = (sme.GetView (sme.activeView)).getselectednodes()
      selectedNodesNames = for o in selNodes collect o.name

      selectedMaps = #()
      
      --now we loop through the trackView SME nodes and find the references using the names (as all names are now unique)
      for i = 1 to trackViewNodes[#sme][sme.activeView].numSubs do
      (
         if (superclassof trackViewNodes[#sme][sme.activeView][i].reference == textureMap or superclassof trackViewNodes[#sme][sme.activeView][i].reference == material) and finditem selectedNodesNames trackViewNodes[#sme][sme.activeView][i].reference.name != 0 do
            append selectedMaps trackViewNodes[#sme][sme.activeView][i].reference
      )
      --this returns an array of maps/materials values - at this point the names have been modified but now we have a pointer to the map/mat it doesn't matter any more
      selectedMaps

      --now we loop through our change ID and change them back to original (clashing) names so the user won't freak out
      for o in changeID do
         trackViewNodes[#sme][sme.activeView][o.v1].reference.name = o.v2
      
      --Our array of materials/maps values have the original names but we'll have the correct mat/map values in our array.
      selectedMaps
   )
)
getSelectedFromSME()



#2

Can you share some test example where this one doesn’t work?


fn getSMEselection = if MatEditor.mode == #advanced do (
    
    viewNode = sme.GetView (sme.activeView)
    smeSelection = #()
    for n = 1 to trackViewNodes[#sme][(sme.activeView)].numSubs do (
        
        ref     = trackViewNodes[#sme][(sme.activeView)][n].reference
        smeNode = viewNode.GetNodeByRef ref
        
        if smeNode.selected do append smeSelection ref
            
    )
    
    smeSelection
    
)


#3

Aha that’s a much better method! I hadn’t seen any examples of getting the material from SME without using name so it’s nice to know there is a way around this!

That’s awesome thanks for sharing, will be switching my function out for this one instead, much more efficient!


#4

Actually denisT posted that back in 2012 here.

-Eric


#5

Show’s how much I use the Slate Material Editor doesn’t it!


#6

i’ve never used it… :stuck_out_tongue:


#7

did some coding before…
heres a simpler way… SME nodes have .selected and .reference property


smeNodesSelected = for i = 1 to (SME.getView SME.activeView).GetNumNodes() where ((SME.getView SME.activeView).getNode i).selected collect ((SME.getView SME.activeView).getNode i)
nodeNames = for i = 1 to smeNodesSelected.count collect ((smeNodesSelected[i]).reference)


#8

what max version do you use? i use max 2016… it still doesn’t have .reference property in <MixinInterface:Node>


#9

v = SME.getView SME.activeView
smeNodesSelected = for i = 1 to v.GetNumNodes() where (n = v.getNode i).selected collect n


#10

by the way im using 3ds max 2017… ddnt checked previous version… i think its not documented… i checked with the fn showInterface <interface>


#11

believe me we know how to get an interface methods. however it’s good to know that max 2017+ has these properties exposed to mxs


#12

That’s best code shrinking I’ve seen in long time <3