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

    Bake Texture within ObjectData

    Cinema 4D SDK
    3
    13
    1.5k
    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.
    • mfersaouiM
      mfersaoui @ferdinand
      last edited by m_adam

      @zipit
      Hi,
      I have another question.
      When I use the op.GetCache().GetDown() I can access to my sphere object but when I bake the object texture this returning a black image (I'm baking the reflection channel).

      op = doc.GetActiveObject()
      
      obj = op.GetCache().GetDown()
      
      if obj is None:
          return
      
      # Retrieves texture and UVW tags from the selected object
      uvwTag = obj.GetTag(c4d.Tuvw)
      
      if uvwTag is None:
          self.SetString(self.infoText, "Bake Init Failed: No uv tag found")
          return
      
      tags = obj.GetTags()
      textags, texuvws, destuvws = [], [], []
      
      for tag in tags:
          if tag.CheckType(c4d.Ttexture):
              textags.append(tag)
              texuvws.append(uvwTag)
              destuvws.append(uvwTag)
      
      self.textureBakerThread = TextureBakerThread(tempDoc, textags, texuvws, destuvws, bd)
      

      But if I clone the sphere object and I copy it then inside a new temp document, the bake texture works.

      op = doc.GetActiveObject()
      
      obj = op.GetCache().GetDown().GetClone()
      
      if obj is None:
          return
              
      # Create a temporary document to compute the cache of the tracer
      objClone = obj.GetClone()
      
      tempDoc = c4d.documents.BaseDocument()
      tempDoc.InsertObject(objClone)
      
      # Retrieves texture and UVW tags from the selected object
      uvwTag = objClone.GetTag(c4d.Tuvw)
      
      if uvwTag is None:
          self.SetString(self.infoText, "Bake Init Failed: No uv tag found")
          return
      
      tags = objClone.GetTags()
      textags, texuvws, destuvws = [], [], []
      
      for tag in tags:
          if tag.CheckType(c4d.Ttexture):
              textags.append(tag)
              texuvws.append(uvwTag)
              destuvws.append(uvwTag)
      
      self.textureBakerThread = TextureBakerThread(tempDoc, textags, texuvws, destuvws, bd)
      

      How I can bake texture in the current document?
      Thank you.

      1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand
        last edited by ferdinand

        Hi,

        your cache is not part of the document, it is the cache of an object in the document. You have to either add the cache to a new document or just use the object you did get the cache from for your baking process (I am a bit rusty when it comes to functionalities of the main app, but I think you can also bake parametric objects - i.e. polygon objects that are not editable).

        obj = op.GetCache().GetDown().GetClone()
        
        if obj is None:
            return
        

        This is a bit nonsensical. Both GetCache() and GetDown() can return None, but the method you are actually testing, GetClone(), cannot. So this will raise an exception when there is no cache, but obj will always be not None in all other cases.

        Cheers
        zipiz

        MAXON SDK Specialist
        developers.maxon.net

        mfersaouiM 1 Reply Last reply Reply Quote 1
        • mfersaouiM
          mfersaoui @ferdinand
          last edited by mfersaoui

          @zipit
          Hi,
          I cloned the sphere in the current document and after the baking finished i remove it . I must to bake my texture in the current document because I want to bake the reflection channel of my texture (the reflect of the curent scene on my object).

          I have used the following solution, but I don't know how to bake parametric objects (I did some research but I haven't found anything).

          def Bake(self, bd):
              # Retrieves selected document
              doc = c4d.documents.GetActiveDocument()
              if doc is None:
                  return
                  
              # Retrieves selected objects
              op = doc.GetActiveObject()
          
              if op is None:
                  self.SetString(self.infoText, "Bake Init Failed: ...")
                  return    
          
              obj = op.GetCache().GetDown().GetClone()
          
              doc.InsertObject(obj)
              obj.ChangeNBit(c4d.NBIT_OHIDE, c4d.NBITCONTROL_SET)
             
              # Retrieves texture and UVW tags from the selected object
              uvwTag = obj.GetTag(c4d.Tuvw)
          
              if uvwTag is None:
                  self.SetString(self.infoText, "Bake Init Failed: No uv tag found")
                  return
          
              tags = obj.GetTags()
              textags, texuvws, destuvws = [], [], []
              for tag in tags:
                  if tag.CheckType(c4d.Ttexture):
                      textags.append(tag)
                      texuvws.append(uvwTag)
                      destuvws.append(uvwTag)
          
              # Initializes and start texture baker thread
              self.aborted = False
          
              self.textureBakerThread = TextureBakerThread(doc, textags, texuvws, destuvws, bd)
              
              self.obj = obj
              ...
          
          def CoreMessage(self, id, msg):
              # Checks if texture baking has finished
              if id == PLUGIN_ID:
          
                  # If not aborted, means the baking finished
                  if not self.aborted:
                      self.obj.Remove()
                      c4d.EventAdd()
                      return True
                          
                  ...
          
                  return True
          
              return c4d.gui.GeDialog.CoreMessage(self, id, msg)
          
          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by

            Hi,

            you have to either use a temporary document:

            cache = op.GetCache()
            if not cache:
                return
                
            cache = cache.GetDown().GetClone() if cache.GetDown() else None
            if not cache:
                return 
                
            temp_doc = c4d.BaseDocument()
            temp_doc.InsertObject(cache)
            # ...
            bake_init = c4d.utils.InitBakeTexture(*my_setup)
            print bake_init
            bake_status = c4d.utils.BakeTexture(temp_doc, my_data, my_bitmap, 
                                                my_thread, my_callback)
            print bake_status
            temp_doc.Flush() # You need to free the document or it will remain in memory
            

            or tell c4d that the document has been updated before you bake it. I would go for a temporary document.

            I am also not sure what you mean by "I do not know how to bake a parametric object". Just pass the node you did execute GetCache() on, op in this case. However, I cannot stress this enough, my knowledge of Cinema's app functionalities is not the best anymore. I DO NOT KNOW FOR SURE IF THIS IS SUPPORTED. So you should consult the docs on that.

            Cheers
            zipit

            MAXON SDK Specialist
            developers.maxon.net

            mfersaouiM 1 Reply Last reply Reply Quote 2
            • mfersaouiM
              mfersaoui @ferdinand
              last edited by

              @zipit said in Bake Texture within ObjectData:

              tell c4d that the document has been updated

              Hi,
              If I go for a temporary document, I must to copy all objects of the current doc (scene) to the temp doc. In my situation I want to bake only the reflection channel of my texture, if there only the cloned object "op.GetCache().GetDown().GetClone()", there no thing to reflecte on my texture reflection.

              # Bake only reflection
              bakeData[c4d.BAKE_TEX_REFLECTION] = True
              

              For that reason I get a black image in the bake texture result.

              Regards,
              Mustapha

              1 Reply Last reply Reply Quote 0
              • ferdinandF
                ferdinand
                last edited by

                Hi,

                I do not really understand what you question is. You can copy a document with c4d.C4DAtom.GetClone(), BaseDocument is derived from C4DAtom.

                Cheers
                zipit

                MAXON SDK Specialist
                developers.maxon.net

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

                  Hi @mfersaoui, may I ask you in which context are you?

                  And do you try to bake the things?
                  Because if it's a button into an ObjectData, the message since it's sent from the GUI, is sent from the MainThread.

                  Cheers,
                  Maxime.

                  MAXON SDK Specialist

                  Development Blog, MAXON Registered Developer

                  mfersaouiM 1 Reply Last reply Reply Quote 0
                  • mfersaouiM
                    mfersaoui @m_adam
                    last edited by mfersaoui

                    Hi @m_adam,
                    I have a first button on my ObjectData that call my Bake Texture CommandData plugin (I'm using this example: py-texture_baker_r18.), and then from the CommandData GUI I run the bake texture process to bake the reflection channel of the sphere object texture.

                    bake_texture_temp_doc.jpg

                    1 Reply Last reply Reply Quote 0
                    • ferdinandF
                      ferdinand
                      last edited by

                      Hi,

                      I am still confused on what you actual question is. When you want to render out the reflection channel, then you obviously have to copy the geometry too. You can copy the whole document as described above.

                      However, like @m_adam pointed out, when your code happens in NodeData.Message() you are in the main thread, so you could use an event to just update your document after you have inserted your cache.

                      # Snippet from your code above
                      doc.InsertObject(obj)
                      c4d.EventAdd()
                      

                      Cheers
                      zipit

                      MAXON SDK Specialist
                      developers.maxon.net

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

                        I guess his issue is that all his stuff is under a virtual document.

                        But since you react to a button click you are in the main thread.
                        So you can retrieve a copy of the cache of your current generator, (Don't forget to call StopAllThread) insert it into the current document, run the baking process, delete everything, that's it 🙂

                        Cheers,
                        Maxime.

                        MAXON SDK Specialist

                        Development Blog, MAXON Registered Developer

                        mfersaouiM 1 Reply Last reply Reply Quote 0
                        • mfersaouiM
                          mfersaoui @m_adam
                          last edited by mfersaoui

                          @m_adam
                          Hi,
                          Yes, it's the method that I'm using, but I don't know if this allowed or no. I explain it above in my second message.

                          And response to @zipit about "I do not know how to bake a parametric object" I mean: I do not know how to bake texture of an object (sphere) without make it editable.

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

                            @mfersaoui Yes it's safe.

                            Find an example below, that does what I described previously:

                            class BakeObject(c4d.plugins.ObjectData):
                                """BakeObject Generator"""
                            
                                def __init__(self, *args):
                                    super(BakeObject, self).__init__(*args)
                                    self.SetOptimizeCache(True)
                            
                            
                                def GetVirtualObjects(self, op, hierarchyhelp):
                                    """
                                    This method is called automatically when Cinema 4D ask for the cache of an object. This is also the place
                                    where objects have to be marked as input object by Touching them (destroy their cache in order to disable them in Viewport)
                                    :param op: The Python Generator
                                    :type op: c4d.BaseObject.
                                    :param hh: The hierarchy helper.
                                    :type hh: c4d.HierarchyHelp (currently a PyObject).
                                    :return: The Representing object (c4d.LineObject or SplineObject)
                                    """
                                    sphere = c4d.BaseObject(c4d.Osphere)
                                    sphere[c4d.PRIM_SPHERE_SUB] = 48
                                    sphere.MakeTag(c4d.Tphong)
                            
                                    return sphere
                            
                                def Message(self, node, msgId, data):
                                    """
                                    Called by Cinema 4D part to notify the object to a special event
                                    :param node: The instance of the ObjectData.
                                    :type node: c4d.BaseObject
                                    :param msgId: The message ID type.
                                    :type msgId: int
                                    :param data: The message data.
                                    :type data: Any, depends of the message passed.
                                    :return: Depends of the message type, most of the time True.
                                    """
                            
                                    if msgId==c4d.MSG_DESCRIPTION_COMMAND:
                                        if data['id'][0].id==1006:
                                            if node.GetCache() is None:
                                                return True
                            
                                            # Make sure no other thread are running
                                            c4d.StopAllThreads()
                            
                                            # Retrieves a clone of the current object's cache.
                                            cacheClone = node.GetCache().GetClone()
                            
                            
                                            # Insert it into the current doc
                                            node.GetDocument().InsertObject(cacheClone)
                            
                                            # Performs a Current State to Object to retrieve a polygonObject.
                                            resultCSTO = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[cacheClone], doc=node.GetDocument())
                                            if not isinstance(resultCSTO, list) or not resultCSTO:
                                                cacheClone.Remove()
                                                raise RuntimeError("Failed to perform MCOMMAND_CURRENTSTATETOOBJECT.")
                                            
                                            polygonizedCache = None
                            
                                            if resultCSTO[0].CheckType(c4d.Opolygon):
                                                polygonizedCache = resultCSTO[0]
                            
                                            # If the results is a Null, performs a Join command to retrieve only one object.
                                            elif resultCSTO[0].CheckType(c4d.Onull):
                                                resultJoin = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_JOIN, list=[resultCSTO[0]], doc=node.GetDocument())
                                                if not isinstance(resultJoin, list) or not resultJoin:
                                                    cacheClone.Remove()
                                                    for obj in resultCSTO:
                                                        obj.Remove()
                                                    raise RuntimeError("Failed to perform MCOMMAND_JOIN.")
                            
                                                polygonizedCache = resultJoin[0]
                            
                                            # Remove the cached clone of our Generator from the document since we get the poligonalized version of it
                                            cacheClone.Remove()
                            
                                            if polygonizedCache is None:
                                                return True
                            
                                            # Now that we have a PolygonObject we can perform our baking
                                            # First we need a glossy material, so lets create it
                                            glossyMat = c4d.Material()
                            
                                            # Disables teh color channel
                                            glossyMat[c4d.MATERIAL_USE_COLOR] = False
                            
                                            # Removes the default specular layer
                                            glossyMat.RemoveReflectionLayerIndex(0)
                            
                                            # Adds a layer
                                            layer = glossyMat.AddReflectionLayer()
                            
                                            # Sets the Layer to GGX mode
                                            glossyMat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_DISTRIBUTION] = c4d.REFLECTION_DISTRIBUTION_GGX
                            
                                            # Defines the Roughness float value
                                            glossyMat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_VALUE_ROUGHNESS] = 0.0
                            
                                            # Defines the Reflection float value
                                            glossyMat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_VALUE_REFLECTION] = 1.0
                            
                                            # Inserts glossy mat and the polygonized object into the document
                                            node.GetDocument().InsertMaterial(glossyMat)
                                            node.GetDocument().InsertObject(polygonizedCache)
                            
                                            # Assigns the glossy Mat to the Polygonized Object
                                            textureTag = polygonizedCache.MakeTag(c4d.Ttexture)
                                            textureTag[c4d.TEXTURETAG_MATERIAL] = glossyMat
                                            
                                            # Now we can start the bake process
                                            bakeData = c4d.BaseContainer()
                                            bakeData[c4d.BAKE_TEX_WIDTH] = 512
                                            bakeData[c4d.BAKE_TEX_HEIGHT] = 512
                            
                                            bakeData[c4d.BAKE_TEX_USE_PHONG_TAG] = True
                                            bakeData[c4d.BAKE_TEX_CONTINUE_UV] = True
                            
                                            bakeData[c4d.BAKE_TEX_COLORPROFILE] = c4d.bitmaps.ColorProfile.GetDefaultLinearRGB()
                                            bakeData[c4d.BAKE_TEX_FILL_COLOR] = c4d.Vector(0.0)
                                            bakeData[c4d.BAKE_TEX_PIXELBORDER] = 12
                                            bakeData[c4d.BAKE_TEX_REFLECTION] = True
                            
                                            bakeData[c4d.BAKE_TEX_UV_LEFT] = 0.0
                                            bakeData[c4d.BAKE_TEX_UV_RIGHT] = 1.0
                                            bakeData[c4d.BAKE_TEX_UV_TOP] = 0.0
                                            bakeData[c4d.BAKE_TEX_UV_BOTTOM] = 1.0
                            
                                            # Initialize the Baking
                                            bakeInfo = c4d.utils.InitBakeTexture(node.GetDocument(), textureTag, polygonizedCache.GetTag(c4d.Tuvw), polygonizedCache.GetTag(c4d.Tuvw), bakeData)
                                            bakeDoc = bakeInfo[0]
                                            bakeStatus = bakeInfo[1]
                                            if bakeStatus != c4d.BAKE_TEX_ERR_NONE or bakeDoc is None:
                                                polygonizedCache.Remove()
                                                glossyMat.Remove()
                                                return True
                            
                                            # Bake as a 32bit
                                            bakeBmp = c4d.bitmaps.MultipassBitmap(512, 512, c4d.COLORMODE_RGBf)
                                            bakeStatus = c4d.utils.BakeTexture(bakeDoc, bakeData, bakeBmp, c4d.threading.GeGetCurrentThread(), self.BakeTextureHook)
                            
                                            if bakeStatus != c4d.BAKE_TEX_ERR_NONE:
                                                polygonizedCache.Remove()
                                                glossyMat.Remove()
                                                return True
                            
                                            # Dispay the baking result
                                            c4d.bitmaps.ShowBitmap(bakeBmp)
                            
                                            # Cleanup temp stuff
                                            polygonizedCache.Remove()
                                            glossyMat.Remove()
                            
                                            return True
                                    return True
                            
                                def BakeTextureHook(self, info):
                                    # Texture Baker hook, currently not used
                                    # print info
                                    pass
                            

                            Cheers,
                            Maxime.

                            MAXON SDK Specialist

                            Development Blog, MAXON Registered Developer

                            mfersaouiM 1 Reply Last reply Reply Quote 1
                            • mfersaouiM
                              mfersaoui @m_adam
                              last edited by mfersaoui

                              @m_adam said in Bake Texture within ObjectData:

                              bakeBmp = c4d.bitmaps.MultipassBitmap(512, 512, c4d.COLORMODE_RGBf)

                              This example helped me a lot. Thank you so much.

                              Regards,
                              Mustapha

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