Deformer_not_work



  • On 22/06/2018 at 22:19, xxxxxxxx wrote:

    Hi folks,
    I try to write a deformable plugin. He uses the PSR information of another object to control the position of the point of the deformed object, and the weight of a MAP control point. I have written ----op.Message (c4d.MSG_UPDATE). Why do I have to press "A (redraw)" to see the deformed object?
    My code:

    class test(plugins.ObjectData) :  
      """Spherify Modifier"""  
      def __init__(self) :  
          self.SetOptimizeCache(True)  
      def ModifyObject(self, mod, doc, op, op_mg, mod_mg, lod, flags, thread) :  
          marr = op.GetAllPoints()  
          cl = mod[c4d.OBJECT]  
          clp = cl.GetUp()  
          clm = cl.GetRelMl()  
          clpm = clp.GetMg()  
          vex = mod[c4d.MAP].GetAllHighlevelData()  
          cnt = len(vex)  
          for i in xrange(cnt ) :  
              if vex _:  
                  pos = ~clpm * op_mg * marr              pos += (clm * pos - pos) * vex _  
                   pos *= clpm  
                  marr _= ~op_mg * pos  
                  op.SetPoint(i,marr _)  
                    
          op.Message(c4d.MSG_UPDATE)  
          return True____
     _ _ _
    



    _ _ Any help appreciated.__




  • On 26/06/2018 at 06:24, xxxxxxxx wrote:

    Hi Faxwang,

    Regarding your issue, the main problem is that you use a link to another object.
    So that means you have to listen for a change in this object to be able to say to your modifier to update. But you also need to listen for the current matrix of the modified object.
    And that's the perfect purpose of CheckDirty.

    Another thing, self.SetOptimizeCache(True) is only used for Generator, and not a modifier.
    Another good practise is to make sure to define your constants (c4d.OBJECT / MAP) with a custom prefix in order to be sure there is no ID collision.

    I also rework your algorithm in order to not need an Up object.

    class test(plugins.ObjectData) :
        targetObj = None
        targetObjLastMg = None
        currentObj = None
        currentObjLastMg = None
      
        def CheckDirty(self, op, doc) :
            # Check if modified object is not already define (aka first execution of the Modifier)
            if self.currentObj is None:
                op.SetDirty(c4d.DIRTYFLAGS_DATA)
                return
      
            # Check if the matrice of the modified object is dirty or not, in order to update the modifier
            if self.currentObj.GetMg() != self.currentObjLastMg:
                # We tell to our Modifier something has change which will trigger the call of ModifyObject
                op.SetDirty(c4d.DIRTYFLAGS_DATA)
                return
      
            # Check if targetObj exist
            if self.targetObj:
                # Check if targetObj is still alive, and the Position we have store is changed.
                if self.targetObj.IsAlive() and self.targetObj.GetMg() != self.targetObjLastMg:
      
                    # We tell to our Modifier something has change which will trigger the call of ModifyObject
                    op.SetDirty(c4d.DIRTYFLAGS_DATA)
                    return
      
            return
      
      
        def ModifyObject(self, mod, doc, op, op_mg, mod_mg, lod, flags, thread) :
            if not mod[1000] or not mod[1001]:
                return True
      
            pts = op.GetAllPoints()
            self.currentObj = mod
            self.currentObjLastMg = mod.GetMg()
            self.targetObj = mod[1000]
      
            self.targetObjLastMg = self.targetObj.GetMg()
            targetGlobalPos = self.targetObjLastMg.off
      
            vex = mod[1001].GetAllHighlevelData()
            cnt = len(vex)
            for i in xrange(cnt) :
                if vex[i]:
                    currentGlobalPos = pts[i] * op.GetMg()
                    distancePosWeighted = (targetGlobalPos - currentGlobalPos) * vex[i]
                    finalLocalPos = pts[i] + distancePosWeighted
                    op.SetPoint(i, finalLocalPos)
                    
            op.Message(c4d.MSG_UPDATE)
            return True
    

    Another thing, please use [ code] and [ /code] when you post code on the forum which makes it easier to read :)

    If you have any questions, feel free to ask.
    Cheers,
    Maxime



  • On 27/06/2018 at 03:27, xxxxxxxx wrote:

    Thanks for your help, MaximeA!
    I'm glad you've helped me optimize the algorithm.
    I finally understand how to use CheckDirty(), but I have the same problem with "ctrl z" targert object. So I changed

    self.targetObj.IsAlive() and self.targetObj.GetMg() != self.targetObjLastMg:
    

    and changed "and" to "or". Should it be safe?
    I have another problem, that is, I'm going to write this plugin as this way of operation.
    A poly object has 3,000 points. I only want to deform 50 points. So there will be a vertex map. Suppose I store the index of the 50 points in the first setup. This guarantees that there is no need to judge 1000 times, directly through the point index to find point and then calculate. In theory this can speed up the calculation, I want to know if this is feasible, because it is going to read something stored. (I'm still confused about how to store this information, like Mesh defomer, set an Initialize button).



  • On 28/06/2018 at 02:24, xxxxxxxx wrote:

    Hi faxwang,

    If you still check for self.targetObj is not None (which will be the case for the first execution of the modifier) then it should be ok. Since None object doesn't have an IsAlive() function it will prompt an error in the console, so it's why you need to check, but after that is up to you to do whatever you want.

    Of course what you can do in ModifyObject is to get the DirtyCount of the vertexMap, so you will be able to know when a change happens to the map.

            tagMap = mod[1001]
            dirtyCnt = tagMap.GetDirty(c4d.DIRTYFLAGS_0)
            if dirtyCnt != self.previousDirtyCnt:
                self.previousDirtyCnt = dirtyCnt
                # Rebuild Your List
    

    If you really want to go to the button way, you can catch the user click as shown in the documentation.

    If you have any question, again feel free to ask!
    Cheers,
    Maxime



  • On 28/06/2018 at 06:18, xxxxxxxx wrote:

    😉Thank you for your help and patient explanation,MaximeA! It really helped me a great deal!


Log in to reply