2

I would like to select multiple objects and add a custom UV set to all of them. My version works for one selected object only but not for multiple selected objects.

import bpy

# Get all selected objects
selected_objects = bpy.context.selected_objects 

for obj in selected_objects:
    # Add new UV set
    bpy.ops.mesh.uv_texture_add() 
    # Set new UV set name for active UV set
    bpy.context.object.data.uv_layers.active.name = "UV_ao"

What's wrong with my code?

brockmann
  • 12,613
  • 4
  • 50
  • 93
Christoph Werner
  • 1,965
  • 1
  • 14
  • 31

2 Answers2

4

You can get rid of the uv_texture_add() operator by adding a new UVLoopLayer:

import bpy

for obj in bpy.context.selected_objects:
    # Make sure this is a mesh object and that it doesn't already use this UV Map
    if obj.type == 'MESH' and "UV_ao" not in obj.data.uv_layers:
        obj.data.uv_layers.new(name="UV_ao")
brockmann
  • 12,613
  • 4
  • 50
  • 93
Gorgious
  • 30,723
  • 2
  • 44
  • 101
2

In order to make the operator work for multiple objects, the current object in the loop needs to be assigned to ViewLayer.active before calling uv_texture_add():

import bpy

# Do the following for all selected objects
for obj in bpy.context.selected_objects: 
    # Set current object in the selection as active
    bpy.context.view_layer.objects.active = obj 
    # Add new UV set to active object
    bpy.ops.mesh.uv_texture_add() 
    # Set the name of the uv layer
    obj.data.uv_layers.active.name = "UV_ao"

Related: Blender 2.8 API, python, set active object


Another way is overriding the context of the operator by passing the object:

import bpy

# Do the following for all selected objects
for obj in bpy.context.selected_objects:
    # Override the context by passing the current object
    bpy.ops.mesh.uv_texture_add({'object': obj})
    # Set the name of the uv layer
    obj.data.uv_layers.active.name = "UV_ao"
brockmann
  • 12,613
  • 4
  • 50
  • 93
Christoph Werner
  • 1,965
  • 1
  • 14
  • 31
  • 1
    Why are you assigning "UV_ao" string to the the active UV-layer of the object in context when looping through the objects anyway? Btw: you don't have to assign the object to the ViewLayer.active. You can override the context by passing the actual object {'object': obj} to uv_texture_add() operator, call is: bpy.ops.mesh.uv_texture_add({'object': obj}). – brockmann May 04 '20 at 14:51
  • Sorry guys. I forgot to delete the last line, because of using it in my scene here. my objects have all a minimum of one UV set. But thank you a lot for the forther information, That helps! – Christoph Werner May 05 '20 at 10:09
  • 1
    No need to say sorry. Just read the comments again and try to understand them. – brockmann May 05 '20 at 10:14