Category: Blender

How To Get Mapping of UV and Vertex

GOAL

To get correspondence of UV coordinates and vertex id in the object in Blender scene by Blender Python. The following is output of the script.

uv: 0.625 0.5 vertex id: 0
uv: 0.875 0.5 vertex id: 4
uv: 0.875 0.75 vertex id: 6
uv: 0.625 0.75 vertex id: 2
uv: 0.375 0.75 vertex id: 3
.
.
.

Environment

Blender 2.83 (Python 3.7.4)
Windows 10

Method

Mesh Loop

Use Mesh Loop to get UV and vertex data.

In unfolded UV, the correspondence between the point of UV map and the vertex of 3D object is not one-to-one. Thus we use ‘Mesh Loop’ instead of vertex or edge to distinct point of UV map.

Mesh Loop is an element surrounding a face, which consists of edges and vertices. Each quad face consists of 4 Mesh Loops as below. For example, cube objects have 6face, 24 mesh loops.

import bpy

obj = bpy.data.objects[obj_name]
mesh_loops = obj.data.loops 
for mesh_loop in mesh_loops:
    print(mesh_loop)

Mesh UV Loop

UVs have Mesh UV Loops as a counterpart to the Mesh Loops. And the correspondence between Mesh Loop and MeshUVLoop is one-to-one.

import bpy

obj = bpy.data.objects[obj_name]
mesh_uv_loop = obj.data.uv_layers[0].data[loop_index]

Source Code

import bpy

def get_uvs(obj_name):
    obj = bpy.data.objects[obj_name]
    mesh_loops = obj.data.loops

    for i, mesh_loop in enumerate(mesh_loops):
        mesh_uv_loop = obj.data.uv_layers[0].data[i]
        print("uv:", mesh_uv_loop.uv[0], mesh_uv_loop.uv[1], "vertex id:", mesh_loop.vertex_index)

get_uvs("Cube")

How To Import Another Blender File

GOAL

Today’s goal is to show how to import data from another blender file.

We can import .fbx, .obj and so on by “menu File>import”, but how can we import .blend file to current scene?

The way to import fbx file

I have 2 blender scene and want to import scene_from.blend to scene_to.blend directly.

Environment

Blender2.83(LTS)
Windows 10

Method

Click File>Append

Double click the scene you want to import. Then select what you want. In my case, I imported collection that contains all objects.

Result of “Append”

The objects in scene_from.blend is imported to scene_to.blend with their materials.

Supplement

Link

You can use File>Link too, but the result is different.

Result of “Link”

You can’t modify linked objects in scene_to.blend. If you’d like to modify the object, change the scene_from.blend.

Blender Addon Naming Rules

GOAL

Today’s goal is to list naming rules and conventions of Blender addon.

Reference:
AddonPreferences(bpy_struct) from Blender 2.93.2 Release Candidate Python API documentation
Script Meta Info from wiki.blender.org

Environment

Blender 2.83 (Python 3.7.4)
Windows10

directory_name and file_name.py

Addon directory and files are snake_case with only lower cases. See examples in your addon directory, C:/Program Files/Blender Foundation/Blender 2.83/2.83/scripts/addons.

Addon Name

Addon name defined in bl_info is defined with the first letter of each word capitalized.

Class Name

2.8x enforces naming conventions for class name. Refer to “Class Registration” > “Naming” in “Blender 2.80: Addon API” reference for details.

The naming convention is UPPER_CASE_{SEPARATOR}_mixed_case. And {SEPARATOR} is defined according to the type of class as below.

  • Header -> _HT_
  • Menu -> _MT_
  • Operator -> _OT_
  • Panel -> _PT_
  • UIList -> _UL_

The followings are examples of panel class name.

# Header
# from "oscurart_tools" addon
class OSSELECTION_HT_OscSelection(bpy.types.Header):
    bl_label = "Selection Osc"
    bl_space_type = "VIEW_3D"

# Menu
# from "space_view3d_spacebar_menu" addon
class VIEW3D_MT_Space_Dynamic_Menu(Menu):
    bl_label = "Dynamic Context Menu"

class VIEW3D_MT_View_Menu(Menu):
    bl_label = "View"

# Operator
# from "add_camera_rigs" addon
class ADD_CAMERA_RIGS_OT_set_scene_camera(Operator):
    bl_idname = "add_camera_rigs.set_scene_camera"
    bl_label = "Make Camera Active"
    bl_description = "Makes the camera parented to this rig the active scene camera"

# Panels
# from "add_camera_rigs" addon
class ADD_CAMERA_RIGS_PT_camera_rig_ui(Panel, CameraRigMixin)
    bl_label = "Camera Rig"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Item'

# UIList
# from "cycles" addon
class CYCLES_RENDER_UL_aov(bpy.types.UIList):
    def draw_item(self, ...

 bl_idname

bl_idname is specified to access the operator from python script in Blender. The bl_idname consists of snake_case words connected with dots.

# bl_idname in cycle/operators.py in cycle addon

class CYCLES_OT_use_shading_nodes(Operator):
    bl_idname = "cycles.use_shading_nodes"

class CYCLES_OT_add_aov(bpy.types.Operator):
    bl_idname="cycles.add_aov"

class CYCLES_OT_remove_aov(bpy.types.Operator):
    bl_idname="cycles.remove_aov"

class CYCLES_OT_denoise_animation(Operator):
    bl_idname = "cycles.denoise_animation"

class CYCLES_OT_merge_images(Operator):
    bl_idname = "cycles.merge_images"

 For headers, menus and panels, the bl_idname is expected to match the class name (automatic if none is specified). Refer to “Class Registration” > “Naming” in “Blender 2.80: Addon API” reference.

Other – PEP 8

Basically the naming rules of module, variable and so on is compliant with PEP 8.

variable = "hello"
variable_two = 2

def function_name(arg_name):
    pass

class ClassName():
    def __init__(self, arg_name):
        self.variable = 1
    def method_name(self):
        pass

How To Use Human Meta-Rig in Rigify

GOAL

Today’s goal is to summarize the rigging method of Human Meta-Rig with Rigify addon in Blender.

I used a human model with MakeHuman.

Environment

Blender 2.83
Windows10

Method

1. Add Human meta rig

Activate addon “RIgging: Rigify” at first.

Import the model with Y-axis front.

Change the mode to “Object Mode” and click Add > Armature > Human(Meta-Rig).

Open metarig tab > Viewport Display and check “In Front” on to show the rig in front of all in the 3D View.

The human rig with “In Front” on

2. Adjust bones

Adjust rig size and locations of bone to fit the target mesh.
Don’t change the transforms of the object. Be sure to change transforms in “Edit Mode” not in “Object Mode“.

(more…)

How To Fix Texture Colored Pink In Blender

Problem

When I open Blender file, the textured model is rendered with pink single-colored texture. How can I fix it?

Texture node on Node Editor

Environment

Blender 2.8.3(LTS)
Windows10

Cause

Pink means missing texture. Blender couldn’t find the specified texture.

Solution

References: You can find solutions in the followings in most cases.
Why are all the textures in my file pink?
Pink textures in Blender and how to avoid them

However, this sometimes occurred when the texture is just overwritten. In that case, I fixed by following steps below.

1. Disconnect Image Texture Node from Base Color socket of Shader Node.

2. Reset texture in Image Texture Node on Node Editor

3. Reconnect Nodes

How To Make My Addon Support “Undo” In Blender

GOAL

Today’s goal is to implement “Undo” in my Blender addon.

Environment

Blender 2.83
Windows10

Method

Add bl_options “UNDO” or “UNDO_GROUPED” into the your custom operator. It’s easy.

UNDO Undo: Push an undo event (needed for operator redo).
UNDO_GROUPED: Grouped Undo, Push a single undo event for repeated instances of this operator.

from Blender2.93.2 Python API Documentation

The following is an example.

class ADDMATRIX_add_cube(bpy.types.Operator):
    bl_idname = 'add_matrix_obj.add_cube'
    bl_label = "Add matrix cube"
    bl_options = {'REGISTER', "UNDO"} # Add "UNDO" option here

    input1: bpy.props.IntProperty()
    input2: bpy.props.IntProperty()

    def execute(self, context):
        for xi in range(self.input1):
            x = xi*1.2
            for yi in range(self.input2):
                y = yi*1.2
                bpy.ops.mesh.primitive_cube_add(size=0.5, enter_editmode=False, align='WORLD', location=(x, y, 0))
        return {'FINISHED'}

Postscript

be aware of the error where Blender crashed when undo after executing script in python console. (Reference: Fix T86293: crash undoing after executing the python console in certain)

That was fixed in Blender 2.93, the latest version. And You can fix the error by adding bl_options “UNDO_GROUPED” into the ConsoleExec operation in C:/Program Files/Blender Foundation/Blender 2.83/2.83/scripts/startup/bl_operators/console.py.

class ConsoleExec(Operator):
    """Execute the current console line as a python expression"""
    bl_idname = "console.execute"
    bl_label = "Console Execute"
    bl_options = {"UNDO_GROUPED"} # add undo here

    interactive: BoolProperty(
        options={'SKIP_SAVE'},
    )

    @classmethod
    def poll(cls, context):
        return (context.area and context.area.type == 'CONSOLE')

How To Get Icon List In Blender

GOAL

Today’s goal is to show Icon Viewer that shows the list of icon we can use in Blender and use it.

Icon Viewer

Environment

Blender2.83(LTS)
Windows10

Method

1. Activate addon “Development Icon Viewer”

2. Open Icon Viewer

Open text Editor and click “Dev” tab.

Click on any icon you like and it’s name will be copied to the clipboard. Then paste it into your editor.

Examples

1. Operator button

def draw(self, context):
    layout = self.layout
    col = layout.column(align=True)
    col.operator("mesh.primitive_monkey_add", icon="MONKEY")

2. EnumProperty

class MyProp(bpy.types.PropertyGroup):
    items = [("id1", "name1", "description 1", "HELP", 0),
             ("id2", "name2", "description 2", "GHOST_ENABLED", 1),
             ("id3", "mame3", "description 3", "FUND", 2),]
    enum: bpy.props.EnumProperty(items=items)
def draw(self, context):
    layout = self.layout
    col = layout.column(align=True)
    col.prop(context.scene.MyProp, "enum")

How To Pass Arguments To Custom Operator In Blender Python

GOAL

Today’s goal is to create operator that takes arguments in Blender Python.

The following is a custom operator that takes 2 argument “count_x” and “count_y”, and add cube object in the form of count_x rows and count_y columns.

Environment

Blender 2.83(LTS)
Windows10

Method

1. Create operator with properties

Pass the argument values through the properties to custom operator. Use “:” to add property in Blender custom operator as below. Check “Operator Example” in Blender manual for details.

class ADDMATRIX_add_cube(bpy.types.Operator):
    bl_idname = 'add_matrix_obj.add_cube'
    bl_label = "Add matrix cube"
    bl_options = {'REGISTER', "UNDO"}

    input1: bpy.props.IntProperty() # add argument1 as property "input1"
    input2: bpy.props.IntProperty() # add argument2 as property "input2"

    def execute(self, context):
        for xi in range(self.input1):
            x = xi*1.2
            for yi in range(self.input2):
                y = yi*1.2
                bpy.ops.mesh.primitive_cube_add(size=0.5, enter_editmode=False, align='WORLD', location=(x, y, 0))
        return {'FINISHED'}

You can execute operator with passing values of arguments “input1” and “input2” as below.

(more…)

List Of Blender Properties

GOAL

Today’s goal is to list up property UI that can be used in Blender Addon.
Reference: Property Definitions

Environment

Blender 2.83(LTS)
Windows10

List of Properties

  • BoolProperty
  • BoolVectorProperty
  • CollectionProperty
  • EnumProperty
  • FloatProperty
  • FloatVectorProperty
  • IntProperty
  • IntVectorProperty
  • PointerProperty
  • StringProperty

How each property looks like

BoolProperty

bool: bpy.props.BoolProperty()

BoolVectorProperty

bool_vector: bpy.props.BoolVectorProperty()

subtypes of BoolVectorProperty

The UI style or label differs according to its subtype.

bool_vector_color: bpy.props.BoolVectorProperty(subtype='COLOR')
bool_vector_translation: bpy.props.BoolVectorProperty(subtype='TRANSLATION')
# and more...

CollectionProperty

UILayout.prop() just shows the number of CollectionProperty. (Use “template_list” to show the item list of CollectionProperty)

class PropertySetTest(bpy.types.PropertyGroup):
    test_int: bpy.props.IntProperty()
    test_string: bpy.props.StringProperty()
collection: bpy.props.CollectionProperty(type=PropertySetTest)

EnumProperty

items = [("id1", "name1", "description 1", "MESH_CUBE", 0),
         ("id2", "name2", "description 2", "MESH_TORUS", 1),
         ("id3", "mame3", "description 3", "CONE", 2),]
enum: bpy.props.EnumProperty(items=items)

FloatProperty

float: bpy.props.FloatProperty()

subtypes of FloatProperty

float_pixel: bpy.props.FloatProperty(subtype="PIXEL")
float_unsigned: bpy.props.FloatProperty(subtype="UNSIGNED")
# and more...

units of FloatProperty

float_none: bpy.props.FloatProperty(unit='NONE')
float_length: bpy.props.FloatProperty(unit='LENGTH')
# and more...

FloatVectorProperty

float_vector: bpy.props.FloatVectorProperty()

subtypes of FloatVectorProperty

units of FloatVectorProperty

IntProperty

subtypes of IntVectorProperty

IntVectorProperty

subtypes of FloatVectorProperty

PointerProperty

PointerProperty takes argument ‘type’ to set the type of pointer.

pointer_scene: bpy.props.PointerProperty(type=bpy.types.Scene)
pointer_object: bpy.props.PointerProperty(type=bpy.types.Object)
pointer_matarial: bpy.props.PointerProperty(type=bpy.types.Material)
pointer_mesh: bpy.props.PointerProperty(type=bpy.types.Mesh)
pointer_image: bpy.props.PointerProperty(type=bpy.types.Image)
pointer_brush: bpy.props.PointerProperty(type=bpy.types.Brush)
pointer_camera: bpy.props.PointerProperty(type=bpy.types.Camera)
pointer_light: bpy.props.PointerProperty(type=bpy.types.Light)

StringProperty

subtypes of FloatVectorProperty