Home Technical Talk

MaxScript questions

polycount lvl 666
Offline / Send Message
PolyHertz polycount lvl 666
Similar to my MEL Questions thread from a while ago (thanks everyone for helping me on that btw :) ), Im spending some time learning Maxscript and have some questions I'd like to ask.

Only one question for the time being (but more to follow):

1. Is their a universal way to open options windows for specific tools? For example, If I wanted to use the connect tool I could use something like:
$.connectEdgeSegments = 1
to make an edge connection with a specified number of segments or
$.EditablePoly.ConnectEdges ()
to connect edges based on the previous settings used in the tool. But how would I go about opening the options window that contains segments/slide/pinch values? Is their a universal way to do this across all standard poly modeling tools? The listener doesn't record this action and I'm finding the Maxscript help to be far less user friendly then Mayas.

edit: oh just fyi, I'm using Max2009 x64.

Replies

  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    Hi Greg, the properties you're looking for are unique for each Editable Poly. You can get/set them with:
    <Editable_Poly>.connectEdgeSegments Integer default: 1 -- integer;
    Get/Set the default Connect Edge Segments value.

    <Editable_Poly>.connectEdgePinch Integer default: 0 -- integer;
    Get/Set the Pinch value in the Edge Connect options dialog.

    <Editable_Poly>.connectEdgeSlide Integer default: 0 -- integer;
    Get/Set the Slide value in the Edge Connect options dialog.

    See Editable_Poly Properties for all the other settings you're looking for. A little piece of advice, in the reference don't trust the Index, perform a Search.

    For methods related to connecting edges, see
    EditablePoly Interface - Connect
    EditablePoly Interface - UI Commands - buttonOp #ConnectEdges method

    If you want to set these parameters for each Editable Poly in the scene you need to loop over every single valid node and do it like:
    for theNode in Geometry where ((classOf theNode.baseObject) == Editable_Poly) do
    (
        theNode.baseObject.connectEdgeSegments = 2
        theNode.baseObject.connectEdgePinch = 50
        theNode.baseObject.connectEdgeSlide = 25
    )
    
  • Bryan Cavett
    Offline / Send Message
    Bryan Cavett polycounter lvl 19
    SyncViews: I believe he actually wants the popup dialog to show up. If thats the case then use:
    <bool><EditablePoly>.PopupDialog <enum>popupOperation
    
    popupOperation enums: 
    
    { #GrowSelection | #ShrinkSelection | #SelectEdgeLoop 
    
    | #SelectEdgeRing | #HideSelection | #HideUnselected 
    
    | #UnhideAll | #NamedSelectionCopy | #NamedSelectionPaste 
    
    | #Cap | #Delete | #Remove 
    
    | #Detach | #AttachList | #SplitEdges 
    
    | #BreakVertex | #Collapse | #ResetSlicePlane 
    
    | #Slice | #WeldSelected | #CreateShape 
    
    | #MakePlanar | #AlignGrid | #AlignView 
    
    | #RemoveIsoVerts | #MeshSmooth | #Tessellate 
    
    | #Update | #SelectByVertexColor | #Retriangulate 
    
    | #FlipNormals | #SelectByMatID | #SelectBySmoothingGroups 
    
    | #Autosmooth | #ClearSmoothingGroups | #Extrude 
    
    | #Bevel | #Inset | #Outline 
    
    | #ExtrudeAlongSpline | #HingeFromEdge | #ConnectEdges 
    
    | #ConnectVertices | #Chamfer | #Cut 
    
    | #RemoveIsoMapVerts | #ToggleShadedFaces 
    
    | #MakePlanarInX | #MakePlanarInY |#MakePlanarInZ }
    
     
    
    Push the popup dialog's button for the specified interactive operation.
    
    

    So something like this:
    $.EditablePoly.popupDialog #ConnectEdges
    
  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    Well, I guess I misread. Now there are also answers to questions never asked :D
  • PolyHertz
    Offline / Send Message
    PolyHertz polycount lvl 666
    Hey thanks guys :)
    Yea, Bryan that's exactly what I was after. Sorry for not replying earlier, but didn't want to have to bump the thread with a double post later.

    Anyhow, got two new questions I'd like to ask:

    2. How would you determin the type of modifier the user has selected, and whats the best approach to dealing with Edit Poly modifiers (so that a function works on both Editable Poly and Edit Poly)? Is it best to just iterate down through the stack until reaching it / hitting the bottom, performing the appropriate action and then returning to the originally selected sub object level, or is their a faster way?

    3. Max seems to give a return value for every "if" statement, even if its false (in which case it returns "undefined"). Is this alright? In MEL it would simply ignore such cases and give no return as it was generally not needed. Giving dozens of "undefined" returns for a simple script seems odd. This may be a dumb question, but I'm wondering if its something I should be concerned with.
  • PolyHertz
    Offline / Send Message
    PolyHertz polycount lvl 666
    Bumping this thread in hopes that someone can answer the the questions in my last post. threads get pushed back to other pages way too fast -_-
  • Funky Bunnies
    Offline / Send Message
    Funky Bunnies polycounter lvl 17
    2. classOf $.baseobject == Editable_Poly can tell you if you're on a poly object, but in this case I think iterating through would be the best bet. Or if you're assuming there's only one you could always do if $.modifiers[#Edit_Poly] != undefined blahblah I guess. iterating through isnt too super slow though.

    3. hmm what's returning undefined after an if statement? a function? If it's a function and you set a return value for the 'If' statement and no catch return statement for the 'Else' it'll return undefined when 'Else' is run.
  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    Hi Greg, I'm going to try an answer.

    2.
    The Base Object, like an Editable Poly, can be accessed with the syntax:
    <node>.baseObject
    

    Ref: "General Node Properties"

    The Modifiers in the Stack, like Edit Poly Modifier, are grouped in a collection called Modifiers, so you can get a pointer them with the syntax:
    <node>.modifiers[i] -- where i is the index starting from 1 at the bottom for the first modifier
    

    Ref: "Modifier Common Properties, Operators, and Methods"

    The currently active modifier/base object can be retrieved with:
    modPanel.getCurrentObject()
    
    then you need to check its class to determine its nature.
    theEditObj = modPanel.getCurrentObject()
    if ((classOf theEditObj) == Editable_Poly) then -- for Base Object
    (
        ...
    )
    else if ((classOf theEditObj) == Edit_Poly) then -- for Modifier
    (
        ...
    )
    

    Ref: "Modify Panel"

    If you want to write a function that works seamlessly on both EditablePoly and EditPolyModifier, you need to get the currently active EditObject in the Modifier Stack, determine its nature and execute the specific code. If none of them is active, you got two choices: one let the function fail (do nothing), two activate first suitable Edit Object in the Stack and run the proper code.

    To do that you must cycle over the Modifiers array from the position you currently are and one by one scan for the EditPoly Modifier until reach the bottom, the Base Object (in reverse, because first modifier is the lowest in the stack and you must scan it from top to bottom). While scanning you need to turn off the modifiers because the geometry pipeline evaluation must be stopped at the right Modifier/BaseObject. In other words what you you see in viewport is the actual geometry. In example, if you got a box, made by 8 verts and apply a TurboSmooth it becomes a 26 verts box. If you activate the baseObject but have the Show End Result active and query the number of vertices, you got still 26. after the function you need to turn back on the modifiers. The most clever way to do that is to save their state into an array while scanning and then revert their state to the saved one.

    You can take a look at the two functions I coded to perform these actions on the stack for the Editable Poly as Base Object on IllusionCatalyst web site, page MaxScript, under "Editable Poly data from underlying Mesh", functions modViewOff() and modViewOn(). They're not the most updated, but do the job.

    Keep in mind that when you deal with Editable Poly Modifiers, they MUST be the currently active Edit Object in the stack, or most of the function on them don't return any value. It means you can't perform anything by simply writing such as:
    $.modifiers[1].getNumVertices -- assuming first Modifier in the stack is an Edit Poly
    
    unless it is the currently active Edit Object. You set the Edit object with:
    modPanel.setCurrentObject <modifier | node | node_baseobject>
    

    About the general coding strategy to deal with both EditablePoly and EditPolyModifier, I usually build a wrapper. In this case a structure, which is initialized by taking the current node, then running functions such as modViewOff/On() and getting the BaseObject, the current Edit Object and the current Mesh. The the structure mimes the common polyOp structure and have functions which can execute the proper code depending on the object initialized. When you develop your code, rather than calling polyOp, or methods for the Edit Poly Modifier, you simply call that struct's methods, like:
    myPolyObj.getNumVerts() -- where myPolyObj is an istance of your multipurpose struct
    
    and it does the job returning what you want.

    3.
    I'm not completely sure about your question. I get it in this way: every if statement returns a value you can use to assign to a variable like:
    a = 3
    
    b = if (a == 2) then
    (
        false
    )
    else
    (
        true
    )
    print b -- in this case prints "true" because a == 3 and b value is now true
    
    This is a perfectly legal way to use the if statement but quite unusual in my experience. More often you simply use the statement like it is supposed to:
    a = 3
    b = undefined -- not needed but good practice
    
    if (a == 2) then
    (
        b = false
    )
    else
    (
        b = true
    )
    print b
    

    If it is not what you mean, please post a little sample of your code.
  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    Hi Greg, this is how things currently work in IC.Shape. Here is the PolyWrapper Structure, you can add your own methods to work with both EditablePoly and Edit Poly Modifiers.
    struct PolyWrapper
    (
        theNode = undefined,
        theEditObj = undefined,
        theMesh = undefined,
    
        _baModViewStatus = #{},
        _bNurmsStatus = false,
    
    --------------------------------------------------------------------------------
    
        function pwModViewOff =
        (
            if (isValidNode theNode) do
            (
                _baModViewStatus = #{}
    
                with redraw off
                (
                    if ((classOf theEditObj) == Editable_Poly) then
                    (
                        for i = 1 to theNode.modifiers.count do
                        (
                            if ( (theNode.modifiers[i].enabled == true) and (theNode.modifiers[i].enabledInViews == true) ) do
                            (
                                _baModViewStatus[i] = true
                                theNode.modifiers[i].enabledInViews = false
                            )
                        )
    
                        _bNurmsStatus = theNode.baseObject.surfSubdivide
                        theNode.baseObject.surfSubdivide = false
                    )
                    else if ((classOf theEditObj) == Edit_Poly) then
                    (
                        local iModIndex = modPanel.getModifierIndex theNode theEditObj
    
                        for i = 1 to (iModIndex-1) do
                        (
                            if ( (theNode.modifiers[i].enabled == true) and (theNode.modifiers[i].enabledInViews == true) ) do
                            (
                                _baModViewStatus[i] = true
                                theNode.modifiers[i].enabledInViews = false
                            )
                        )
                    )
                )
            )
        ),
    
        function pwModViewOn =
        (
            if (isValidNode theNode) do
            (
                with redraw off
                (
                    for i = 1 to theNode.modifiers.count do
                    (
                        if ( (theNode.modifiers[i].enabled == true) and (_baModViewStatus[i] == true) ) do
                        (
                            theNode.modifiers[i].enabledInViews = true
                        )
                    )
    
                    if ((classOf theEditObj) == Editable_Poly) do
                        theNode.baseObject.surfSubdivide = _bNurmsStatus
                )
    
                _baModViewStatus = #{}
                _bNurmsStatus = false
            )
        ),
    
    --------------------------------------------------------------------------------
    
        function initStruct initNode initEditObj =
        (
            theEditObj = initEditObj
    
            if ( (theEditObj != undefined) and ((superClassOf theEditObj) == Modifier) ) do
            (
                if ((findItem initNode.modifiers theEditObj) == 0) do
                (
                    select initNode
                    theEditObj = modPanel.getCurrentObject()
                )
            )
    
            if ( ((classOf theEditObj) == Editable_Poly) or ((classOf theEditObj) == Edit_Poly) ) then
            (
                theNode = initNode
    
                pwModViewOff()
                theMesh = theNode.mesh
                pwModViewOn()
            )
            else
            (
                theEditObj = undefined
                theNode = undefined
                theMesh = undefined
            )
        ),
    
    --------------------------------------------------------------------------------
    
        function getNumVerts =
        (
            local iNumVerts = 0
    
            if ((classOf theEditObj) == Editable_Poly) then
                iNumVerts = polyOp.getNumVerts theEditObj
            else if ((classOf theEditObj) == Edit_Poly) then
                iNumVerts = theEditObj.getNumVertices node:theNode
    
            return iNumVerts
        ),
    
        function getNumEdges =
        (
            local iNumEdges = 0
    
            if ((classOf theEditObj) == Editable_Poly) then
                iNumEdges = polyOp.getNumEdges theEditObj
            else if ((classOf theEditObj) == Edit_Poly) then
                iNumEdges = theEditObj.getNumEdges node:theNode
    
            return iNumEdges
        ),
    
        function getNumFaces =
        (
            local iNumFaces = 0
    
            if ((classOf theEditObj) == Editable_Poly) then
                iNumFaces = polyOp.getNumFaces theEditObj
            else if ((classOf theEditObj) == Edit_Poly) then
                iNumFaces = theEditObj.getNumFaces node:theNode
    
            return iNumFaces
        )
    
    )
    
    -- Sample
    (
        -- Instance the PolyWrapper structure
        local pw = PolyWrapper()
        
        -- Create a Sphere and convert it to an Editable Poly
        local theSphere = convertToPoly (Sphere())
        
        -- Create an instance of an Edit Poly Modifier and assign it to the Sphere 
        local theMod = EditPolyMod()
        addModifier theSphere theMod
        
        -- Set Command Panel in Modify mode and select the Sphere
        setCommandPanelTaskMode #Modify
        select theSphere
    
        -- Standard Edit Poly Modifier operations to modify the Sphere topology
        theMod.setEPolySelLevel #Vertex 
        theMod.select #Vertex #{1..33} select:true node:theSphere
        theMod.ButtonOp #RemoveVertex
    
        -- Set the Editable Poly as active in Modifier Stack (get a Warning)
        modPanel.setCurrentObject theSphere.baseObject
        -- Init the PolyWrapper to the Current Active Edit Object in the Stack
        pw.initStruct theSphere (modPanel.getCurrentObject())
        -- Call the PolyWrapper Methods
        format "The Editable Poly has % verts, % edges, % facesn" (pw.getNumVerts()) (pw.getNumEdges()) (pw.getNumFaces())
    
        -- Set the Edit Poly Modifier as active in Modifier Stack
        modPanel.setCurrentObject theSphere.modifiers[1]
        -- Init the PolyWrapper to the Current Active Edit Object in the Stack
        pw.initStruct theSphere (modPanel.getCurrentObject())
        -- Call the PolyWrapper Methods
        format "The Edit Poly Modifier has % verts, % edges, % facesn" (pw.getNumVerts()) (pw.getNumEdges()) (pw.getNumFaces())
    )
    

    You can see how the call to PolyWrapper methods is the same for both Editable Poly and Edit Poly Modifiers. You need to reinit the structure every time the scene/selection/stack has changed before calling its methods.
Sign In or Register to comment.