Realign uv mapping from script



  • On 09/02/2017 at 01:19, xxxxxxxx wrote:

    Hi,

    I am trying to realign UV mapping of an object from script. I want the same result from script that I get when I press the apply button in the UV optimal mapping tool.

    Here is the settings and the result when i press the apply button:

    https://postimg.org/image/oh298vdzr/

    Here is the code that I expect to do the same thing (I have used the code from Andreas in this post: https://plugincafe.maxon.net/topic/9738/13094_new-calluvcommand and changed the settings) :

    import c4d
    from c4d import utils
    from c4d import gui
    from c4d.modules import bodypaint

    def applyRealign(doc,obj) :

    for tag in obj.GetTags() :
          if type(tag) == c4d.UVWTag:
              uvwTag = tag
              doc.SetActiveObject(obj)
              doc.SetActiveTag(uvwTag)

    # Retrieves active UVSet
              handle = bodypaint.GetActiveUVSet(doc, c4d.GETACTIVEUVSET_ALL)
              if not handle:
                  print "No active UVSet!"
                  return

    settings = c4d.BaseContainer()

    settings[c4d.OPTIMALMAPPING_PRESERVEORIENTATION] = 0
              settings[c4d.OPTIMALMAPPING_STRETCHTOFIT] = 0
              settings[c4d.OPTIMALMAPPING_EQUALIZEAREA] = 1
              settings[c4d.OPTIMALMAPPING_SPACING] = 0.02

    # Retrieves UVW list
              uvw = handle.GetUVW()
              if uvw is None:
                  return

    # Calls UVCOMMAND_TRANSFORM to change UVW list
              ret = bodypaint.CallUVCommand(handle.GetPoints(), handle.GetPointCount(), handle.GetPolys(), handle.GetPolyCount(), uvw,
                                            handle.GetPolySel(), handle.GetUVPointSel(), obj, handle.GetMode(), c4d.UVCOMMAND_REALIGN, settings)
              if not ret:
                  print "CallUVCommand() failed!"
                  return

    print "CallUVCommand() successfully called"

    # Sets the transformedUVW from Texture View
              if handle.SetUVWFromTextureView(uvw, True, True, True) :
                  print "UVW from Texture View successfully set"
              else:
                  print "UVW from Texture View failed to be set!"

    # Releases active UVSet
              bodypaint.FreeActiveUVSet(handle)

    def main() :
      # Get the selected objects, including children.
      selection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
     
      if len(selection) <= 0:
          gui.MessageDialog('Must select objects!')
          return

    #  doc.StartUndo()  # Start undo block.
      for i in range(0,len(selection)) :
          sel = selection      applyRealign(doc,sel)

    if __name__=='__main__':
      main()

    And this is the resulting uv mapping after running the script:

    https://postimg.org/image/sc11xp7rr/

    It seems that OPTIMALMAPPING_SPACING is not set to the specified value. It seems that the resulting spacing is around 50%. I have tried different values for OPTIMALMAPPING_SPACING but the resulting mapping always seem to use a bigger spacing than requested.

    I am missing something or is this a bug?

    Cheers,

    Per



  • On 10/02/2017 at 02:13, xxxxxxxx wrote:

    Hi,

    The value 0.02 for OPTIMALMAPPING_SPACING is valid. The issue isn't there but in other parts of your script (please use

    tags for better formatting of code snippets).

    With the following loop the script doesn't run fine:

    for i in range(0,len(selection)) :
        sel = selection
    

    In fact the previous lopp isn't needed. You can call applyRealign(doc) once with just the active document.
    Also don't change the active object and tag from the script. TempUVHandle.GetBaseObject() gives the object for the current UV context.

    So the fixed script that gives the same result as the UI is:

    import c4d
    from c4d import gui
    from c4d.modules import bodypaint
      
    def **applyRealign(doc)** :
      
        # Retrieves active UVSet
        handle = bodypaint.GetActiveUVSet(doc, c4d.GETACTIVEUVSET_ALL)
        if not handle:
            print "No active UVSet!"
            return
        
        settings = c4d.BaseContainer()
        settings[c4d.OPTIMALMAPPING_PRESERVEORIENTATION] = **False**
        settings[c4d.OPTIMALMAPPING_STRETCHTOFIT] = **False**
        settings[c4d.OPTIMALMAPPING_EQUALIZEAREA] = **True**
        settings[c4d.OPTIMALMAPPING_SPACING] = 0.02
      
        # Retrieves UVW list
        uvw = handle.GetUVW()
        if uvw is None:
            return
        
        # Calls UVCOMMAND_TRANSFORM to change UVW list
        ret = bodypaint.CallUVCommand(handle.GetPoints(), handle.GetPointCount(), handle.GetPolys(), handle.GetPolyCount(), uvw,
                                      handle.GetPolySel(), handle.GetUVPointSel(), **handle.GetBaseObject()** , handle.GetMode(), c4d.UVCOMMAND_REALIGN, settings)
        if not ret:
            print "CallUVCommand() failed!"
            return
        
        print "CallUVCommand() successfully called"
      
        # Sets the transformedUVW from Texture View 
        if handle.SetUVWFromTextureView(uvw, True, True, True) :
            print "UVW from Texture View successfully set"
        else:
            print "UVW from Texture View failed to be set!"
        
        # Releases active UVSet
        bodypaint.FreeActiveUVSet(handle)
      
      
    def main() :
        # Get the selected objects, including children.
        selection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
     
        if len(selection) <= 0:
            gui.MessageDialog('Must select objects!')
            return
        
        **applyRealign(doc)**
      
      
    if __name__=='__main__':
        main()
    


  • On 13/02/2017 at 02:01, xxxxxxxx wrote:

    Hi and thanks for your reply :-)

    I should have described better what I want the script to do. I want the script to iterate all selected objects and automatically remap the UVs without having to manually make one active.

    With your changes only one object seems to be remapped and only the active UV.

    Cheers,

    Per



  • On 13/02/2017 at 02:25, xxxxxxxx wrote:

    Hi Per,

    Thanks for the clarification.

    I think you're just missing a call to c4d.EventAdd() after setting the active object and tag (only call SetActiveObject() once for an object in applyRealign()) so that Cinema updates all its data for the document.

    Also the loop in main() should be changed to (if not done yet) :

    for obj in selection:
        applyRealign(doc, obj)
    

Log in to reply