1
$\begingroup$

So still trying to automate some processes.

I am trying to use drivers to access information about an image (pixel x/y size and DPI)

The location is simple bpy.data.materials['Fabric'].node_tree.nodes['IMAGE01'].image.size[0]

But the driver cannot access it through a Texture node enter image description here

As you can see, it works if I go through the image variable. But not useful when the user changes the texture.

What do I need to make it work?

$\endgroup$
  • $\begingroup$ What is being driven? $\endgroup$ – batFINGER Mar 30 at 11:57
  • $\begingroup$ A value in a Mapping Group Node $\endgroup$ – Sharl Mar 30 at 12:05
1
$\begingroup$

Use self in drivers

enter image description here

Can use self in drivers, to see what is going on can make a driver method, register it, and print to system console what the value of self is, and often more importantly what self.id_data is.

Here is a little test driver foo(self) that also returns a random number, so we can see if it is working, and when.

import bpy
from random import random

def foo(self):
    print(self, self.id_data)
    return random()

bpy.app.driver_namespace["foo"] = foo

Now add as a driver.

Add the driver directly into the property by typing #foo(self) before its a driver. Once it is a driver simply edit the expression in field.

enter image description here

On first time, Make sure use self is checked, and update deps to fire it up. If it breaks may have to update deps again.

For the simple driver will see that

<bpy_struct, NodeSocketVector("Vector")> <bpy_struct, ShaderNodeTree("Shader Nodetree")>

is printed to sys console, and the driver is a random value. Ok then self.id_data is the nodetree to which the texture node belongs.

Extending, will give a value of 4 if no image or no node named "Image Texture" .. but if there is will return the image width.

import bpy

def foo(self):
    print(self, self.id_data)
    node_tree = self.id_data
    tn = node_tree.nodes.get("Image Texture")
    if tn:
        print(tn)
        if tn.image:
            return tn.image.size[0]
    else:
        print("NO IMAGE")
    return 4.0

bpy.app.driver_namespace["foo"] = foo

Could extend further by passing the name of the image texture node and image height or width as an int for instance, and not rely on it being called "Image Texture"

def foo(self, name="Image Texture", index=0, default=0.0):
    ...

        tn = node_tree.nodes.get(name)
        ...
            return tn.image.size[index]

    return default

Now can type #foo(self, "BarTexture", 1, -44) into a prop on nodetree and it will be the height of the image in the node named "BarTexture" or -44 if there is no image or no node.

Notes:

An issue is crossing an ID line in a path for a driver variable. Starting from material going thru nodetree. If defined as a group then try using the nodetree ID type in a variable (Haven't had much joy doing this).

Remove print statements if happy with result so you don't spam the console.

| improve this answer | |
$\endgroup$
-1
$\begingroup$

Thanks everyone for your help.

I found the solution. It's a syntax issue.

In the console viewport, the code to get the pixel height or width is

bpy.data.materials['######'].node_tree.nodes['######'].image.size[0]

but the code for the driver is

node_tree.nodes["######"].image.size[0]

The Apostrophe ( ' ) should be converted to Quotation marks ( " ).

Don't know why, but it works.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.