2
$\begingroup$

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?

$\endgroup$
3
  • 2
    $\begingroup$ You need to set the active object during the for loop. bpy.context.view_layer.objects.active = obj $\endgroup$
    – Ratt
    May 4, 2020 at 9:11
  • $\begingroup$ Thank you a lot for the fast answer. All works fine! I've added the right code below to help others. $\endgroup$ May 4, 2020 at 9:14
  • $\begingroup$ Related: How to add a UV Map to a Mesh Using Python $\endgroup$
    – brockmann
    May 4, 2020 at 15:16

2 Answers 2

4
$\begingroup$

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")
$\endgroup$
4
  • $\begingroup$ Thank you for this hint! $\endgroup$ May 5, 2020 at 10:13
  • $\begingroup$ @brockmann Thanks for the edit, would you care to explain why the single quote around 'Mesh'but not around the other string ? $\endgroup$
    – Gorgious
    May 5, 2020 at 11:08
  • 2
    $\begingroup$ Readability. "Use single quotes for enums, and double quotes for strings.", quote from: docs.blender.org/api/current/info_best_practice.html $\endgroup$
    – brockmann
    May 5, 2020 at 11:10
  • $\begingroup$ @brockmann Oh, right. Thanks ! $\endgroup$
    – Gorgious
    May 5, 2020 at 12:13
2
$\begingroup$

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"
$\endgroup$
3
  • 1
    $\begingroup$ 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}). $\endgroup$
    – brockmann
    May 4, 2020 at 14:51
  • $\begingroup$ 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! $\endgroup$ May 5, 2020 at 10:09
  • 1
    $\begingroup$ No need to say sorry. Just read the comments again and try to understand them. $\endgroup$
    – brockmann
    May 5, 2020 at 10:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .