Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    Issues Modifying Cloned Document

    Cinema 4D SDK
    python r21
    2
    3
    470
    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
      wuzelwazel
      last edited by s_bach

      Hello! I'm attempting to make Cinema 4D's FBX export a bit more robust for our pipeline. We're dealing with lots of instancing of non-polygonal objects which C4D seems to have trouble outputting to FBX. Specifically we're seeing issues with Symmetry, Cloners and Subdivision Surfaces.

      I wrote a script that worked well, but it would modify the current document and I felt it would be better to modify a clone of the document. In order to do that I built a class to handle the document preparation. Unfortunately, this seems to have broken something fundamental in the logic but I can't figure out why.

      The plugin is supposed to find all instanced subdivision surfaces, create a group null below the subdivision, point all instances that had previously referred to the sds to that null, and then place each of the instances into a new subdivision surface (so that the instance is now the cage mesh). This is the only way I can find to get instances and subdivision surfaces to work together in an FBX export. However, in it's new form the plugin seems to end up with the instances inside of two nulls instead of inside a single subdivision surface. In addition some of the instances and subdivision surfaces are switching locations in the hierarchy. It's a mess!

      Perhaps I've bitten off more than I can handle at the moment. Below is my full code. Any help with cleaning this up would be much appreciated!

      import c4d
      import c4d.utils
      import os
      import os.path
      
      blacklist = {"persp","top","side","front"}
      FBX_EXPORTER_ID = 1026370
      PLUGIN_ID = 1053631
      
      class ExportFBX():
          def __init__(self, doc, flags):
              if doc:
                  self.doc = doc.GetClone()
                  self.name = os.path.splitext(doc.GetDocumentName())[0]
              self.flags = flags
              self.status = False
      
          def __del__(self):
              if self.doc:
                  c4d.documents.KillDocument(self.doc)
      
          def _GetAllObjects(self, obj):
              while obj:
                  yield obj
                  for o in self._GetAllObjects(obj.GetDown()):
                      yield o
                  obj = obj.GetNext()
      
          def _UpdateName(self, obj):
              name = obj.GetName()
              if name in blacklist:
                  obj.SetName("{}_geo".format(name))
      
          def _UpdateAxis(self, obj):
              if obj:
                  null = c4d.BaseObject(c4d.Onull)
                  null.SetName("{}_grp".format(obj.GetName()))
                  self.doc.InsertObject(null)
                  null.InsertBefore(obj)
                  obj.InsertUnder(null)
                  return null
      
          def _UpdateSdsInstance(self, obj):
              sds = obj.GetReferenceObject(self.doc)
              parent = None
              child = sds.GetDown()
              pred = obj.GetPred()
              if not pred:
                  parent = obj.GetUp()
      
              obj.SetReferenceObject(child)
      
              new_sds = c4d.BaseObject(c4d.Osds)
              if sds.GetName().startswith("Subdivision"):
                  new_sds.SetName("{0}_subdivision".format(child.GetName()))
              else:
                  new_sds.SetName(sds.GetName())
      
              new_sds.SetData(sds.GetData())
              self.doc.InsertObject(new_sds, parent, pred, checknames=True)
              obj.InsertUnder(new_sds)
      
      
          def Prepare(self):
              if self.doc:
                  objs = list(self._GetAllObjects(self.doc.GetFirstObject()))
                  instances = [o for o in objs if o.IsInstanceOf(c4d.Oinstance)]
                  instance_sources = [i.GetReferenceObject(self.doc) for i in instances]
                  sds_list = [o for o in objs if o.IsInstanceOf(c4d.Osds) and o in instance_sources]
                  convert_editable = [o for o in objs if o.IsInstanceOf(c4d.Osymmetry) or o.IsInstanceOf(1018544)]
                  c4d.StopAllThreads()
                  c4d.utils.SendModelingCommand(c4d.MCOMMAND_MAKEEDITABLE, convert_editable, doc=self.doc, flags=c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)
                  _ = [self._UpdateName(o) for o in objs]
                  _ = [self._UpdateAxis(sds.GetDown()) for sds in sds_list]
                  _ = [self._UpdateSdsInstance(i) for sds in sds_list for i in instances if i.GetReferenceObject(self.doc) == sds]
      
          def Export(self):
              if self.doc:
                  self.status = c4d.documents.SaveDocument(self.doc,
                                  os.path.join(self.doc.GetDocumentPath(), self.name),
                                  self.flags,
                                  FBX_EXPORTER_ID)
                                  
          def GetStatus(self):
              return self.status
      
      
      class ExportFBXCommandData(c4d.plugins.CommandData):
          def Execute(self, doc):
              flags = c4d.SAVEDOCUMENTFLAGS_EXPORTDIALOG|c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST|c4d.SAVEDOCUMENTFLAGS_DIALOGSALLOWED|c4d.SAVEDOCUMENTFLAGS_SAVEAS
      
              fbx_export = ExportFBX(doc, flags)
      
              fbx_export.Prepare()
              fbx_export.Export()
              
              return fbx_export.GetStatus()
              
      
      # Execute main()
      if __name__=='__main__':
          directory, _ = os.path.split(__file__)
          fn = os.path.join(directory, "res", "export_fbx.tif")
      
          bmp = c4d.bitmaps.BaseBitmap()
          if bmp is None:
              raise MemoryError("Failed to create a BaseBitmap")
      
          if bmp.InitWith(fn)[0] != c4d.IMAGERESULT_OK:
              raise MemoryError("Failed to initialize a BaseBitmap")  
      
          c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                              str="Export FBX...",
                                              help="An FBX export with enhanced support for instances.",
                                              info=0,
                                              dat=ExportFBXCommandData(),
                                              icon=bmp)
      
      1 Reply Last reply Reply Quote 0
      • W
        wuzelwazel
        last edited by

        Just wanted to provide an update here.

        I stand corrected, the above plugin creates an FBX that works perfectly when imported into Maya. It appears that Cinema 4D isn't able to understand what's going on in the FBX and I was checking the export by importing into Cinema 4D.

        I suppose the lesson here is to follow the actual pipeline when testing ☺

        ...and the other lesson is that Cinema's FBX export and import are not to be trusted ☠

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

          Hello,

          Really sorry about this issue.

          Would it be possible to send us a scene and some screenshot maybe to reproduce the behaviour ? That would be really appreciate. I will send that to our devs.

          You can use our mailbox [email protected]

          Thanks and cheers,
          Manuel

          MAXON SDK Specialist

          MAXON Registered Developer

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