Get shader's parent ID



  • Hi all,

    Is it possible to get the parent ID of a shader?
    For example have a image texture and want to know if is in the diffuse or opacity channel, etc?

    Cheers! ☺

    Andre





  • Hey,

    if I do understand your initial question correctly the linked post does not contain your answer. While both BaseShaders and BaseMaterials are GeListNodes only BaseShaders that are attached to each other (a noise shader in a fusion shader for example) are in child - parent relationship. BaseMaterials do not carry their associated BaseShaders as children.

    While it is possible to figure out the hosting material for a shader by walking over all materials in the document, actually implementing that will be probably more work than you expect as you have to accommodate the mess that is Cinemas material system under the hood: reflectance channel, layer shader, multiple material types, and the list goes on.

    Let me clarify this (before an angry maxon employee points out that this all follows a bigger plan :)): I always felt that dealing with the material system is a bit of mess ;)

    Cheers
    zipit



  • @zipit said in Get shader's parent ID:

    Hey,

    if I do understand your initial question correctly the linked post does not contain your answer. While both BaseShaders and BaseMaterials are GeListNodes only BaseShaders that are attached to each other (a noise shader in a fusion shader for example) are in child - parent relationship. BaseMaterials do not carry their associated BaseShaders as children.

    While it is possible to figure out the hosting material for a shader by walking over all materials in the document, actually implementing that will be probably more work than you expect as you have to accommodate the mess that is Cinemas material system under the hood: reflectance channel, layer shader, multiple material types, and the list goes on.

    Let me clarify this (before an angry maxon employee points out that this all follows a bigger plan :)): I always felt that dealing with the material system is a bit of mess ;)

    Cheers
    zipit

    Hi Zipit,

    Thanks for your help and reply!
    Yes you are absolutely correct in regards of the relationship between BaseShaders and BaseMaterials (and how the material system works ;)). Perhaps I should have explained it better above, before marking it as solved. So thank you for that! 👍

    The solution I linked seems to be doing the opposite, where it checks the channel first and if enabled and have a shader, returns the channel. (Think this is what is written, but please correct me if i'm wrong! :))

    In my case, I have a specific attribute I want to change with all of the Octane materials. The Image Texture node has a type attribute that need changing to float for specific channels. This is reduce to memory when Octane is loading and rendering textures.

    Have to think of a different solution and come back...

    Thanks for your help again! ☺

    Andre



  • Hi,

    ah, ok, that was indeed a misunderstanding then. I was just pointing out that you cannot go (easily) from a BaseShader instance to its associated BaseMaterial but you can of course retrieve all shaders associated with a BaseList2D via .GetFirstShader (which includes a BaseMaterial).

    Cheers
    zipit



  • @zipit said in Get shader's parent ID:

    Hi,

    ah, ok, that was indeed a misunderstanding then. I was just pointing out that you cannot go (easily) from a BaseShader instance to its associated BaseMaterial but you can of course retrieve all shaders associated with a BaseList2D via .GetFirstShader (which includes a BaseMaterial).

    Cheers
    zipit

    Hi Zipit,

    Absolutely correct! Thank you! 👍

    I've actually end up hardcoding it a bit. To be honest it works for now and if needed to be changed, it's just a matter of changing the channels list. As such:

    import c4d
    
    count = 0
    total_size = 0.00
    
    
    def change_to_float(mat):
        """
        If channel contains linked textures, change attribute type to Float.
        """
    
        channels = [c4d.OCT_MATERIAL_ROUGHNESS_LINK,
                    c4d.OCT_MATERIAL_SPECULAR_LINK,
                    c4d.OCT_MAT_SPECULAR_MAP_LINK,
                    c4d.OCT_MATERIAL_BUMP_LINK,
                    c4d.OCT_MATERIAL_DISPLACEMENT_LINK,
                    c4d.OCT_MIXMATERIAL_DISPLACEMENT_LINK,
                    c4d.BLENDMAT_DISPLACEMENT_LINK,
                    c4d.OCT_MATERIAL_OPACITY_LINK,
                    c4d.OCT_MAT_REFLECTION_LINK,
                    c4d.MIXMATERIAL_AMOUNT_LNK]
    
        for channel in channels:
            if mat[channel]:
    
                linked = mat[channel]
    
                if channel == c4d.OCT_MATERIAL_DISPLACEMENT_LINK or \
                        channel == c4d.BLENDMAT_DISPLACEMENT_LINK or \
                        channel == c4d.OCT_MIXMATERIAL_DISPLACEMENT_LINK:
    
                    linked = linked[c4d.DISPLACEMENT_INPUT]
    
                if linked is not None and linked[c4d.IMAGETEXTURE_MODE] == 0:
    
                    linked[c4d.IMAGETEXTURE_MODE] = 1  # Float
                    path = linked[c4d.IMAGETEXTURE_FILE]
                    bmp = c4d.bitmaps.BaseBitmap()
                    bmp.InitWith(path)
    
                    x, y = bmp.GetSize()  # Gets the X and Y dimensions of the image
    
                    size_bmp = (x * y) / 1024
                    global total_size
                    total_size += size_bmp
    
                    global count
                    count += 1
    
        return count, total_size
    
    
    def main():
        """
        Main function for textureTypeFloat().
        """
    
        mat = DOC.GetFirstMaterial()
        c4d.gui.SetMousePointer(c4d.MOUSE_NORMAL)
    
        if not mat:
            c4d.gui.MessageDialog("No material(s) in the scene!")
            c4d.StatusSetText("No material(s) in the scene!")
            return False
    
        while mat:
    
            c4d.gui.SetMousePointer(c4d.MOUSE_BUSY)
    
            if mat.GetTypeName() == 'Octane Material' or \
                    mat.GetTypeName() == 'Octane Mix Material' or \
                    mat.GetTypeName() == 'Octane Blend Material':
    
                count, total_size = change_to_float(mat)
                print("{0} Checked!".format(mat.GetName()))
    
            mat = mat.GetNext()
    
        c4d.EventAdd()
        c4d.gui.SetMousePointer(c4d.MOUSE_NORMAL)
        c4d.gui.MessageDialog("{0} Shaders Changed! Saving {1:.2f} Mb!".format(count, (total_size / 1024)))
    
    
    if __name__ == '__main__':
        main()
    
    

    Thank you very much for your help! ☺

    Andre



  • hello,
    thanks @zipit ^^

    just one thing, in the context of the script manager, you don't need DOC = c4d.documents.GetActiveDocument() there is already doc.

    cheers,
    Manuel.



  • @m_magalhaes said in Get shader's parent ID:

    hello,
    thanks @zipit ^^

    just one thing, in the context of the script manager, you don't need DOC = c4d.documents.GetActiveDocument() there is already doc.

    cheers,
    Manuel.

    Corrected! ☺

    Thank you Manuel!


Log in to reply