Page 1 of 2 12 LastLast
Results 1 to 15 of 26

Thread: Code Snippets (aka: "How to...")

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817

    Code Snippets (aka: "How to...")

    If it helps anyone, feel free to use these functions in your Python scripts...

    Code:
    ## the following returns a string containing
    ## the filepath to the content directory.
    
    def getContentDir():
        return lwsdk.LWDirInfoFunc('Content')
    Code:
    ## Given a string ("p") containing a file path to an image, the following
    ## attempts to load that image into the Image Editor. It then
    ## returns the name of that image and the image ID.
    
    def loadImage(p):
        IM = lwsdk.LWImageList()
        id = IM.load(p)
        name = IM.name(id)
        return name, id
    Code:
    ## this returns the FPS of the scene.
    
    def getFPS():
        info = lwsdk.LWSceneInfo()
        return info.framesPerSecond
    Code:
    ## these return the Preview Start and Preview End frames.
    
    def getPreviewStart():
        info = lwsdk.LWInterfaceInfo()
        return info.previewStart
    
    def getPreviewEnd():
        info = lwsdk.LWInterfaceInfo()
        return info.previewEnd
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  2. #2
    Member
    Join Date
    Oct 2003
    Location
    Orlando, FL
    Posts
    4,144
    Thanks, Jen!

  3. #3
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817

    Smile

    Quote Originally Posted by Dexter2999 View Post
    Thanks, Jen!


    Here's another set of functions that go together:

    Code:
    ## returns the item ID of a pyObj.
    
    def getObjID(pyObj):
        return lwsdk.itemid_to_str(pyObj)
    
    
    
    ## returns a list of pyObj representing the selected items in the scene.
    
    def getSelectedItems():
        interface_info = lwsdk.LWInterfaceInfo()
        return interface_info.selected_items()
    
    
    
    ## given a list of pyObjs, this function returns a list of IDs. It relies
    ## on the "getObjID" function above.
    
    def getIDs(pyObjs):
        li = []
        for pyObj in pyObjs:
            id = getObjID(pyObj)
            li.append(id)
        return li
    
    
           
    ## This function relies on three of the above functions to return
    ## a list of selected item IDs. It needs "getObjID", "getIDs" and
    ## "getSelectedItems"
     
    def getSelectedItemsIDs():    
        selected_items = getSelectedItems()
        objIDs = getIDs(selected_items)
        return objIDs
    
    
    
    ## This function returns the pyObj representing the current item.
    ## It relies on the "getSelectedItems" function, which is defined above.
    
    def getCurrentItem():
        return getSelectedItems()[0]
    
    
    
    ## This function returns the ID of the current item and relies on three
    ## of the above functions: "getCurrentItem", "getSelectedItems"
    ## and "getObjID"
    
    def getCurrentItemID():
        obj = getCurrentItem()
        return getObjID(obj)
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  4. #4
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817
    I prefer iterating over lists and dictionaries instead of while loops in Python, so these functions return dictionaries of specific item types in Layout:

    Code:
    ## returns a dictionary of objects. The keys contain the
    ## ID numbers, while the items contain the pyObjs themselves.
    
    def getObjects():
        d = {}
        info = lwsdk.LWItemInfo()
        item = info.first(lwsdk.LWI_OBJECT, None)
        while(item):
            id = getObjID(item)
            d[id] = {}
            d[id] = item
            item = info.next(item)
        return d
    Code:
    ## returns a dictionary of cameras. The keys contain the
    ## ID numbers, while the items contain the pyObjs themselves.
    
    def getCameras():
        d = {}
        info = lwsdk.LWItemInfo()
        item = info.first(lwsdk.LWI_CAMERA, None)
        while(item):
            id = getObjID(item)
            d[id] = {}
            d[id] = item
            item = info.next(item)
        return d
    Code:
    ## returns a dictionary of lights. The keys contain the
    ## ID numbers, while the items contain the pyObjs themselves.
    
    def getLights():
        d = {}
        info = lwsdk.LWItemInfo()
        item = info.first(lwsdk.LWI_LIGHT, None)
        while(item):
            id = getObjID(item)
            d[id] = {}
            d[id] = item
            item = info.next(item)
        return d
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  5. #5
    Kamehameha Chameleon BigHache's Avatar
    Join Date
    Sep 2006
    Location
    Future Past Life
    Posts
    1,899
    Good stuff! Thank you!

  6. #6
    automator of tasks xchrisx's Avatar
    Join Date
    Jul 2003
    Location
    Nevada
    Posts
    593
    Blog Entries
    6
    Just started to get into python coding for LW and this stuff helps a bunch. Thanks Jen.
    My Lscript Collection | LinkedIn
    3D Generalist IGT

  7. #7
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817

    Cool. I think I found a redundant line of code...

    Glad to help. Glancing at my code for getObjects/getCameras/getLights reveals a line that should probably be deleted.

    This:

    Code:
            d[id] = {}
            d[id] = item
    ...means the exact same thing as this:


    Code:
            d[id] = item
    There's no point in assigning an empty dictionary to a dictionary entry if I'm just going to replace it with a pyObj in the next line. It must have been a leftover from an earlier draft of the code.
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  8. #8
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817
    Two more "get directory" functions:

    Code:
    ## configs directory
    
    def getConfigsDir():
        return lwsdk.LWDirInfoFunc('Settings')
    
    
    
    ## temporary path directory
    
    def getTempDir():
        return lwsdk.LWDirInfoFunc('Temp')
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  9. #9
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817
    Typing in:

    Code:
    help(lwsdk)
    ...in PCore Console reveals a huge chunk of information which can be saved to a text file using "Save Log." This information includes these variables:

    Code:
        LWFTYPE_ANIMATION = 'Animations'
        LWFTYPE_CONTENT = 'Content'
        LWFTYPE_DYNAMICS = 'Dynamics'
        LWFTYPE_ENVELOPE = 'Envelopes'
        LWFTYPE_IMAGE = 'Images'
        LWFTYPE_INSTALL = 'Install'
        LWFTYPE_LIGHTS = 'Lights'
        LWFTYPE_MOTION = 'Motions'
        LWFTYPE_NODES = 'Nodes'
        LWFTYPE_OBJECT = 'Objects'
        LWFTYPE_PLUGIN = 'Plug-ins'
        LWFTYPE_PREVIEW = 'Previews'
        LWFTYPE_PSFONT = 'PSFonts'
        LWFTYPE_RADIOSITY = 'Radiosity'
        LWFTYPE_RIGS = 'Rigs'
        LWFTYPE_SCENE = 'Scenes'
        LWFTYPE_SETTING = 'Settings'
        LWFTYPE_SOUNDS = 'Sounds'
        LWFTYPE_SURFACE = 'Surfaces'
        LWFTYPE_VERTCACHE = 'VertCache'
    It looks like these variables and their values are what artists would use to get the directory paths they want using lwsdk.LWDirInfoFunc(). I've written code snippets above for getting the content directory, configs directory and temp path. Using the above information, here's a code snippet for getting the location of LWSN.exe:

    Code:
    import lwsdk
    import os
    
    def getLWSN():
        return os.path.join( lwsdk.LWDirInfoFunc('Install'), "lwsn.exe" )
    An alternative that uses the variable name for the same information:

    Code:
    import lwsdk
    import os
    
    def getLWSN():
        return os.path.join( lwsdk.LWDirInfoFunc(LWFTYPE_INSTALL), "lwsn.exe" )
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  10. #10
    Newbie Member skarloc's Avatar
    Join Date
    Apr 2008
    Location
    France
    Posts
    50
    Thanks awfully for these - they helped me (along with the LWPy videos on YouTube) to do 2 scripts. My first excursion into LW Scripting (and Python) and getting my head around (a) the Python syntax and (b) the LW data model was an interesting challenge.

    For those interested, the 2 scripts are similar; one aligns the positions of objects in Layout with the last object selected (like the "Align" options, except it does all 3 at the same time, avoiding that annoying problem of the selection being inverted, meaning you have to reselect the items each time you want to align them). The other one does the same, but also sets the rotation to be the same as the last object (a kind of one-frame parenting).

    If anyone wants them (even for study for your own scripts), leave me a message.

    P.S. I hope these functions didn't existe elsewhere...

    [Edit] Thanks also to GregMalick, for his channel code which put me on the right track for getting the current position. Thanks also to those who I haven't mentioned as well.
    Last edited by skarloc; 07-19-2012 at 10:02 AM.

  11. #11
    Newbie Member skarloc's Avatar
    Join Date
    Apr 2008
    Location
    France
    Posts
    50
    Here are a few lines of code I use to ensure that Parent In Place is correct :

    1) Before the process function :

    Code:
        def setPIP(self, state):
            if (self._cur_pip != state):
                lwsdk.command("ParentInPlace")
                self._cur_pip = state
    At the start of the process function :
    Code:
            init_pip = ((lwsdk.LWInterfaceInfo().generalFlags & lwsdk.LWGENF_PARENTINPLACE) == lwsdk.LWGENF_PARENTINPLACE)
            self._cur_pip = init_pip
    When I need to set the PIP :
    Code:
                self.setPIP(False)
                self.setPIP(True)
    On quitting the process function :
    Code:
            self.setPIP(init_pip)
    That way, I don't need to keep track of what the PIP is (with what I'm doing, I need to change it often).

  12. #12
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817

    Thanks, skarloc!!!!

    skarloc, thank you so much for that last post. Until you wrote that, I did not know one could execute commands just by writing:

    Code:
    lwsdk.command(<COMMAND>)
    This is a lot less cumbersome than the ga.evaluate(ga.data, <COMMAND>) method I was using in my scripts.

    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

  13. #13
    Newbie Member skarloc's Avatar
    Join Date
    Apr 2008
    Location
    France
    Posts
    50

    Smile

    No problem - To be honest, I've never used that method (but I've seen it written - and you're right, it's a bit cumbersome).

    Speaking of reducing cumbersonness, I've done a large number of wrappers for the functions so as to make the code more readable and homogeneous. For example :

    Code:
                lwsdk.command("Position %f %f %f" % (fb_x, fb_y, fb_z))
                lwsdk.command("Rotation %f %f %f" % (fb_h, fb_p, fb_b))
                if not autokey_is_on:
                    lwsdk.command("CreateKey %f" % current_time)
    I've replaced with :
    Code:
                self.setPositionAndRotation(fb_x,fb_y,fb_z,fb_h,fb_p,fb_b,current_time)
    where setPositionAndRotation is defined :

    Code:
        def setPositionAndRotation(self, x, y, z, h, p, b, cur_time):
            lwsdk.command("Position %f %f %f" % (x, y, z))
            lwsdk.command("Rotation %f %f %f" % (h, p, b))
            if not self._autokey_on:
                lwsdk.command("CreateKey %f" % cur_time)
    This means (obviously) that in my main body, I've got 1 line of code and not 4. Also, I'm not worried about forgetting the autokey bit.

    FYO, in order to read the position and rotation of a given object at a given time (which may or not be a frame) :

    Code:
        def getPositionAndRotation(self, object, cur_time):
            # Note : this returns degrees - hence the "* 57.2957795"
            groupID = lwsdk.LWItemInfo().chanGroup( object )
            chanID = lwsdk.LWChannelInfo().nextChannel(groupID, None)
            (x,y,z,h,p,b) = (0.0,0.0,0.0,0.0,0.0,0.0)
            while chanID:
                channelName = lwsdk.LWChannelInfo().channelName(chanID)
                if channelName == "Position.X":
                    x = lwsdk.LWChannelInfo().channelEvaluate(chanID, cur_time)
                elif channelName == "Position.Y":
                    y = lwsdk.LWChannelInfo().channelEvaluate(chanID, cur_time)
                elif channelName == "Position.Z":
                    z = lwsdk.LWChannelInfo().channelEvaluate(chanID, cur_time)
                elif channelName == "Rotation.H":
                    h = lwsdk.LWChannelInfo().channelEvaluate(chanID, cur_time) * 57.2957795
                elif channelName == "Rotation.P":
                    p = lwsdk.LWChannelInfo().channelEvaluate(chanID, cur_time) * 57.2957795
                elif channelName == "Rotation.B":
                    b = lwsdk.LWChannelInfo().channelEvaluate(chanID, cur_time) * 57.2957795
                # else - we don't care !
                chanID = lwsdk.LWChannelInfo().nextChannel(groupID, chanID)
            return (x,y,z,h,p,b)
    And to use it :

    Code:
            (fb_x,fb_y,fb_z,fb_h,fb_p,fb_b) = self.getPositionAndRotation(temp_obj,startTime)
    Last edited by skarloc; 07-20-2012 at 05:54 PM. Reason: Because I'm worth it.

  14. #14
    Hey All,

    I do apologize for the necro-post, but this thread has been amazingly useful. I do have one question, though: I see you're using lwsdk.LWChannelInfo().channelEvaluate to ask a Channel what value it has. But I noticed in the documentation there's a ChannelAccess class that SEEMS to do that same job. Unfortunately I have not gotten that working. I was curious if a.) there was some benefit to using that class instead and b.) ...how exactly do you get that working? Passing a channelID doesn't seem to work.

    B
    Go TEAM VAD!! \/

  15. #15
    Red Mage Celshader's Avatar
    Join Date
    Feb 2003
    Location
    Burbank, California
    Posts
    1,817
    Quote Originally Posted by NanoGator View Post
    Hey All,

    I do apologize for the necro-post, but this thread has been amazingly useful. I do have one question, though: I see you're using lwsdk.LWChannelInfo().channelEvaluate to ask a Channel what value it has. But I noticed in the documentation there's a ChannelAccess class that SEEMS to do that same job. Unfortunately I have not gotten that working. I was curious if a.) there was some benefit to using that class instead and b.) ...how exactly do you get that working? Passing a channelID doesn't seem to work.

    B
    I hope skarloc answers, myself. I have not yet used channelEvaluate, but I have a script that at one point loops through the keys of a channel and replaces the original key values with "overscan" values. I am posting that code here in case it is of use.

    Code:
    """
    Clone Overscan Camera by Jennifer Hachigian
    2014-04-14
    With thanks to Deuce Bennett.
    
    Usage: select a camera in the scene and run this script to clone an
    overscan version of that camera.
    """
    
    import lwsdk
    
    def error(arg1, arg2):
        """ simplified way to call an error message. """
        lwsdk.LWMessageFuncs().error(arg1, arg2)
        
    def getZoomFactorEnvelope(item):
        """ returns the ZoomFactor envelope if it exists, and
        None if no ZoomFactor enveloper exists. """
        zEnv = None
        cGrp = lwsdk.LWItemInfo().chanGroup(item)
        chan = lwsdk.LWChannelInfo().nextChannel(cGrp, None)
        while chan:
            chanName = lwsdk.LWChannelInfo().channelName(chan)
            if chanName == "ZoomFactor":
                zEnv = chan
            chan = lwsdk.LWChannelInfo().nextChannel(cGrp, chan)
        return zEnv
    
    def overscanZoomFactorEnvelope(chan, overscan):
        """ applies overscan to every key in the ZoomFactor envelope. """
        env = lwsdk.LWChannelInfo().channelEnvelope(chan)
        key = lwsdk.LWEnvelopeFuncs().nextKey(env, None)
        while key:
            val = lwsdk.LWEnvelopeFuncs().keyGet(env, key, lwsdk.LWKEY_VALUE)
            old_zoom = val[1]
            new_zoom = val[1]/(overscan)
            lwsdk.LWEnvelopeFuncs().keySet(env, key, lwsdk.LWKEY_VALUE, new_zoom)
            key = lwsdk.LWEnvelopeFuncs().nextKey(env, key)
        
    
    def cloneOverscanCamera():
        """ clones a selected camera, adjusts its resolution/zoom,
        and renames it with the percentage of overscan involved. """
        items = lwsdk.LWInterfaceInfo().selected_items()
        if not items:
            error("No selected items.", "Please select an item.")
            return
    
        item = items[0]
        if lwsdk.LWItemInfo().type(item) != lwsdk.LWI_CAMERA:
            error("No selected camera.", "Please select a camera.")
            return
        
        zEnv = getZoomFactorEnvelope(item)
        
        curTime = lwsdk.LWInterfaceInfo().curTime
        name = lwsdk.LWItemInfo().name(item)
        w, h = lwsdk.LWCameraInfo().resolution(item)
        
        """ get overscan value from user """
        text = lwsdk.LWMessageFuncs().askName("Input new width.", "Width", str(w))
        try:
            overscan = float(text)/float(w)
        except ValueError:
            error("Wrong value.", "Enter a number next time!")
            return
        except TypeError:
            error("Cancelled.", "User cancelled operation.")
            return
        
        new_w = int( text )
        new_h = int( h * (overscan) )
        
        lwsdk.command("Clone 1")
        lwsdk.command("Rename %s_overscan_%d%%" % (name, (overscan-1.0) * 100))
        lwsdk.command("FrameSize %d %d" % (new_w, new_h))
        
        if zEnv:
            """ apply overscan to the ZoomFactor envelope """
            overscanZoomFactorEnvelope(zEnv, overscan)
        else:    
            """ apply overscan to the static ZoomFactor value """
            zoom = lwsdk.LWCameraInfo().zoomFactor(item, curTime)
            new_z = zoom/(overscan)
            lwsdk.command("ZoomFactor %f" % new_z)
        
    cloneOverscanCamera()
    Jen's 3D -- LightWave stuff.
    Jen's 2D -- my comic book.

    Python is my smashing board. LightWave is my S.M.A.K.

Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •