SOLVED Creating a material and applying to BaseObject within Python Generator

Hello, I did a search and couldn't find much to do with materials.

My c4d version is R19

I am creating a bunch of BaseObjects inside a Python Generator and trying to shade them in various ways- which requires me to create a new material for each BaseObject.

I am successfully creating the Material instance (I think) by storing a new c4d.Material() into a new variable. However, when I run MakeTag(c4d.Ttexture) on the BaseObject and set the c4d.TEXTURETAG_MATERIAL parameter to my newly created material, it does not appear to take.

Here is my code. It uses some modata from a linked matrix object to generate a series of discs / rings.

import c4d
from c4d.modules import mograph as mo
#Welcome to the world of Python

def main():
    link = op[c4d.ID_USERDATA,1]
    size = op[c4d.ID_USERDATA,2]
    roff = op[c4d.ID_USERDATA,3]
    
    md = mo.GeGetMoData(link)
    if md is None: return False
    
    null = c4d.BaseObject(c4d.Onull)
    
    cnt = md.GetCount()
    marr = md.GetArray(c4d.MODATA_MATRIX)
    carr = md.GetArray(c4d.MODATA_COLOR)
    for i in reversed(xrange(0, cnt)):
        
        mat = c4d.Material()
        mat.SetChannelState(c4d.CHANNEL_COLOR, True)
        mat[c4d.MATERIAL_COLOR_COLOR] = carr[i]
        
        disc1 = c4d.BaseObject(c4d.Odisc)
        disc1[c4d.PRIM_DISC_ORAD] = carr[i][0] * size
        disc1[c4d.PRIM_AXIS] = 4
        disc1.SetMg(marr[i])
        disc1.InsertUnder(null)
        
        disc2 = c4d.BaseObject(c4d.Odisc)
        disc2[c4d.PRIM_DISC_IRAD] = carr[i][0] * size
        disc2[c4d.PRIM_DISC_ORAD] = carr[i][0] * size * 1.2
        disc2[c4d.PRIM_AXIS] = 4
        moff = marr[i]
        moff.off = moff.off + (roff * carr[i][0])
        disc2.SetMg(marr[i])
        ttag =  disc2.MakeTag(c4d.Ttexture)
        ttag[c4d.TEXTURETAG_MATERIAL] = mat
        disc2.InsertUnder(null)
    
    return null

Any ideas or suggestions are greatly appreciated! Thank you!

Hello,

you cannot create a Material in the main() function of a Python Generator object.

The main() function of the Python Generator object defines a cache of "virtual" BaseObjects which will appear in the scene.

Materials cannot be created this way. A material must be inserted into the BaseDocument. This must only happen from the main thread, typically in reaction to some user interaction.

One way of doing this would be to add a user data button to your Generator. Then your user could simply press that button to create the needed materials. Pressing the button can be detected by implementing the message() function.

This could look like this:

def main():

    # search for material
    mat = doc.SearchMaterial("Generator Material")

    if mat is None:
        return None

    # create object
    cube = c4d.BaseObject(c4d.Ocube)
    
    # apply material
    ttag =  cube.MakeTag(c4d.Ttexture)
    ttag[c4d.TEXTURETAG_MATERIAL] = mat

    return cube

def message(id, data):
    if id == c4d.MSG_DESCRIPTION_COMMAND:
        buttonId = data['id']

        # check button ID
        if buttonId[1].id == 1:
            
            # create material and insert it into the host document
            c4d.StopAllThreads()

            material = c4d.Material()
            material.SetName("Generator Material")
            material[c4d.MATERIAL_COLOR_COLOR] = c4d.Vector(1,0,0)

            doc.InsertMaterial(material, None)

            c4d.EventAdd()

Also, please use the Q&A system.

best wishes,
Sebastian