Bake Texture within ObjectData



  • 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



  • @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



  • 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



  • 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.



  • 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



  • 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



  • 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.



  • @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.



  • @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.



  • @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