Solved Cinema Gradient, weird behaviour

Hi all,

I encountered a very weird behaviour. I tried to write a script in python which reads all the knot-values of one gradient and set those value to another gradient.
I can read the knots by calling GetKnot().
BUT when I try to extract a certain info from a Knot (for example the position) I get wrong results. So when transfering these infos to another gradient, the gradient is shown wrong.

Thats the Code:

import c4d
from c4d import gui


def main():
    mat = doc.GetFirstMaterial()           #Gets the first material in the materials manager
    shdr1 = mat[c4d.MATERIAL_COLOR_SHADER]

    shd = c4d.BaseList2D(1011100) # Gradient
    mat[c4d.MATERIAL_DIFFUSION_SHADER] = shd
    mat.InsertShader(shd)
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)

    shdr2 = mat[c4d.MATERIAL_DIFFUSION_SHADER]


    grad1 = shdr1[c4d.SLA_GRADIENT_GRADIENT]
    grad2 = shdr2[c4d.SLA_GRADIENT_GRADIENT]


    grad1_knot1 = grad1.GetKnot(0)
    print("Knot1 = " + str(grad1_knot1))
    grad1_knot2 = grad1.GetKnot(1)
    print("Knot2 = " + str(grad1_knot2))
    grad1_knot3 = grad1.GetKnot(2)
    print("Knot3 = " + str(grad1_knot3))

    index1 = grad1_knot1['index']
    print("Index" + " " + str(index1))
    index2 = grad1_knot2['index']
    print("Index" + " " + str(index2))
    index3 = grad1_knot3['index']
    print("Index" + " " + str(index3))
    pos1 = grad1_knot1['pos']
    print("Position" + " " + str(pos1))
    pos2 = grad1_knot2['pos']
    print("Position" + " " + str(pos2))
    pos3 = grad1_knot2['pos']
    print("Position" + " " + str(pos3))
    col1 = grad1_knot1['col']
    print("Color" + " " + str(col1))
    col2 = grad1_knot2['col']
    print("Color" + " " + str(col2))
    col3 = grad1_knot2['col']
    print("Color" + " " + str(col3))
    bri1 = grad1_knot1['brightness']
    print("Brightness" + " " + str(bri1))
    bri2 = grad1_knot2['brightness']
    print("Brightness" + " " + str(bri2))
    bri3 = grad1_knot2['brightness']
    print("Brightness" + " " + str(bri3))
    grad2.FlushKnots()

    grad2.InsertKnot(col=col1, pos=pos1,index=index1)
    grad2.InsertKnot(col=col2, pos=pos2,index=index2)
    grad2.InsertKnot(col=col3, pos=pos3,index=index3)
    shdr2[c4d.SLA_GRADIENT_GRADIENT] =  grad2
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)
    c4d.EventAdd()
    
# Execute main()
if __name__=='__main__':
    main()

And thats the result I get from the console and obviously the second gradient looks like that (wrong), too.

"Knot1 = {'index': 1, 'bias': 0.5, 'pos': 0.3, 'col': Vector(1, 1, 1), 'brightness': 1.0}
Knot2 = {'index': 2, 'bias': 0.5, 'pos': 1.0, 'col': Vector(1, 1, 1), 'brightness': 1.0}
Knot3 = {'index': 3, 'bias': 0.5, 'pos': 0.5, 'col': Vector(1, 0.6, 0.5), 'brightness': 1.0}
Index 1
Index 2
Index 3
Position 0.3
Position 1.0
Position 1.0
Color Vector(1, 1, 1)
Color Vector(1, 1, 1)
Color Vector(1, 1, 1)
Brightness 1.0
Brightness 1.0
Brightness 1.0
"

As you can see: When calling GetKnot() the infos of the Knots are right. But when extracting for example col of those Knots, The results are wrong. They all show Vector(1, 1, 1).

What is happening here?

Cheers,
PdZ

I coded a solution. But this was so much work and effort to get it work.
Its not very sexy though. BUT it works.

import c4d
from c4d import gui


def main():
    mat = doc.GetFirstMaterial()           #Gets the first material in the materials manager
    shdr1 = mat[c4d.MATERIAL_COLOR_SHADER]

    shd = c4d.BaseList2D(1011100) # Gradient
    mat[c4d.MATERIAL_DIFFUSION_SHADER] = shd
    mat.InsertShader(shd)
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)

    shdr2 = mat[c4d.MATERIAL_DIFFUSION_SHADER]


    grad1 = shdr1[c4d.SLA_GRADIENT_GRADIENT]
    grad2 = shdr2[c4d.SLA_GRADIENT_GRADIENT]


    grad1_knot1 = str(grad1.GetKnot(0)).replace("'", "").replace(":", " =").replace("Vector", "c4d.Vector").replace("{", "").replace("}", "")
    grad1_knot2 = str(grad1.GetKnot(1)).replace("'", "").replace(":", " =").replace("Vector", "c4d.Vector").replace("{", "").replace("}", "")
    grad1_knot3 = str(grad1.GetKnot(2)).replace("'", "").replace(":", " =").replace("Vector", "c4d.Vector").replace("{", "").replace("}", "")
    print(grad1_knot1)
    
    # index
    newgrad1_knot1_index_nr = grad1_knot1.find(",")
    newgrad1_knot1_index = int(grad1_knot1[newgrad1_knot1_index_nr-1:newgrad1_knot1_index_nr])
    
    # bias
    newgrad1_knot1_bias_nr = grad1_knot1.find(",", newgrad1_knot1_index_nr+1 )
    newgrad1_knot1_bias = float(grad1_knot1[newgrad1_knot1_bias_nr-3:newgrad1_knot1_bias_nr])
    
    # color
    newgrad1_knot1_col_nr = grad1_knot1.find("col")
    newgrad1_knot1_col_nr2 = grad1_knot1.find("brig")
    newgrad1_knot1_col = grad1_knot1[newgrad1_knot1_col_nr+6:newgrad1_knot1_col_nr2-2]
    newgrad1_knot1_col_1komma = newgrad1_knot1_col.find(",")
    newgrad1_knot1_col_2komma = newgrad1_knot1_col.rfind(",")
    newgrad1_knot1_col_ende = newgrad1_knot1_col.find(")")
    vector_value_1 = float(newgrad1_knot1_col[11:newgrad1_knot1_col_1komma])
    vector_value_2 = float(newgrad1_knot1_col[newgrad1_knot1_col_1komma+2:newgrad1_knot1_col_2komma])
    vector_value_3 = float(newgrad1_knot1_col[newgrad1_knot1_col_2komma+2:newgrad1_knot1_col_ende])
    
    # position
    newgrad1_knot1_pos_nr = grad1_knot1.find("pos")
    newgrad1_knot1_pos = float(grad1_knot1[newgrad1_knot1_pos_nr+6:newgrad1_knot1_col_nr-2])
    
    # brightness
    newgrad1_knot1_bri_nr = len(grad1_knot1)
    newgrad1_knot1_bri = float(grad1_knot1[newgrad1_knot1_col_nr2+13:newgrad1_knot1_bri_nr])


    grad2.FlushKnots()

    grad2.InsertKnot(index = newgrad1_knot1_index, bias = newgrad1_knot1_bias, pos = newgrad1_knot1_pos, col = c4d.Vector(vector_value_1, vector_value_2, vector_value_3), brightness = newgrad1_knot1_bri)


    shdr2[c4d.SLA_GRADIENT_GRADIENT] =  grad2
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)
    c4d.EventAdd()

# Execute main()
if __name__=='__main__':
    main()

Hi, @PdZ in which version are you, using R20 with the first code works as expected, could you share a scene example?

Cheers,
Maxime.

@PdZ any news?

Hi Adam,

thx for your response!
Sorry I was busy. Didn't meant to let you wait.

Iam working with:
Cinema 4D Studio R20 20.059

Heres the testscene:
gradient_test.c4d

Heres the code:

import c4d
from c4d import gui

def main():
    mat = doc.GetFirstMaterial()           #Gets the first material in the materials manager
    shdr1 = mat[c4d.MATERIAL_COLOR_SHADER]

    shd = c4d.BaseList2D(1011100) # Gradient
    mat[c4d.MATERIAL_DIFFUSION_SHADER] = shd
    mat.InsertShader(shd)
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)

    shdr2 = mat[c4d.MATERIAL_DIFFUSION_SHADER]


    grad1 = shdr1[c4d.SLA_GRADIENT_GRADIENT]
    grad2 = shdr2[c4d.SLA_GRADIENT_GRADIENT]


    grad1_knot1 = grad1.GetKnot(0)
    print("Knot1 = " + str(grad1_knot1))
    grad1_knot2 = grad1.GetKnot(1)
    print("Knot2 = " + str(grad1_knot2))
    grad1_knot3 = grad1.GetKnot(2)
    print("Knot3 = " + str(grad1_knot3))

    index1 = grad1_knot1['index']
    print("Index" + " " + str(index1))
    index2 = grad1_knot2['index']
    print("Index" + " " + str(index2))
    index3 = grad1_knot3['index']
    print("Index" + " " + str(index3))
    pos1 = grad1_knot1['pos']
    print("Position" + " " + str(pos1))
    pos2 = grad1_knot2['pos']
    print("Position" + " " + str(pos2))
    pos3 = grad1_knot2['pos']
    print("Position" + " " + str(pos3))
    col1 = grad1_knot1['col']
    print("Color" + " " + str(col1))
    col2 = grad1_knot2['col']
    print("Color" + " " + str(col2))
    col3 = grad1_knot2['col']
    print("Color" + " " + str(col3))
    bri1 = grad1_knot1['brightness']
    print("Brightness" + " " + str(bri1))
    bri2 = grad1_knot2['brightness']
    print("Brightness" + " " + str(bri2))
    bri3 = grad1_knot2['brightness']
    print("Brightness" + " " + str(bri3))
    grad2.FlushKnots()

    grad2.InsertKnot(col=col1, pos=pos1,index=index1)
    grad2.InsertKnot(col=col2, pos=pos2,index=index2)
    grad2.InsertKnot(col=col3, pos=pos3,index=index3)
    shdr2[c4d.SLA_GRADIENT_GRADIENT] =  grad2
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)
    c4d.EventAdd()
    
# Execute main()
if __name__=='__main__':
    main()

Here is what I get as gradient in the Diffusion shader:
Knots.jpg

There are 3 Knots. 2 at the same position on the right side.
Also the console tells me that result:
console.jpg

Thx in Advance!
PdZ

@PdZ

Ok adam,

iam a stupid idiot. I had a typo.
Pls ignore everything. I checked the code and I set values of knot 2 to knot 3.

Iam sorry!

Don't feel sorry yes this is the issue and since Knot ID are not ordered from right to left but from creation order its why it's confused you.
Moreover, using a for loop will make way more sense and help you to avoid this kind of stuff.

    grad1 = shdr1[c4d.SLA_GRADIENT_GRADIENT]
    grad2 = shdr2[c4d.SLA_GRADIENT_GRADIENT]

    for knotId in xrange(grad1.GetKnotCount()):
        knot = grad1.GetKnot(knotId)
        grad2.InsertKnot(col=knot['col'], pos=knot['pos'],index=knot['index'])

    grad2.FlushKnots()

    shdr2[c4d.SLA_GRADIENT_GRADIENT] =  grad2

Finally, a BaseShader is derived from BaseList2D which is derived from C4DAtom that mean you can use GetClone to retrieves a clone of this shader so your code can look like.

import c4d

def main():
    mat = doc.GetFirstMaterial()
    colorShader = mat[c4d.MATERIAL_COLOR_SHADER]
    if colorShader is None:
        return
    
    copyColor = colorShader.GetClone()
    mat[c4d.MATERIAL_DIFFUSION_SHADER] = copyColor
    mat.InsertShader(copyColor)
    
    mat.Message(c4d.MSG_UPDATE)
    mat.Update(True, True)
    c4d.EventAdd()
    
# Execute main()
if __name__=='__main__':
    main()

Cheers,
Maxime.