add texture driver

Hi
I tried to add a driver to the color influence of a texture.
Something like:
driver_add(‘texture_slots[0].diffuse_color_factor’)
But that seems to be the wrong string. Also I’m not sure where exactly to add the driver, like: object.driver_add()
Any help appreciated

If you add it from the UI you get a driver added to the object with datapath (path from object to property) of


material_slots["Material"].material.texture_slots[0].diffuse_color_factor

If you try and add this using script it will spit the dummy… You can add a dummy driver like location[0] and then overwrite the data_path later.


>>> C.object.driver_add('material_slots["Material"].material.texture_slots[0].diffuse_color_factor')
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
ValueError: bpy_struct.driver_add(): path spans ID blocks

>>> driver = C.object.driver_add('location',0)
>>> driver
bpy.data.objects['Cube']...FCurve

>>> driver.data_path = 'material_slots["Material"].material.texture_slots[0].diffuse_color_factor'

You can also add the driver to the material… this is my prefered method. This way the material is driven for any object that uses it


>>> bpy.data.materials['Material'].driver_add('texture_slots[0].diffuse_color_factor')
bpy.data.materials['Material']...FCurve

Thank you very much, that worked well
One other question:
if you do something in the viewport, the python code gets displayed in the info window. But only the “global” command gets shown, which automatically refers to the active object.
Is there an easy way to “convert” this code to do it with some other object?
e.g.
bpy.ops.object.duplicate_move() to
myObject.duplicate_move()
I mean just so I can look it up more quickly in general, not to actually use this in a script

Hi batFINGER,

Have you really managed to create drivers for the material directly? There is something special about material and texture drivers that make them work differently from other drives. Run the program below with the default setup.

If test = 1, the first texture slot turns purple but the driver does not work.
If test = 2, I get the error message “path spans ID blocks”.
If test = 3, the first texture slot does not turn purple but the driver works.

Unfortunately, in my specific problem I dont have access to the mesh when I want to create material drivers, at least not without a rather massive recoding. That I dont get visual feedback is ok, but I really want to create material drivers before I create the objects.

import bpy

test = 3

tex = bpy.data.textures.new("Tex", type = "CLOUDS")
mat = bpy.data.materials.new("Mat")
mtex = mat.texture_slots.add()
mtex.texture = tex

cube = bpy.data.objects["Cube"]
cube["UseTex"] = True
cube.data.materials[0] = mat

if test == 1:
    fcu = mat.driver_add("use_textures", 0)
elif test == 2:
    fcu = cube.driver_add("data.materials[0].use_textures", 0)
elif test == 3:
    fcu = cube.driver_add("location", 0)
    fcu.data_path = "data.materials[0].use_textures"
    fcu.array_index = 0    

drv = fcu.driver
drv.type = "SCRIPTED"
drv.expression = "x"
drv.show_debug_info = True

var = drv.variables.new()
var.name = "x"
var.type = "SINGLE_PROP"

targ = var.targets[0]
targ.id = cube
targ.data_path = '["UseTex"]'

Hmmm,

Yeah i see what you mean… haven’t paid too much attention to the values, glad you pointed this out.
This piece of code makes method 1 work


def matfix(scene):
    for mat in bpy.data.materials:
        if mat.animation_data is not None:
            for driver in mat.animation_data.drivers:
                prop = mat.path_resolve(driver.data_path)
                #print(prop)
                prop[driver.array_index] = driver.evaluate(scene.frame_current)

bpy.app.handlers.frame_change_pre.append(matfix)

Is it bug-reportworthy?

EDIT: couple of checks for specific case


def matfix(scene):
    dlist = [(driver, mat) for mat in bpy.data.materials
             if mat.animation_data is not None
             for driver in mat.animation_data.drivers 
             if driver.data_path == "use_textures"]
    for driver, mat in dlist:                
        prop = mat.path_resolve(driver.data_path)
        #print(prop)
        cls = type(prop).__name__
        if cls == "bpy_prop_array":
            prop[driver.array_index] = driver.evaluate(scene.frame_current)

bpy.app.handlers.frame_change_pre.append(matfix)

Thanks a lot! Your matfix function resolves a long-standing problem for me, although I invoke it from a explicit update button rather than on frame change.

I already filed a bug report half a year ago. Somebody, probably Aligorith, explained that material and texture drivers were handled differently from other drivers, but I did not understand how it worked.