Questions about Bake Texture tag & Python
-
Hello,
I have some questions concerning the Bake Texture tag:
1 - Is there command that allow to open the bake preview window
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.
-
Hi,
- Not really in Python, since it is inside a context menu of an gadget within a description resource.
- 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 -
@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. -
@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
-
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 theSTRING
element (here you can just assign a value) or overwriteNodeData.GetDDescription()
to modify your description (of yourSTATICTEXT
) dynamically.Cannot say much about your
GetDEnabling
, since you are only checking someDescIDs
there. I don't really get what is not working there?Cheers
zipit -
@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. -
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
-
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. -
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)
-
Hi,
BitmapButton.SetImage()
works just fine. Here is an example on how to set aBitmapButton
to aBaseBitmap
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. CheckMultipassBitmap.GetLayers
on how to access individual layers ofBaseBitmaps
in yourMultipassBitmap
which you could then hand to yourBitmapButton
.Cheers
zipit -
Hi,
Thank you very much @zipit and have a good day.