GetAllTextures from materials only



  • Hi all,

    Following this post: https://plugincafe.maxon.net/topic/10645/14093_getalltextures-not-working

    Where if we want to get the textures from specific objects (in my case just the material objects), you need to add them to an AtomArray. Unfortunately, I cannot understand how to append this list to it, so I can can pass it to GetAlltextures. So I'm missing something here.

    BaseDocument.GetAllTextures(isNet=True, ar=None)
    ar (List[c4d.C4DAtom]) – An atom array to get the textures for. If None (default), all used textures in the document will be returned.

    Thank you in advance! 😃

    Andre



  • Hi,

    AtomArrays are soley (although sometimes mentioned in the Python docs) a C++ thing. C4d expects you to pass a list of type symbols for ar, which will define the filter for the objects that will be returned.

    I never used this method, but something like the following should do what you want. But you might have to fine tune the type symbols, depending on what you want to do.

    my_types = [c4d.Mmaterial, c4d.Xbase]
    tex_filenames = my_document.GetAllTextures(ar=my_types)
    

    Cheers
    zipit



  • Hi @zipit ,

    Cheers for your help! ☺

    @zipit said in GetAllTextures from materials only:

    AtomArrays are soley (although sometimes mentioned in the Python docs) a C++ thing.

    Thank you for clarifying! I was suspecting that it may be the case.

    It gives me the following TypeError:
    BaseDocument.GetAllTextures expected c4d.C4DAtom, not int

    Does it work fine on your end?

    I mean I can get all textures per material but it would take longer to process.

    Thanks again! :)

    Andre



  • Hi,

    oh, then you have actually to pass the types not the smybols.

    my_types = [c4d.BaseMaterial, c4d.BaseShader]
    

    Cheers
    zipit



  • Hi,

    @zipit said in GetAllTextures from materials only:

    oh, then you have actually to pass the types not the smybols.
    my_types = [c4d.BaseMaterial, c4d.BaseShader]

    Yes, I tried that as well before, it still looks for c4d.C4DAtom 😄
    It's a weird one, but like you said it may only work with C++. I can't see what objects to pass if types or symbols don't work.

    That's ok! I appreciate your time and help with this! 👍

    Andre



  • Hi,

    sorry for all the confusion. You have to pass actual instances of objects. The following code does what you want (and this time I actually tried it myself ;)).

    import c4d
    
    def main():
        """
        """
        bc = doc.GetAllTextures(ar=doc.GetMaterials())
        for cid, value in bc:
            print cid, value
    
    if __name__=='__main__':
       main()
    

    Cheers,
    zipit



  • Hi @zipit ,

    No need to apologise! ☺
    Thank you for figuring it out! It's actually clear, now that you explained.

    Do you have access to other render engines? Just to confirm I'm not being stupid (again 😄). It seems to return a list with texture paths from only Cinema materials.

    As a summary:

    • If I do not pass the Object Instances to doc.GetAllTextures() I will have a basecontainer with all of the textures paths from every scene object including materials that are Cinema and other type.
    • If we pass specific Object Instances list doc.GetAllTextures(ar=doc.GetMaterials()) I will have a basecontainer with all of the texture paths from Cinema materials.

    If this is correct it's a great workflow if only using Cinema materials, but rest not as much, still need to filter a lot of stuff out.

    Either way, you answer my questions!

    Thank you very much once again! 😃

    Andre



  • Hi,

    no, I do not have any external render engines here. But you can filter stuff, you just have to compose ar of objects you want to include.

    my_filter = [obj for obj in doc.GetMaterials()
                 if obj.CheckType(c4d.Mterrain)]
    for _, path in doc.GetAllTextures(ar=my_filter):
        print path, "is a texture path in a terrain material."
    

    You can throw everything that is a c4d.C4DAtom into ar. You could try some of the BaseObjects for example that have a texture path.

    For external renderer materials: have you confirmed that they are actually included in doc.GetMaterials()?

    Also writing a little script, that extracts all bitmap path attributes from a GeListNode (i.e. a shader tree) tree is not too hard either. I think someone asked a similar question in combination with Octane just recently.

    Cheers
    zipit



  • Hi,

    @zipit said in GetAllTextures from materials only:

    Hi,

    no, I do not have any external render engines here. But you can filter stuff, you just have to compose ar of objects you want to include.

    my_filter = [obj for obj in doc.GetMaterials()
                 if obj.CheckType(c4d.Mterrain)]
    for _, path in doc.GetAllTextures(ar=my_filter):
        print path, "is a texture path in a terrain material."
    

    You can throw everything that is a c4d.C4DAtom into ar. You could try some of the BaseObjects for example that have a texture path.

    That's a great example! Thank you!

    For external renderer materials: have you confirmed that they are actually included in doc.GetMaterials()?

    Yep, I've tried it and can confirm that the materials are included. Following your example:

    OCTANE_MAT_ID = 1029501
    
    my_filter = [obj for obj in doc.GetMaterials()
                 if obj.CheckType(OCTANE_MAT_ID)]
    
    for _, path in doc.GetAllTextures(ar=my_filter):
        print path, "is a texture path in an Octane material."
    

    Does not print anything.

    Also writing a little script, that extracts all bitmap path attributes from a GeListNode (i.e. a shader tree) tree is not too hard either. I think someone asked a similar question in combination with Octane just recently.

    It may have been me! I do have the script but was curious to understand the GetAllTextures function, which you explained to me really well.

    Thanks again!



  • Hi,

    the function is most likely just looking for c4d.Xbitmap nodes (the shader type cinema uses to wrap around a texture file). If Octane does use its own bitmap shader, the function will not work.

    Cheers
    zipit



  • Just to add some information GetAllTexture call the message MSG_GETALLASSETS to all passed BaseList2D.

    So even 3rd party BaseList2D are supported as long as the 3rd party developer supported MSG_GETALLASSETS.

    Cheers,
    Maxime.



  • Hi @m_adam,

    Thanks for letting me know! 😃

    Andre


Log in to reply