0
$\begingroup$

In my current project I'm facing some strange, but necessary operation to be done with my models, and what is worst, this operation is REALLY annoying when repeated manually again and again for thousand times. Is there any way to script it out?

So here it is:

enter image description here

  1. At the beginning, lets say I have two objects. Active is the Original one (ORIG) and the second (selected) is the Clone (CLONE). Firstly, I have to transfer Location, Rotation and Scale from active to selected. I'm using "Copy all to Selected" for this step;

enter image description here 2. Secondly, I have to self-copy a material on selected object (copy existing and rename with that "two sheets of paper" button, so that it would be unique and dont affect on the same materials on other similar objects) and name it exactly as an Object.Name of active object. I DO NOT copy any materials from selected to active. Moreover, this type of material is having a texture, which also has to be recreated (without alpha channel) with 1024x1024 resolution and named as an Object.Name of active object after new material was already made;

enter image description here 3. Finally, selected object has to be renamed itself as an Object.Name of active object + "_A". So in my example it should now be "ORIG_A". I have a solution for this step and it works fine alone:

import bpy

name = bpy.context.active_object.name
suffix = "_A"

for object in bpy.context.selected_objects:
    if not object.name == name:
        object.name = bpy.context.active_object.name + suffix
        break

Please provide any help! I think it's quiete an easy peace of code, but not for a dumb guy like me :(

$\endgroup$
2
  • 2
    $\begingroup$ It might be beneficial to provide more context about what you are trying to do. Even though the question can be answered easily and it might be a good question possibly useful for other users of BSE, this might still be an XY problem. It might be possible to achieve your primary goal easier. $\endgroup$ Commented Jun 20, 2023 at 7:18
  • 1
    $\begingroup$ Hi Please use a title that reflects the content of the question. It should be descriptive but succinct, unique and identifying, summarizing the issue so that users can at a glance understand what your post is about. Use the edit link below your post and avoid anything not strictly essential to the post. Remember, your title is the first thing potential visitors will see, and makes your question findable for future users. See "What is the problem with posting an image or link and asking “How do I do this?"" $\endgroup$ Commented Jun 20, 2023 at 8:33

3 Answers 3

0
$\begingroup$

You can use Python to automate things in Blender. See Blender Python API documentation

A script that does what you describe might look something like this:

import bpy

for o in bpy.context.selected_objects:
    if o == bpy.context.object:
        active = o
    else:
        selected = o
        
selected.matrix_world = active.matrix_world # copy transfr

selected.material_slots[0].material = active.material_slots[0].material.copy()

mat = selected.material_slots[0].material

mat.name = active.name
image = bpy.data.images.new(active.name, 1024, 1024, alpha = False)
image.alpha_mode = 'NONE'  
image.generated_type = 'COLOR_GRID'  

for n in mat.node_tree.nodes:
    if n.type == 'TEX_IMAGE':
        n.image = image
        
selected.name = active.name + "_A"

It might be a good idea to check for unexpected conditions.

$\endgroup$
10
  • $\begingroup$ Also works great except for material legacy, as I mensioned in a comment above: "When I'm running the script, it appears that material is clearly "New". I mean, when I'm using New Material button (those two sheets of paper on the right from Material name), this allows to keep all necessary parameters of material like Viewport Color, Principle BSDF settings and other node tree stuff, just the name is changed. Can it somehow be done via this script?" $\endgroup$
    – Jeff
    Commented Jun 20, 2023 at 7:06
  • $\begingroup$ What are you talking about? active.material_slots[0].material.copy() copies material. $\endgroup$ Commented Jun 20, 2023 at 7:09
  • $\begingroup$ Whoops, seems like I was not clear enough in my OP description, corrected it now. We do not copy any materials from active to selected, we just make a self-copy of a material on selected object (copy existing and rename with that "two sheets of paper" button, so that it would be unique and dont affect on the same materials on other similar objects). $\endgroup$
    – Jeff
    Commented Jun 20, 2023 at 7:33
  • $\begingroup$ Well, that is not clear anyway. In any case, you have two good examples, how to do it, you can edit the scripts to your liking. $\endgroup$ Commented Jun 20, 2023 at 7:39
  • $\begingroup$ I don't understand to be honest. The script does what you describe as far as I can tell - it duplicates the first material from active object and assigns the duplicate to the selected one. As you can see it does that for the first material slot of the objects. So if you have more materials on the active object it only duplicates the first one. My idea was really just to provide an example, so you can edit it and adapt it to your exact situation. $\endgroup$ Commented Jun 20, 2023 at 7:46
1
$\begingroup$
import bpy
from bpy import context


def remove_material_slots(object: bpy.types.Object):
    '''
    Remove all the material slots.

    object (bpy.types.Object) - The object to remove material slots from.
    '''
    if object.type == 'MESH' and object.material_slots:
        object.data.materials.clear()


def set_material(object: bpy.types.Object, material: bpy.types.Material, index: int=None):
    '''
    Set material to object.

    object (bpy.types.Object) - Object to set material to.
    material (bpy.types.Material) - Material to set.
    '''
    if object.data.materials and index:
        object.data.materials[index] = material
    else:
        object.data.materials.append(material)


for object in context.selected_objects:
    if object == context.object:
        continue
    
    # Copy Transform
    object.matrix_world = context.object.matrix_world
    
    # Assign Material
#    remove_material_slots(object=object)
    set_material(object=object, material=object.material_slots[0].material.copy())
    
    # Rename Material
    object.material_slots[0].material.name = context.object.name
    
    # Rename Image Texture
    node_tree = object.material_slots[0].material.node_tree
    image = bpy.data.images.new(name=context.object.name, width=1024, height=1024)
    for node in node_tree.nodes:
        if node.type == 'TEX_IMAGE' and node.image:
            node.image = image
    
    # Rename to Active Object
    object.name = f'{context.object.name}_A'
    if object.type == 'MESH':
        object.data.name = f'{context.object.name}_A'
$\endgroup$
8
  • $\begingroup$ Works great for transforms, many thanks! But as for material and texture I have some questions. When I'm running the script, it appears that material is clearly "New". I mean, when I'm using New Material button (those two sheets of paper on the right from Material name), this allows to keep all necessary parameters of material like Viewport Color, Principle BSDF settings and other node tree stuff, just the name is changed. Can it somehow be done via this script? $\endgroup$
    – Jeff
    Commented Jun 20, 2023 at 7:01
  • $\begingroup$ Texture has correct name of an Active object, but the resolution is 1440x1440 and the color is not black as it usually is for a new texture, it has some raster imaginary O_o $\endgroup$
    – Jeff
    Commented Jun 20, 2023 at 7:01
  • $\begingroup$ Do you need the new image of 1024px? $\endgroup$
    – Karan
    Commented Jun 20, 2023 at 7:11
  • $\begingroup$ How many materials do your active object have? $\endgroup$
    – Karan
    Commented Jun 20, 2023 at 7:12
  • 1
    $\begingroup$ The script doesn't creates new material, it just copies the first material of the active object and assign to the selected objects $\endgroup$
    – Karan
    Commented Jun 20, 2023 at 7:26
0
$\begingroup$

Anyways, here the is solution for my question based on both Karan and Martynas Žiemys answers.

import bpy

for o in bpy.context.selected_objects:
    if o == bpy.context.object:
        active = o
    else:
        selected = o
        
selected.matrix_world = active.matrix_world # copy transfr

selected.material_slots[0].material = selected.material_slots[0].material.copy()

mat = selected.material_slots[0].material

mat.name = active.name
image = bpy.data.images.new(active.name, 1024, 1024, alpha = False)
image.alpha_mode = 'NONE'  
image.generated_type = 'BLANK'  

for n in mat.node_tree.nodes:
    if n.type == 'TEX_IMAGE':
        n.image = image
        
selected.name = active.name + "_A"
$\endgroup$
1
  • $\begingroup$ One question at a time, please $\endgroup$ Commented Jun 20, 2023 at 9:07

You must log in to answer this question.

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