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.
    • mfersaouiM
      mfersaoui
      last edited by r_gigante

      Hello,

      I have some questions concerning the Bake Texture tag:

      1 - Is there command that allow to open the bake preview window

      bake_texture_tag_open_win.jpg

      2 - Is it possible to detect when the bake render is finished

      I imagine that there is no way to display the small image preview inside description resource via python.

      Thank you.

      1 Reply Last reply Reply Quote 0
      • 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