Blender AI Wiki / Русский Поиск

СПРАВОЧНИК ПО API ОПЕРАЦИЙ С МЕШАМИ BLENDER

Низкоуровневый способ (без контекста) — ПРЕДПОЧТИТЕЛЬНО python import bpy import bmesh from mathutils import Vector

📚 Референсы 27 блоков кода обновлено 2026-10-02

Создание примитивов

bpy.ops (зависит от контекста)

# Требуется корректный контекст (view_layer, активный объект)
bpy.ops.mesh.primitive_cube_add(size=2, location=(0,0,0), rotation=(0,0,0))
bpy.ops.mesh.primitive_uv_sphere_add(radius=1, segments=32, ring_count=16)
bpy.ops.mesh.primitive_ico_sphere_add(radius=1, subdivisions=2)
bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=2, vertices=32, cap_ends=True)
bpy.ops.mesh.primitive_cone_add(radius1=1, radius2=0, depth=2, vertices=32)
bpy.ops.mesh.primitive_torus_add(
    major_radius=1, minor_radius=0.3,
    major_segments=48, minor_segments=12
)
bpy.ops.mesh.primitive_plane_add(size=2)
bpy.ops.mesh.primitive_grid_add(x_subdivisions=10, y_subdivisions=10, size=2)
bpy.ops.mesh.primitive_monkey_add(size=1)  # Suzanne

Низкоуровневый способ (без контекста) — ПРЕДПОЧТИТЕЛЬНО

import bpy
import bmesh
from mathutils import Vector

def create_cube(name="Cube", size=2, location=(0,0,0)):
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)
    obj.location = location
    
    bm = bmesh.new()
    bmesh.ops.create_cube(bm, size=size)
    bm.to_mesh(mesh)
    bm.free()
    return obj

def create_uv_sphere(name="Sphere", radius=1, segments=32, ring_count=16):
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)
    
    bm = bmesh.new()
    bmesh.ops.create_uvsphere(bm, radius=radius, u_segments=segments, v_segments=ring_count)
    bm.to_mesh(mesh)
    bm.free()
    return obj

def create_cylinder(name="Cylinder", radius=1, depth=2, vertices=32):
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)
    
    bm = bmesh.new()
    bmesh.ops.create_cone(bm, radius1=radius, radius2=radius, depth=depth, segments=vertices)
    bm.to_mesh(mesh)
    bm.free()
    return obj

Операции BMesh (эквивалент режима редактирования)

Подготовка

import bmesh

# BMesh в режиме объекта (создаёт новый меш)
bm = bmesh.new()
# ... операции ...
bm.to_mesh(mesh)
bm.free()

# BMesh в режиме редактирования (изменяет существующий)
bm = bmesh.from_edit_mesh(obj.data)
# ... операции ...
bmesh.update_edit_mesh(obj.data)

Операции с вершинами

# Создать вершины
v1 = bm.verts.new((0, 0, 0))
v2 = bm.verts.new((1, 0, 0))
v3 = bm.verts.new((0, 1, 0))

# Выделить / снять выделение
v1.select = True
bm.verts.ensure_lookup_table()

# Трансформация
v1.co = (2, 0, 0)
v1.co += Vector((0.1, 0, 0))

# Удаление
bm.verts.remove(v1)

Операции с рёбрами

# Создать ребро
e = bm.edges.new((v1, v2))

# Циклы рёбер
bmesh.ops.edge_loops(bm, edges=[e])

# Разделить рёбра
bmesh.ops.subdivide_edges(bm, edges=bm.edges, cuts=2)

# Скруглить рёбра
bmesh.ops.bevel(bm, geom=bm.edges, offset=0.1, segments=3, profile=0.5)

# Растворить рёбра
bmesh.ops.dissolve_edges(bm, edges=[e])

Операции с гранями

# Создать грань
f = bm.faces.new((v1, v2, v3))  # Треугольник
f = bm.faces.new((v1, v2, v3, v4))  # Четырёхугольник

# Свойства грани
f.select = True
f.material_index = 0
f.normal  # mathutils.Vector

# Экструзия
result = bmesh.ops.extrude_face_region(bm, geom=[f])
extruded_geom = result['geom']
# Переместить экструдированные грани
for elem in extruded_geom:
    if isinstance(elem, bmesh.types.BMFace):
        bmesh.ops.translate(bm, verts=elem.verts, vec=(0, 0, 1))

# Inset
bmesh.ops.inset_region(bm, faces=[f], thickness=0.1, depth=0.1)

# Poke (веер из треугольников)
bmesh.ops.poke(bm, faces=[f])

# Триангуляция
bmesh.ops.triangulate(bm, faces=bm.faces)

# Разделить грани
bmesh.ops.subdivide_edges(bm, edges=[e for f in bm.faces for e in f.edges], cuts=1)

Выделение и запросы

# Выделить всё
for v in bm.verts: v.select = True
for e in bm.edges: e.select = True
for f in bm.faces: f.select = True

# Получить выделенное
selected_verts = [v for v in bm.verts if v.select]
selected_edges = [e for e in bm.edges if e.select]
selected_faces = [f for f in bm.faces if f.select]

# По индексу
v = bm.verts[0]
e = bm.edges[0]
f = bm.faces[0]

# Таблицы поиска (обязательны после изменения топологии)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()

Модификаторы меша (BMesh)

# Remesh (воксельный)
bmesh.ops.remesh(bm, voxel_size=0.1, adaptivity=0.0)

# Сглаживание
bmesh.ops.smooth_vert(bm, verts=bm.verts, factor=0.5, iterations=10)

# Decimate
# Напрямую в bmesh нет — используйте модификатор или bpy.ops

# Удалить оторванные элементы
bmesh.ops.delete_loose(bm, dist=0.001)

Доступ к данным меша (bpy.data.meshes)

Чтение данных меша

mesh = obj.data

# Вершины
for v in mesh.vertices:
    v.co           # локальные координаты
    v.normal       # нормаль вершины
    v.groups       # группы вершин
    v.index        # индекс

# Рёбра
for e in mesh.edges:
    e.vertices     # (v1_idx, v2_idx)
    e.use_seam     # шов UV
    e.use_sharp    # острое ребро
    e.bevel_weight # вес Bevel

# Полигоны (грани)
for poly in mesh.polygons:
    poly.vertices        # индексы вершин
    poly.loop_indices    # индексы лупов
    poly.normal          # нормаль грани
    poly.center          # центр грани
    poly.area            # площадь грани
    poly.material_index  # индекс слота материала

# Лупы (данные на каждую пару «вершина-грань»)
for loop in mesh.loops:
    loop.vertex_index   # индекс вершины
    loop.normal         # нормаль лупа (для гладкого затенения)

# Слои UV
for uv_layer in mesh.uv_layers:
    for uv in uv_layer.data:
        uv.uv           # Vector (u, v)

# Цвета вершин
for vc_layer in mesh.vertex_colors:
    for vc in vc_layer.data:
        vc.color        # RGBA (0-1)

# Shape Keys
if mesh.shape_keys:
    for key in mesh.shape_keys.key_blocks:
        key.value = 0.5

Модификаторы (через API)

Добавление модификатора

mod = obj.modifiers.new("Subdivision", 'SUBSURF')
mod.levels = 2
mod.render_levels = 3
mod.subdivision_type = 'CATMULL_CLARK'  # 'SIMPLE'

mod = obj.modifiers.new("Bevel", 'BEVEL')
mod.width = 0.02
mod.segments = 3
mod.profile = 0.5
mod.limit_method = 'ANGLE'  # 'WEIGHT', 'VGROUP', 'NONE'
mod.angle_limit = 1.0472  # 60 градусов

mod = obj.modifiers.new("Array", 'ARRAY')
mod.count = 5
mod.use_relative_offset = True
mod.relative_offset_displace = (1.5, 0, 0)

mod = obj.modifiers.new("Mirror", 'MIRROR')
mod.use_axis = (True, False, False)
mod.use_bisect_axis = (True, False, False)

mod = obj.modifiers.new("Boolean", 'BOOLEAN')
mod.operation = 'DIFFERENCE'  # 'UNION', 'INTERSECT'
mod.object = other_obj
mod.solver = 'EXACT'  # 'FAST'

mod = obj.modifiers.new("Solidify", 'SOLIDIFY')
mod.thickness = 0.1
mod.offset = 0  # от -1 до 1
mod.use_even_offset = True

mod = obj.modifiers.new("Decimate", 'DECIMATE')
mod.ratio = 0.5  # 0.0-1.0
mod.decimate_type = 'COLLAPSE'  # 'UNSUBDIV', 'PLANNAR'

mod = obj.modifiers.new("Remesh", 'REMESH')
mod.mode = 'VOXEL'  # 'SMOOTH', 'SHARP'
mod.voxel_size = 0.1
mod.adaptivity = 0.0

Применение модификатора

# Один
bpy.ops.object.modifier_apply(modifier="Subdivision")

# Все
for mod in list(obj.modifiers):
    bpy.ops.object.modifier_apply(modifier=mod.name)

# Через Python (без контекста)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.modifier_apply(modifier=mod.name)

Булевы операции

Через модификатор (рекомендуется)

def boolean_union(obj_a, obj_b):
    mod = obj_a.modifiers.new("Bool", 'BOOLEAN')
    mod.operation = 'UNION'
    mod.object = obj_b
    mod.solver = 'EXACT'
    bpy.context.view_layer.objects.active = obj_a
    bpy.ops.object.modifier_apply(modifier="Bool")
    bpy.data.objects.remove(obj_b, do_unlink=True)
    return obj_a

def boolean_difference(obj_a, obj_b):
    mod = obj_a.modifiers.new("Bool", 'BOOLEAN')
    mod.operation = 'DIFFERENCE'
    mod.object = obj_b
    mod.solver = 'EXACT'
    bpy.context.view_layer.objects.active = obj_a
    bpy.ops.object.modifier_apply(modifier="Bool")
    bpy.data.objects.remove(obj_b, do_unlink=True)
    return obj_a

def boolean_intersect(obj_a, obj_b):
    mod = obj_a.modifiers.new("Bool", 'BOOLEAN')
    mod.operation = 'INTERSECT'
    mod.object = obj_b
    mod.solver = 'EXACT'
    bpy.context.view_layer.objects.active = obj_a
    bpy.ops.object.modifier_apply(modifier="Bool")
    bpy.data.objects.remove(obj_b, do_unlink=True)
    return obj_a

Развёртка UV

Базовая развёртка

# Smart UV Project (лучше для hard surface)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.smart_project(angle_limit=1.0472, island_margin=0.02)
bpy.ops.object.mode_set(mode='OBJECT')

# Lightmap Pack (для запекания)
bpy.ops.uv.lightmap_pack(PADDING=4, Px_MARGIN=4)

# Cube Projection
bpy.ops.uv.cube_project()

# Sphere Projection
bpy.ops.uv.sphere_project()

Развёртка по швам

bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')

# Пометить швы
for e in bmesh.from_edit_mesh(obj.data).edges:
    if e.calc_face_angle() > 1.0472:  # 60 градусов
        e.use_seam = True

bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001)
bpy.ops.object.mode_set(mode='OBJECT')

Манипуляция с UV

# Масштабировать UV
uv_layer = mesh.uv_layers.active
for uv in uv_layer.data:
    uv.uv *= 2.0

# Сдвинуть UV
for uv in uv_layer.data:
    uv.uv += (0.5, 0.5)

# Повернуть UV
import math
angle = math.pi / 4
for uv in uv_layer.data:
    u, v = uv.uv
    uv.uv = (u * math.cos(angle) - v * math.sin(angle),
             u * math.sin(angle) + v * math.cos(angle))

Группы вершин и веса

Создание и назначение

vg = obj.vertex_groups.new(name="GroupName")

# Назначить вершины с весом
vg.add([0, 1, 2, 3], 1.0, 'REPLACE')  # индексы вершин, вес, тип

# Получить вес
weight = vg.weight(vertex_index)

# Удалить
vg.remove([0, 1, 2])

Операции с группами вершин

# Нормализовать все группы для вершины
vg.normalize()

# Очистить (убрать нулевые веса)
vg.clean(0.001, 0.0, 0.0)

# Зеркалить (для симметричных ригов)
vg.mirror("GroupName.R", "GroupName.L", True)

# Копировать
new_vg = obj.vertex_groups.new(name="Copy")
for v in obj.data.vertices:
    try:
        w = vg.weight(v.index)
        new_vg.add([v.index], w, 'REPLACE')
    except RuntimeError:
        pass  # Вершина не входит в группу

Нормали и затенение

Автосглаживание

obj.data.use_auto_smooth = True
obj.data.auto_smooth_angle = 1.0472  # 60 градусов

Пользовательские нормали

# Задать пользовательские нормали
mesh = obj.data
mesh.use_auto_smooth = True
normals = []
for poly in mesh.polygons:
    for loop_idx in poly.loop_indices:
        normals.append(poly.normal)
mesh.normals_split_custom_set(normals)
mesh.use_auto_smooth = True

# Или по вершинам
mesh.normals_split_custom_set_from_vertices([v.normal for v in mesh.vertices])

Острые рёбра

# Пометить острыми
for e in mesh.edges:
    e.use_sharp = True  # Для автосглаживания

# Вес Bevel
for e in mesh.edges:
    e.bevel_weight = 1.0

Цвета вершин

Рисование через Python

# Создать слой
vc_layer = mesh.vertex_colors.new(name="Paint")

# Красить по граням
for poly in mesh.polygons:
    for loop_idx in poly.loop_indices:
        loop = mesh.loops[loop_idx]
        vc_layer.data[loop_idx].color = (1.0, 0.0, 0.0, 1.0)  # Красный

# Градиент по высоте
for poly in mesh.polygons:
    for loop_idx in poly.loop_indices:
        v = mesh.vertices[mesh.loops[loop_idx].vertex_index]
        h = (v.co.z - min_z) / (max_z - min_z)
        vc_layer.data[loop_idx].color = (h, h, h, 1.0)

Советы по производительности

Пакетные операции

# Использовать foreach для массового доступа к атрибутам
co_list = [0.0] * (len(mesh.vertices) * 3)
mesh.vertices.foreach_get("co", co_list)

# Изменить
for i in range(0, len(co_list), 3):
    co_list[i+2] += 0.1  # Поднять Z

# Записать обратно
mesh.vertices.foreach_set("co", co_list)
mesh.update()

Эффективное выделение

# Вместо цикла:
# for v in bm.verts: v.select = True

# Использовать:
bm.verts.ensure_lookup_table()
for v in bm.verts:
    v.select_set(True)  # или v.select = True

Избегайте bpy.ops в циклах

# ПЛОХО
for obj in objects:
    bpy.ops.object.modifier_apply(modifier="Subdivision")

# ХОРОШО — один override контекста
with bpy.context.temp_override(selected_objects=objects):
    bpy.ops.object.modifier_apply(modifier="Subdivision")

Общие паттерны

Создание меша по координатам

def create_mesh_from_vertices(name, vertices, faces):
    """vertices: [(x,y,z), ...], faces: [(v1,v2,v3), ...]"""
    mesh = bpy.data.meshes.new(name)
    mesh.from_pydata(vertices, [], faces)
    mesh.update()
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)
    return obj

# Использование
verts = [(0,0,0), (1,0,0), (0,1,0), (1,1,0)]
faces = [(0,1,3,2)]  # Четырёхугольник
obj = create_mesh_from_vertices("Quad", verts, faces)

Дублирование и разделение

# Дублировать объект + меш
new_obj = obj.copy()
new_obj.data = obj.data.copy()
bpy.context.collection.objects.link(new_obj)

# Отделить оторванные части (режим редактирования)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.separate(type='LOOSE')
bpy.ops.object.mode_set(mode='OBJECT')

Преобразование в меш

# Преобразовать кривую/текст/мета-объект в меш
bpy.context.view_layer.objects.active = obj
bpy.ops.object.convert(target='MESH')

🎯 ЦЕЛЬ

Референс категории «Референсы», сложность —.


🔗 СВЯЗИ

Связанные материалы

Подобраны по тегам и категории.