4
$\begingroup$
def displace(obj):
    mod=bpy.ops.object.modifier_add(type='DISPLACE')
    tex1 = bpy.ops.texture.new()
    bpy.data.textures[tex1].type = 'VORONOI'

I am trying to add a Voronoi displace texture, but I just can't assign my freshly made tex1 to be a type of Voronoi.

$\endgroup$

2 Answers 2

3
$\begingroup$

Passing obj to your function doesn't matter, because modifier_add works on the active object. If you don't want that, see this answer for how to avoid bpy.ops altogether.

bpy.ops.texture.new doesn't return a value, nor does bpy.ops.object.modifier_add, so you have to find tex1 some other way. You also have to assign your newly created texture to the modifier. Here is one way to do this, there are others. This code is verbose to make it clear what it is doing. It can be simplified a bit.

def displace():
    bpy.ops.object.modifier_add(type='DISPLACE')
    texture_set = set(bpy.data.textures.keys())
    bpy.ops.texture.new()
    new_texture_set = set(bpy.data.textures.keys()) - texture_set
    texture_name = new_texture_set.pop()
    texture = bpy.data.textures[texture_name]
    texture.type = 'VORONOI'
    bpy.context.active_object.modifiers[-1].texture = texture

This uses a common technique for find what an bpy.ops operator has created:

  • Create a set of all the things created by that op
  • Execute the op
  • Create a set of all the things created by that op and remove the old set from it.

This will leave you with a set that consists of the newly created things. In the case of a texture there is only one.

It also relies on modifier_add adding the modifier to the end of the modifier stack, making it possible to find it with the index -1.

Often, there is a better approach because the op will set some contextual "active" data, and instead of constructing the sets you can just refer to whatever that is.

Also, Markus von Broady just reminded me in a comment that if the op adds one newly created thing to a list you can use the index -1 to retrieve it rather than the set operations. (In other words, I could use the same technique I used for finding the modifier to find the texture!) This leads to the shorter version:

def displace():
    bpy.ops.object.modifier_add(type='DISPLACE')
    bpy.ops.texture.new()
    texture = bpy.data.textures[-1]
    texture.type = 'VORONOI'
    bpy.context.active_object.modifiers[-1].texture = texture
$\endgroup$
3
  • $\begingroup$ Damn you, you've beat me again :) Interesting set operation, afraid the last added texture won't actually be last in the list? $\endgroup$ Jan 25 at 1:16
  • $\begingroup$ Not afraid, just trying to share a seldom described technique. Notice I used last in the list for the modifier. $\endgroup$ Jan 25 at 1:17
  • $\begingroup$ I did notice that! I was wondering why two different techniques, definitely makes sense for an operator that outputs a variable number of stuff or might not output something if it already exists etc. $\endgroup$ Jan 25 at 1:18
6
$\begingroup$

If you enable the System Console (option in Window menu), you can see the error complaining about an invalid key being a set. This is because your tex1 is a set {'FINISHED'} - a typical return value of an operator. You can instead assign the last texture and the last modifier to your variables to use them:

import bpy
bpy.ops.object.modifier_add(type='DISPLACE')
mod = bpy.context.object.modifiers[-1]
bpy.ops.texture.new()
tex1 = bpy.data.textures[-1]
tex1.type = 'VORONOI'
mod.texture = tex1

Or use more direct API without operators: How to create a generic texture using python?

import bpy
from bpy import context as C, data as D
ob = C.object
mod = ob.modifiers.new('', type='DISPLACE')
tex1 = D.textures.new("displace_voronoi", 'VORONOI')
mod.texture = tex1
$\endgroup$
2
  • $\begingroup$ why not skip tex1 in you second version and go with mod.texture = D.textures.new(...)? $\endgroup$ Jan 25 at 1:47
  • $\begingroup$ @MartyFouts honestly that's what I would do, but the OP used a variable tex1, so I wanted to make both codes as similar to his as reasonably possible. You could also do C.object.modifiers.new('', type='DISPLACE').texture = D.textures.new('', 'VORONOI'), which is 83 characters long (and according to PEP 8, lines should be at most 79 characters long, counting indentation) $\endgroup$ Jan 25 at 10:56

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.