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

    Questions about Bake Texture tag & Python

    Cinema 4D SDK
    python
    3
    11
    1.3k
    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.
    • ferdinandF
      ferdinand
      last edited by

      Hi,

      1. Not really in Python, since it is inside a context menu of an gadget within a description resource.
      2. You might want to check c4d.CheckIsRunning(c4d.CHECKISRUNNING_BAKING), but I am not sure if it does work for all scenarios of baking.

      Cheers
      zipit

      MAXON SDK Specialist
      developers.maxon.net

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

        @zipit said in Questions about Bake Texture tag & Python:

        c4d.CheckIsRunning(c4d.CHECKISRUNNING_BAKING)

        Hi,
        I tried with c4d.CheckIsRunning(c4d.CHECKISRUNNING_BAKING) but this always returning false.

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

          @zipit

          Hi,
          Since the c4d.CheckIsRunning(c4d.CHECKISRUNNING_BAKING) doesn't work, I'm trying to use an alternative method to check if baking is running.

          The problem is that the print() result work but the static text field (description resource) of my object dosen't change.

          Also the GetDEnabling() don't react to my custom CheckIsRunning condition or the CheckIsRunning condition doesn't send the change.

          see code below:

          def Init(self, op):
              self.PyCObject_id = None
              self.hide_bake_button = None
              self.hide_stop_bake_button = c4d.MYOBJECT_BAKETEXTURE_STOP
          
          def Message(self, node, type, data):
                  
              if type == c4d.MSG_DESCRIPTION_COMMAND: 
                  id = data['id'][0].id
                    
                  # My custom bake texture button   
                  if id == c4d.MYOBJECT_BAKETEXTURE_BAKE:
                      self.hide_bake_button = c4d.MYOBJECT_BAKETEXTURE_BAKE
          
                      # Bake texture function
                      self.BakeTexture(node, c4d.BAKETEXTURE_BAKE)
          
                  # My custom stop bake texture button 
                  if id == c4d.MYOBJECT_BAKETEXTURE_STOP:
                      self.hide_stop_bake_button = c4d.MYOBJECT_BAKETEXTURE_STOP
                      self.hide_bake_button = None
          
                      # Bake texture function
                      self.BakeTexture(node, c4d.BAKETEXTURE_STOP)
          
              # Check if bake texture is running (my custom CheckIsRunning condition)
              if type == 14:  
                  if data['type'] == 1001071:
                      pydata= data['data']            
                      pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
                      pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
                      PyCObject_id = pythonapi.PyCObject_AsVoidPtr(pydata)
                      
                      if self.PyCObject_id != PyCObject_id:
                          self.PyCObject_id = PyCObject_id
                          print("Bake texture is running")
                          
                          # issue with the following line
                          node[c4d.MYOBJECT_BAKETEXTURE_STATICTEXT_STATE] = "Bake texture is running" # STATICTEXT description resource
                          
                      else:
                          print("Bake texture is finished")
          
                          # issue with the following lines 
                          self.hide_bake_button = None
                          node[c4d.MYOBJECT_BAKETEXTURE_STATICTEXT_STATE] = "Bake texture is running" # STATICTEXT description resource
          
          
          def BakeTexture(self, op, event):
                  obj = op.GetDown()
          
                  tag = obj.GetTag(c4d.Tbaketexture)
          
                  tag[c4d.BAKETEXTURE_FORMAT] = c4d.FILTER_HDR        
                  tag[c4d.BAKETEXTURE_CHANNEL_REFLECTION] = True
          
                  c4d.CallButton(tag, event)
          
                  return tag
          
          def GetDEnabling(self, node, id, t_data, flags, itemdesc):
                  
              if id[0].id == self.hide_bake_button:
                  return False
          
              if id[0].id == self.hide_stop_bake_button:
                  return False
          
              return True
          
          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by ferdinand

            Hi,

            you can't assign a value to a STATICTEXT description element as it is a static element as the name implies 😉 You have either to use the STRING element (here you can just assign a value) or overwrite NodeData.GetDDescription() to modify your description (of your STATICTEXT) dynamically.

            Cannot say much about your GetDEnabling, since you are only checking some DescIDs there. I don't really get what is not working there?

            Cheers
            zipit

            MAXON SDK Specialist
            developers.maxon.net

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

              @zipit
              I tried with all types (float, string, bool..) and that not works, nothing happens.

              And about the GetDEnabling
              for example in the condition :

              if id == c4d.MYOBJECT_BAKETEXTURE_BAKE:
                    self.hide_bake_button = c4d.MYOBJECT_BAKETEXTURE_BAKE
              

              the GetDEnabling react and disable the bake button.

              but in CheckIsRunning condition the GetDEnabling don't react and re-enable my custom bake:

              if type == 14:  
                  if data['type'] == 1001071:
                      ...
                      if self.PyCObject_id != PyCObject_id:
                          self.PyCObject_id = PyCObject_id
                          ...
                      else:
                          self.hide_bake_button = None # <<< here the bake button is not re-enabled
              

              it is a bit complicated to explain the issue, if this is not clear I will try to create a full example and share it here.
              sorry, and thank you for your time.

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

                Problem solved by adding a global variable.

                # Global variable
                checkisrunning_baking = False
                   
                class MyClass(c4d.plugins.ObjectData):
                
                    def Init(self, op):
                        self.PyCObject_id = None
                        self.hide_bake_button = None
                        self.hide_stop_bake_button = c4d.HDRISG_BAKETEXTURE_STOP
                
                    def Message(self, node, type, data):
                        global checkisrunning_baking
                
                        if type == c4d.MSG_DESCRIPTION_COMMAND: 
                            id = data['id'][0].id
                          
                            # My custom bake texture button   
                            if id == c4d.MYOBJECT_BAKETEXTURE_BAKE:
                                # Bake texture function
                                self.BakeTexture(node, c4d.BAKETEXTURE_BAKE)
                
                            # My custom stop bake texture button 
                            if id == c4d.HDRISG_BAKETEXTURE_STOP:
                
                                # Bake texture function
                                self.BakeTexture(node, c4d.BAKETEXTURE_STOP)
                
                        # Check if bake texture is running
                        if type == 14:  
                            if data['type'] == 1001071:
                                pydata= data['data']            
                                pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
                                pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
                                PyCObject_id = pythonapi.PyCObject_AsVoidPtr(pydata)
                            
                                if self.PyCObject_id != PyCObject_id:
                                    self.PyCObject_id = PyCObject_id
                                    checkisrunning_baking = True
                                
                                else:
                                    checkisrunning_baking = False
                    
                    def GetVirtualObjects(self, op, hierarchyhelp):
                        global checkisrunning_baking
                
                        ...
                
                        self.hide_baketexture_bake = c4d.HDRISG_BAKETEXTURE_BAKE if checkisrunning_baking else None
                        self.hide_baketexture_stop = c4d.HDRISG_BAKETEXTURE_STOP if not checkisrunning_baking else None
                
                        baking_state = "Is running baking..." if checkisrunning_baking else ""
                        op[c4d.HDRISG_BAKETEXTURE_STATICTEXT] = baking_state
                
                        dirty = op.CheckCache(hierarchyhelp) or op.IsDirty(c4d.DIRTY_DATA)
                        if dirty is False: return op.GetCache(hierarchyhelp)
                
                    def BakeTexture(self, op, event):
                            obj = op.GetDown()
                
                            tag = obj.GetTag(c4d.Tbaketexture)
                
                            tag[c4d.BAKETEXTURE_FORMAT] = c4d.FILTER_HDR        
                            tag[c4d.BAKETEXTURE_CHANNEL_REFLECTION] = True
                
                            c4d.CallButton(tag, event)
                
                            return tag
                
                    def GetDEnabling(self, node, id, t_data, flags, itemdesc):
                        
                        if id[0].id == self.hide_bake_button:
                            return False
                
                        if id[0].id == self.hide_stop_bake_button:
                            return False
                
                1 Reply Last reply Reply Quote 0
                • M
                  m_adam
                  last edited by

                  Hi @mfersaoui, using the Bake Take is not the way to go to do texture baking programmatically. Since as you discovered you have no control over it. And as you execute CallButton it forces you to do the baking operation from the main thread (that's why CheckIsRunning is failing).

                  So the correct way is to use c4d.utils.BakeTexture, you can find an example in the github repository: py-texture_baker_r18.
                  The preview can be retrieved with the BAKE_TEX_PREVIEW flag.

                  If you have any questions, let me know.
                  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, Thank you I used py-texture_baker_r18 and I wanted to display an image preview inside the dialog, so I added a custom GUI to the dialog

                    bc = c4d.BaseContainer()
                    bc.SetBool(c4d.BITMAPBUTTON_BUTTON, False)
                    bc.SetLong(c4d.BITMAPBUTTON_BORDER, c4d.BORDER_THIN_IN)
                    self.myBitButton=self.AddCustomGui(self.BAKE_PREVIEW, c4d.CUSTOMGUI_BITMAPBUTTON, "", c4d.BFH_LEFT | c4d.BFV_TOP, 512, 256, bc)
                    

                    And from the CoreMessage() when the baking is finished I save the baked bitmap and then I set it as Image to my custom GUI Button

                    bmp.Save(self.filename, self.fileformat, c4d.BaseContainer(), c4d.SAVEBIT_ALPHA)
                    self.myBitButton.SetImage(self.filename, False)
                    

                    The problem is that my saved image is largest then the GUI button size. And I want to resize this image to fit my custom bitmap button, and without using an external python library.

                    Or is it possible to set the baked bitmap as image without saving it. and then resizing it to ensure that fit the bitmap button.

                    # this doesn't work
                    bmp = self.textureBakerThread.bakeBmp """ bmp = <Objet c4d.bitmaps.MultipassBitmap à 0x000000001BF75850>"""
                    self.myBitButton.SetImage(bmp, False)
                    

                    Here is the full example:

                    class TextureBakerThread(c4d.threading.C4DThread):
                    
                        def __init__(self, doc, textags, texuvws, destuvws):
                            ...
                    
                        def Begin(self):
                    
                            # Defines baking setting
                            bakeData = c4d.BaseContainer()
                            bakeData[c4d.BAKE_TEX_WIDTH] = 1024
                            bakeData[c4d.BAKE_TEX_HEIGHT] = 512
                            ...
                            self.bakeData = bakeData
                    
                            # Initializes bake process
                            bakeInfo = c4d.utils.InitBakeTexture(self.doc, self.textags, self.texuvws, self.destuvws, self.bakeData, self.Get())
                            self.bakeDoc = bakeInfo[0]
                            self.bakeError = bakeInfo[1]
                    
                            if self.bakeError != c4d.BAKE_TEX_ERR_NONE or self.bakeDoc is None:
                                return False
                    
                            # Starts bake thread
                            self.Start(c4d.THREADMODE_ASYNC, c4d.THREADPRIORITY_BELOW)
                    
                            return True
                    
                        def BakeTextureHook(self, info):
                            ...
                    
                        def Main(self):
                            ...
                    
                    class TextureBakerDlg(c4d.gui.GeDialog, TextureBakerHelper):
                        BUTTON_BAKE = 1000
                        BUTTON_ABORT = 1001
                        BAKE_PREVIEW = 1002
                    
                        aborted = False
                        textureBakerThread = None
                        infoText = None
                    
                        def CreateLayout(self):
                    
                            # Defines the title
                            self.SetTitle("Texture Baker")
                    
                            # Creates 2 buttons for Bake / Abort button
                            if self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, rows=1, title="", cols=2, groupflags=0):
                                self.AddButton(id=self.BUTTON_BAKE, flags=c4d.BFH_LEFT, initw=100, inith=25, name="Bake")
                                self.AddButton(id=self.BUTTON_ABORT, flags=c4d.BFH_LEFT, initw=100, inith=25, name="Abort")
                            self.GroupEnd()
                    
                            # Creates an image preview
                            bc = c4d.BaseContainer()
                            bc.SetBool(c4d.BITMAPBUTTON_BUTTON, False)
                            bc.SetLong(c4d.BITMAPBUTTON_BORDER, c4d.BORDER_THIN_IN)
                            self.myBitButton=self.AddCustomGui(self.BAKE_PREVIEW, c4d.CUSTOMGUI_BITMAPBUTTON, "", c4d.BFH_LEFT | c4d.BFV_TOP, 512, 256, bc)
                    
                            # Creates a statics text for the status
                            if self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, rows=1, title="", cols=1, groupflags=0):
                                self.infoText = self.AddStaticText(id=0, initw=0, inith=0, name="", borderstyle=0, flags=c4d.BFH_SCALEFIT)
                            self.GroupEnd()
                    
                            # Sets Button enable states so only bake button can be pressed
                            self.EnableButtons(False)
                    
                            return True
                    
                    
                        def CoreMessage(self, id, msg):
                            # Checks if texture baking has finished
                            if id == PLUGIN_ID:
                    
                                # Checks if texture baking has finished
                                if id == PLUGIN_ID:
                                    # Sets Button enable states so only bake button can be pressed
                                    self.EnableButtons(False)
                    
                                    # If not aborted, means the baking finished
                                    if not self.aborted:
                                        # Updates the information status
                                        self.SetString(self.infoText, str("Baking Finished"))
                    
                                        # Retrieves the baked bitmap
                                        bmp = self.textureBakerThread.bakeBmp
                                        if bmp is None:
                                            raise RuntimeError("Failed to retrieve the baked bitmap.")
                    
                                        # Displays the bitmap
                                        c4d.bitmaps.ShowBitmap(bmp)
                    
                                        # Save the bitmap
                                        bmp.Save(self.filename, self.fileformat, c4d.BaseContainer(), c4d.SAVEBIT_ALPHA)
                                    
                                        self.myBitButton.SetImage(self.filename, False)
                    
                                        # Removes the reference to the C4D Thread, so the memory used is free
                                        self.textureBakerThread = None
                                        return True
                                    else:
                                        # If baking is aborted, updates the information status
                                        self.SetString(self.infoText, str("Baking Aborted"))
                    
                                    return True
                            return c4d.gui.GeDialog.CoreMessage(self, id, msg)
                    
                    1 Reply Last reply Reply Quote 0
                    • ferdinandF
                      ferdinand
                      last edited by ferdinand

                      Hi,

                      BitmapButton.SetImage() works just fine. Here is an example on how to set a BitmapButton to a BaseBitmap that has been scaled to fit a target size.

                      import c4d
                      from c4d import bitmaps
                      
                      BUTTONIZE = 128
                          
                      class TextureBakerDlg(c4d.gui.GeDialog):
                      
                          def CreateLayout(self):
                      
                              # Creates an image preview
                              bc = c4d.BaseContainer()
                              bc.SetBool(c4d.BITMAPBUTTON_BUTTON, False)
                              bc.SetLong(c4d.BITMAPBUTTON_BORDER, c4d.BORDER_THIN_IN)
                              self.myBitButton=self.AddCustomGui(1000, c4d.CUSTOMGUI_BITMAPBUTTON, "", 
                                                                 c4d.BFH_LEFT | c4d.BFV_TOP,
                                                                 BUTTONIZE, BUTTONIZE,
                                                                 bc)
                              
                              # Set up two bitmaps, the source bitmap (it is just the maxon logo in the top 
                              # left corner of the forum) and a target sized empty bitmap                  
                              src_bmp = bitmaps.BaseBitmap()
                              src_bmp.InitWith(
                                  "https://developers.maxon.net/forum/assets/uploads/system/site-logo.png")
                              dst_bmp = bitmaps.BaseBitmap()
                              dst_bmp.Init(BUTTONIZE, BUTTONIZE)
                              
                              # Scale copy our source into the target.
                              src_bmp.ScaleIt(dst_bmp, 256, True, True)
                              
                              # Set your button.
                              self.myBitButton.SetImage(dst_bmp)
                      
                              return True
                      
                      def main():
                          dlg = TextureBakerDlg()
                          dlg.Open(c4d.DLG_TYPE_ASYNC)
                      
                      # Execute main()
                      if __name__=='__main__':
                          main()
                      

                      The fact that you do not see anything / that it 'does not work' for you is probably caused by the fact that you are passing a MultipassBitmap to your button. Check MultipassBitmap.GetLayers on how to access individual layers of BaseBitmaps in your MultipassBitmap which you could then hand to your BitmapButton.

                      Cheers
                      zipit

                      MAXON SDK Specialist
                      developers.maxon.net

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

                        Hi,
                        Thank you very much @zipit and have a good day.

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