1

enter image description here

Above is the material I've created. I exported my model to .obj from Blender. From a Python script (I have Blender compiled as a Python Module), I import my .obj file. I then attempt to set the Noise Texture 'W' property:

import bpy

bpy.ops.import_scene.obj( filepath = PATH_TO_MY_OBJ) bpy.context.object.name = "obbb" obj = bpy.data.objects["obbb"]

My material is called Material. How can I access the Noise Texture node and change the value of W?

As suggested, here is the Blend file:

Marty Fouts
  • 33,070
  • 10
  • 35
  • 79
pookie
  • 133
  • 1
  • 6
  • @brockmann nope: AttributeError: 'NoneType' object has no attribute 'node_tree' – pookie Oct 10 '21 at 14:48
  • @pookie make sure you selected an object and in Material Properties tab you selected a non-empty material slot. – Markus von Broady Oct 10 '21 at 14:52
  • @MarkusvonBroady There is no Materials Properties tab -- as I mentioned, I am doing this all from Python; Blender is not open/running. – pookie Oct 10 '21 at 14:53
  • 2
    @pookie you're using bpy.context.object to access your object. So how about print(bpy.context.object.material_slots[:]) - does it display an empty list []? If not, how about print(bpy.context.object.material_slots[0].material.node_tree) - does it display something without an error? If so, how about print(bpy.context.object.material_slots[0].material.node_tree.get("Noise Texture"))? – Markus von Broady Oct 10 '21 at 14:59
  • @MarkusvonBroady It shows an empty list – pookie Oct 10 '21 at 15:01
  • I think we need to see a Blend file to understand what is going on. (How to add a blend file) I also don't think this is answered by the other question anyway, because the answer there doesn't talk about how to find particular sockets of a node, which is necessary here. – Marty Fouts Oct 10 '21 at 15:47
  • @MartyFouts Thanks - I have added the Blend file as you suggested. – pookie Oct 10 '21 at 15:53
  • The first thing you need to do is change the string "Material" to the actual name of the material "CloudMaterial" and then the index at the end from [1] to ['W'] – Marty Fouts Oct 10 '21 at 16:23
  • @MartyFouts I've already done that, but there is no Noise Texture node: print(bpy.data.materials..node_tree.nodes.keys()) outputs: ['Principled BSDF', 'Material Output', 'Normal Map'] – pookie Oct 10 '21 at 16:25
  • There is a Noise texture in the file you posted and the change works when I test it. – Marty Fouts Oct 10 '21 at 16:29
  • @MartyFouts It works when you run the script from that Blend file... I am not running this script from within Blender. – pookie Oct 10 '21 at 16:31
  • 1
    Then there's something wrong with how you embedded blender into your application. What is the actual error you get when it fails? – Marty Fouts Oct 10 '21 at 16:33

4 Answers4

6

Above is the material I've created. I exported my model to .obj from Blender. From a Python script (I have Blender compiled as a Python Module), I import my .obj file. I then attempt to set the Noise Texture 'W' property:

When you rountrip through OBJ you will not get the original node graph back. OBJ only supports a few simple material properties, not stuff like noise textures. Import your .obj into Blender and check the shader graph. You will see that all those nodes you added are lost. That's why there isn't a noise texture.

See Import & Export of Node Shaders in the manual for more info about what is supported when exporting to OBJ.


Here is how you can append (as in File > Append) the CloudCube from your proceedural_clouds.blend file into the current file and change its W.

import bpy

First, append the CloudCube from your .blend into the current file.

blendpath = "//proceedural_clouds.blend" with bpy.data.libraries.load(blendpath, link=False) as (data_src, data_dst): data_dst.objects = ["CloudCube"] cloud_cube = data_dst.objects[0]

Link cloud cube into scene so it shows up

bpy.context.scene.collection.objects.link(cloud_cube)

Grab the material it uses

mat = cloud_cube.material_slots[0].material

Change W

mat.node_tree.nodes["Noise Texture"].inputs["W"].default_value = 42.0

brockmann
  • 12,613
  • 4
  • 50
  • 93
scurest
  • 10,349
  • 13
  • 31
  • I have a few items in my scene already. Will opening the .blend file delete them? Also, could you give me an example of how I would load the blend file and set the Noise Texture W property? – pookie Oct 10 '21 at 16:53
  • "Will opening the .blend file delete them?" Yes it would. You can append the data you need instead. See edit. – scurest Oct 10 '21 at 17:19
  • Thank you! And nice touch with the reference to Hitch Hikers Guide to the Galaxy. – pookie Oct 10 '21 at 18:21
1

Hover over the W property and right-click (RMB context) menu Copy Full Data Path:

enter image description here

Then you can paste it into your python script, e.g.,:

bpy.data.materials["Material.001"].node_tree.nodes["Noise Texture"].inputs[1].default_value

and just add = 0.2 or whatever

james_t
  • 5,446
  • 8
  • 29
  • No, it will not work. It does not find any Noise Texture, for some reason. – pookie Oct 10 '21 at 16:28
  • @pookie -- do you own "Copy Full Data Path" as I show above, as the name of your Noise Texture node might not be "Noise Texture"! It might be "Noise Texture.001", for example. – james_t Oct 10 '21 at 16:54
1

EDIT The real reason is that the object file was being imported as OBJ, which doesn't support Blender materials, especially not noise.

The solution is to either read the Blender file or to reconstruct the material in Python before trying the solution below.

Your approach was close:

from random import randrange
import bpy
import time

for i in range(0,50): n = randrange(10) bpy.data.materials["Material"].node_tree.nodes["Noise Texture"].inputs[1].default_value = n

but you need to change the last line slightly:

bpy.data.materials["CloudMaterial"].node_tree.nodes["Noise Texture"].inputs['W'].default_value = n

The index for materials should be the actual name of the material and using ['W'] rather than [1] makes the code work even if the developers change the order of input sockets in the future.

Marty Fouts
  • 33,070
  • 10
  • 35
  • 79
  • This will error with KeyError: 'bpy_prop_collection[key]: key "Noise Texture" not found'.

    I'm not running my script from within Blender; I'm running Blender as a Python module. My Python app calls bpy, loads the obj file and now I am trying to edit the W property of the Noise Texture shader node.

    – pookie Oct 10 '21 at 16:38
  • So the problem is probably that the shader being loaded from the obj file is not the shader in the blend file. – Marty Fouts Oct 10 '21 at 16:42
  • hmm, any idea how to fix that? – pookie Oct 10 '21 at 16:45
  • Wavefront obj's mtl files don't support materials that translate to Noise textures. The best I can suggest is to reconstruct the material in Python so it ends up with the node tree you want. – Marty Fouts Oct 10 '21 at 16:51
  • Ha, OK, thanks -- No idea how I will do that :D – pookie Oct 10 '21 at 16:52
  • @MartyFouts and pookie, don't ASSUME the node is actually "Noise Texture", as you'll see from my comment to my answer below. Copy Full Data Path and paste into your script. – james_t Oct 10 '21 at 16:56
  • In my own code, I actually have a function to find node by type that I use, because names change. – Marty Fouts Oct 10 '21 at 17:00
1

You wrote "I have Blender compiled as a Python Module". Do you realize that you can run blender in background against a script (no UI).

For example I set up a python script.py as

import bpy
bpy.data.materials['CloudMaterial'].node_tree.nodes['Noise Texture'].inputs[1].default_value=2.33
bpy.ops.wm.save_mainfile()

and used the command line:

blender -b proceedural_clouds.blend -P script.py

And the V value was changed.

james_t
  • 5,446
  • 8
  • 29