Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Modify rotation of clone child objects

    Cinema 4D SDK
    4
    5
    887
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • W
      will_blizzard
      last edited by will_blizzard

      Hi there,

      Sorry if this has been asked and answered before, but I've been searching in vain for days for a solution and can't figure it out.

      I'm trying to write a python effector which will mimic the target effector, but which will allow me to separate specifically the heading and pitch onto two separate child objects of a clone.

      The use case is to be able to clone 3D models of moving lights (where the arm assembly rotates( heading) and has a rotating (pitch) head attached to it) and use a target effector-like system to have the models follow a null. The clones are set up as follows:

      Null Parent (The fixture root)
      ---Fixture base geometry (this is the part of the fixture that doesn't move)
      ---Null (The fixture arms, should react to heading)
      ---Arm geometry
      ---Null (The fixture head, should react to pitch)
      ---Head geometry and light

      Screenshot 2022-05-18 001315.png
      I've tried every iteration of constraint and protection tags I can think of, and also have a python effector which modifies ALL of the clones children to follow the target, but does not modify each individual clone's children individually (as the target effector would).

      The python effector script I've written is below:

      from typing import Union
      import c4d
      from c4d.modules import mograph as mo
      from c4d import utils
      
      op: c4d.BaseObject # The python effector
      
      gen: c4d.BaseObject # The MoGraph Generator executing the effector
      doc: c4d.documents.BaseDocument # The document evaluating this effector
      thread: c4d.threading.BaseThread # The thread executing this effector
      
      
      def SetTarget (objMx, target):
          pos2 = target[c4d.ID_BASEOBJECT_REL_POSITION]
          pos1 = objMx.off
          vec3=(pos2-pos1).GetNormalized()
          vec2=vec3.Cross(c4d.Vector(0,1,0)).GetNormalized()
          vec1=vec3.Cross(c4d.Vector(1,0,0)).GetNormalized()
          newMx = c4d.Matrix(pos1,vec1,vec2,vec3)
          newRot = c4d.utils.MatrixToHPB(newMx)
          # print(newRot)
          #obj.SetMl(new_mx)
          return newRot
      
      def main() -> Union[c4d.Vector, float, int]:
          
          target = doc.SearchObject("TargetNull")
          if (target == None): return False
      
          moData = mo.GeGetMoData(op)
          gen = moData.GetGenerator()
          cnt = moData.GetCount()
          cntArray = moData.GetArrayCount()
          marr = moData.GetArray(c4d.MODATA_MATRIX)
          clarr = moData.GetArray(c4d.MODATA_CLONE)
          fixt = gen.GetDown()
          base = fixt.GetDown()
          yoke = base.GetDown()
          head = yoke.GetDown()
      
          for i in range(cnt):
              newRot = SetTarget(marr[i], target)
              head.SetRelRot(c4d.Vector(0,newRot.y,0))
              yoke.SetRelRot(c4d.Vector(newRot.x,0,0))
      
          #moData.SetArray(c4d.MODATA_MATRIX, marr, False)
          c4d.EventAdd()
          return True
      

      I can provide the c4d file as well if necessary, but hopefully what i've noted above makes sense.

      Thanks in advance for the help.
      Will

      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        hi,

        First, we have a bug with the python effector, it is not working when you render to pictures viewer.

        If i correctly understood the question:
        i don't think this is doable with one single cloner. The clones cannot have different rotation for a child object. Otherwise, they would not be clone anymore.

        One solution that come to my mind would be to use two cloners, one for the arm, the other for the head. Using an Inherit effector, the head could inherit from the rotation of the arm, and you would be free to add another effector to this head to add rotation.

        lights.c4d

        But that will not solve the problem if you want to follow a target or different targets. The solution also depend on what are exactly your needs. In this forum we try to focus on programming questions, you are a step before that.

        Cheers,
        Manuel

        MAXON SDK Specialist

        MAXON Registered Developer

        W 1 Reply Last reply Reply Quote 0
        • W
          will_blizzard @Manuel
          last edited by

          @m_magalhaes

          Hi there,

          Well, I figured it out, and have no issue rendering to picture viewer with python effector, so not sure what you're referring to, but maybe the bug is fixed?

          Here is the code that works as intended, although it requires a frame update to change. I'm guessing I can fix that as well with a bit more tinkering. This works as intended with the cloner in either instance or render instance mode.

          from typing import Union
          import c4d
          from c4d.modules import mograph as mo
          from c4d import utils
          
          op: c4d.BaseObject # The python effector
          
          gen: c4d.BaseObject # The MoGraph Generator executing the effector
          doc: c4d.documents.BaseDocument # The document evaluating this effector
          thread: c4d.threading.BaseThread # The thread executing this effector
          
          
          def SetTarget (objMx, target):
              pos2 = target[c4d.ID_BASEOBJECT_REL_POSITION]
              pos1 = objMx.off
          
              vec3=(pos2-pos1).GetNormalized()
              vec2=vec3.Cross(c4d.Vector(0,1,0)).GetNormalized()
              vec1=vec3.Cross(c4d.Vector(1,0,0)).GetNormalized()
              newMx = c4d.Matrix(pos1,vec1,vec2,vec3)
              newRot = c4d.utils.MatrixToHPB(newMx)
              return newRot
          
          def main() -> Union[c4d.Vector, float, int]:
              # Called when the effector is executed to set MoGraph data.
              target = doc.SearchObject("TargetNull")
              if (target == None): return False
          
              moData = c4d.modules.mograph.GeGetMoData(gen)
              marr = moData.GetArray(c4d.MODATA_MATRIX)
          
              cloneSource = gen.GetCache().GetDown()
              clones = []
          
              while cloneSource != None:
                  clones.append(cloneSource)
                  cloneSource = cloneSource.GetNext()
          
              cnt = len(clones)
          
              frame = doc.GetTime().GetFrame(doc.GetFps())
              for i in range(cnt):
                  fixt = clones[i]
                  base = fixt.GetDown()
                  yoke = base.GetDown()
                  head = yoke.GetDown()
          
                  newRot = SetTarget(marr[i], target)
                  head.SetRelRot(c4d.Vector(0,newRot.y,0))
                  yoke.SetRelRot(c4d.Vector(newRot.x,0,0))
          
              moData.SetArray(c4d.MODATA_MATRIX, marr, False)
              c4d.EventAdd()
              return True
          
          CairynC 1 Reply Last reply Reply Quote 0
          • CairynC
            Cairyn @will_blizzard
            last edited by

            @will_blizzard said in Modify rotation of clone child objects:

            have no issue rendering to picture viewer with python effector, so not sure what you're referring to

            The error is in the function moData.GetFalloffs(), which you are not using, so you are not affected I guess.

            1 Reply Last reply Reply Quote 0
            • M
              m_adam
              last edited by

              Hello @will_blizzard,

              without further questions or postings, we will consider this topic as solved by Wednesday 31/05/2023 and flag it accordingly.

              Thank you for your understanding,
              Maxime.

              MAXON SDK Specialist

              Development Blog, MAXON Registered Developer

              1 Reply Last reply Reply Quote 0
              • First post
                Last post