Blender > Дополнения, скрипты

Совсем не страшный питон.

(1/10) > >>

LanuHum:
Многие думают, что для того, чтобы мало помалу начать писать скрипты, нужно очень много изучить теории.
Сам я мало знаю теории, далеко не ас в программировании, как некоторые из присутствующих здесь на сайте, но кое-что могу и другим могу показать.
Питон в блендере - это не страшное животное, и его изучение может стать весьма интересным и полезным.
Итак, для начала вооружимся несколькими основными понятиями в языке программирования Python.

1. Код в обязательном порядке пишется на латинице за исключением названий объектов, материалов, текстур и прочих имён.

2. Всё, что пишется на одной строке после символа "#" - комментарий, который так же может быть написан на любом языке.
 Комментарий для исполнения программы не нужен. Его вы оставляете, чтобы помнить, зачем та или иная часть кода.

3. Переменные.
Это то, что несёт информацию от пользователя и применяется для вычислений.
Значения их могут меняться по ходу пьесы.
Переменная должна быть объявлена до действий над ней.(Чуть ниже в п 6.1 это будет понятно)
Пример переменных:

--- Код: ---a = 10          # Целое число
b = "Cube"      # Строка
c = 10.0        # Число с плавающей запятой
с = float(a)    # Превращает целое число в число с плавающей запятой
a = int(c)      # Округляет число с плавающей запятой до целого числа
--- Конец кода ---

4. Арифметика.

--- Код: ---d = a / c   # Разделить
e = a * c   # Умножить
g = a + c   # Сложить
h = a - c   # Вычесть
i = a ** c  # а возвести в степень с
--- Конец кода ---

5. Отступы. Если строчка заканчивается символом ":" (двоеточием), то начало следующей строчки должно быть смещено от начала строчки,
 в которой находится символ ":" на четыре отступа вправо.
Пример:

--- Код: ---if a > b:
    break
--- Конец кода ---
Это так же относится и к строчкам имеющим комментарий.
Пример:

--- Код: ---if a > b: # если a > b, то прекращаем цикл
    break
--- Конец кода ---

6. Ключевые слова. Это служебные слова, которые нельзя применять в обозначениях переменных.
В текстовом редакторе Блендера есть кнопка, включающая подсветку синтаксиса.
Если вы напишете

--- Код: ---k = a * g 
--- Конец кода ---
а ниже напишете

--- Код: ---float = i / e
--- Конец кода ---
то увидите, что float отличается цветом от k. Это значит, что слово float ключевое, и его необходимо заменить на любое другое, не отличающееся цветом от k

6.1 Ключевые слова if, elif, else, or, and задают условия. Часто при этом используются сравнения. Заданное условие заканчивается двоеточием

--- Код: ---c = 0 # Вспоминаем пункт 3 и заблаговременно объявляем переменные
g = 6
m = 100
if a == b:                  # Задаём условие: если (if) a равно(==) b 
    c = 1                   # То с равно(=) одному (не забываем про отступ и не путаем равенство со сравнением:
                            # если сравниваем, то ==, если присваиваем значение переменной, то =)   
elif a != b and b > 0:      # Продолжаем задавать условие: или если (elif) a не равно(!=) b и(and) b больше(>) нуля(0)
    с = 2                   # То с равно двум (не забываем про отступ)
elif a < g or a > m:        # Продолжаем задавать условие: или если (elif) a меньше(<), чем g или(or) а больше(>) чем m
    c = 3                   # То с равно трём  (не забываем про отступ)
else:                       # В противном случае, если ни одно условие не удовлетворилось (else)
    c = 4               # То с равно четырём
 
--- Конец кода ---
 
Другие сравнения:
a <= b    # а меньше или равно
a >= b    # а больше или равно

6.2 Ключевые слова for, in, range, break
Если нужно выполнить несколько однотипных действий запускается цикл.
Пример:

--- Код: ---a = 4
b = a ** 3
c = 5
for i in range(a,b):    # ключевое слово for запускает цикл: по порядку от а до b (i здесь переменная, значение которой с каждым проходом увеличивается на 1)
    с = (с + 3) / i           # к с прибавить 3 и разделить это на i
--- Конец кода ---
Понятно, что первый раз с будет равно (5 + 3)/4, то бишь 2, второй раз с будет равно (2 + 3)/5, то бишь 1, третий раз (1 + 3)/6, то бишь 0,666666666667 и так далее...

--- Код: ---a = 4
b = a ** 3
c = 5
for i in range(a,b):    # ключевое слово for запускает цикл: по порядку от а до b (i здесь переменная, значение которой с каждым проходом увеличивается на 1)
    с = (с + 3) / i           # к с прибавить 3 и разделить это на i
    if c == 0.001:
        break     # Прекратить цикл

--- Конец кода ---
7. Подключаемые модули. Сегодня random и bpy

--- Код: ---import random
a = random.random()         # Для переменной а генерируется случайное значение от нуля до одного
a = random.randint(1,10)    # Для переменной а генерируется случайное целое значение от одного до десяти
--- Конец кода ---

На первый раз мы много узнали и ничего не поняли бы, если бы не узнали кое-что про наш родной модуль bpy, связывающий Блендер с Питоном
Итак, первая заветная строчка нашего первого скрипта - это подключение нашего родимого модуля

--- Код: ---import bpy
--- Конец кода ---
Активные элементы -
--- Код: ---bpy.context
--- Конец кода ---
Определяем нужные так:

--- Код: ---scn = bpy.context.scene
ob = bpy.context.object
--- Конец кода ---
Из вышесказанного понимаем, что scn и ob - это переменные, а называем мы их так, чтобы приблизительно помнить, что есть что
Варианты sc, sce, obj, да какие угодно
Важно знать, что многие манипуляции над объектами производятся когда они либо активны

--- Код: ---scn.objects.active = ob
--- Конец кода ---
либо выделены

--- Код: ---ob.select = True
--- Конец кода ---
Напротив, чтобы объект остался нетронутым с него неплохо было бы снять выделение:

--- Код: ---ob.select = False
--- Конец кода ---
Создадим стенку из кирпичей, не используя array, чтобы кирпичи легли с небольшой неравномерностью.
Для этого поищем нужные операторы пройдя в меню Help > Operator Cheat Sheet. Кликнув,
мы создадим текстовой блок, который сможем отыскать в текстовом редакторе Блендера.
В строчках, начинающихся с bpy.ops поищем что-нибудь про bpy.ops.object и bpy.ops.transform. Ура! Здесь всё есть, что нам нужно!
Пишем скрипт зная, что у операторов Блендера переменные в скобках - по умолчанию, поэтому употребляем их, только, если наши значения с ними не совпадают:

--- Код: ---import bpy
import random
ob=bpy.context.object
for y in range(0,10):  # Цикл! Десять кирпичей в ряд!
    for z in range(0,5): # Цикл! Пять рядов!
        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')  # Копируем выделенный объект
        bpy.ops.transform.translate(value=(0, (y*2)+(y/10), (z*2)+(z/10))) # Перемещаем копию первый раз на длину одного кирпича плюс шов, далее на два и так далее...
        if z % 2 != 0:  # Если ряд нечётный
            bpy.ops.transform.translate(value=(0, 1, 0)) # сдвигаем кирпич ещё на полкирпича
        scale=random.randint(1,5)  # Задаём случайный масштаб
        bpy.ops.transform.resize(value=(1-(scale/10), 1, 1)) # Масштабируем по оси X
        angle=random.random()/10   # Задаём случайный угол
        bpy.ops.transform.rotate(value=angle, axis=(1, 1, 1))  # Вращаем по все осям
        obj=bpy.context.object # Определяем активный объект. После копирования им становится новый
        obj.select=False # Снимаем выделение с активного объекта
        bpy.context.scene.objects.active=ob # Делаем активным исходный объект, который мы взялись копировать
        ob.select=True  # Выделяем его, чтобы следующий проход цикла скопировал, именно, его, и от его координат разместил следующую копию
--- Конец кода ---

[вложение удалено Администратором]

bdancer:
В примере лучше сдвигать кирпичи используя ob.dimensions (который bounding box), иначе придется менять скрипт, подгоняя параметры, если размеры кирпича изменятся:

--- Код: ---import bpy
import random

ob = bpy.context.object

obX = ob.dimensions[0]
obY = ob.dimensions[1]
obZ = ob.dimensions[2]

# Цикл! Десять кирпичей в ряд!
for y in range(0,10):
    # Цикл! Пять рядов!
    for z in range(0,5):
        # Копируем выделенный объект
        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')

        # Перемещаем копию первый раз на длину одного кирпича плюс шов, далее на два и так далее...
        bpy.ops.transform.translate(value=(0.0, y * obY, z * obZ))
       
        # Если ряд нечётный
        if z % 2 != 0:
            # сдвигаем кирпич ещё на полкирпича
            bpy.ops.transform.translate(value=(0.0, obY / 2.0, 0.0))

--- Конец кода ---

sungreen:
... добавлю как этим пользоваться и как это выглядит :)  ...
... вот мувик ...
out 27



ps отец всегда говорил, что кирпич в кладке не главное, раствор - главное, он связывает, он держит ...

LanuHum:

--- Цитировать ---... добавлю как этим пользоваться и как это выглядит :)  ...
--- Конец цитаты ---
Он же не дописал до конца.  :) :) :)
 Там как раз проводится переназначение. Если этого ни сделать, то смещение как раз будет производиться ни от изначального, а от последнего продублированного.

Ну, расскажу сегодня про startswith.
Как нам быть, если нам нужно выделить только копии? Блендер копированным объектам присваивает то же название, но только с числовым индексом. Это очень хорошо, поскольку у Питона есть функция позволяющая сравнивать имена по их первым символам. Как это выглядит, мы увидим на примере созданных кирпичиков.
Давайте теперь снимем фаски на каждом кирпиче так же с небольшими отклонениями от определённой величины.
Теперь context.object нас не спасёт. Мы будем обращаться к общей базе данных
bpy.data.objects


--- Код: ---import bpy
import random
scene=bpy.context.scene
bpy.ops.object.select_all(action='DESELECT')  # Обязательно снимаем выделение со всех объектов, чтобы в дальнейшем цикл смог выделять их по одному и обрабатывать.
for ob in bpy.data.objects:    # По объекту в базе данных
    if ob.type == "MESH" and ob.name.startswith("Cube"):  # Если тип объекта Mesh и начало имени объекта "Cube"
        ob.select=True    # Выделяем объект
        scene.objects.active = ob  # Делаем его активным
        bpy.ops.object.mode_set(mode="EDIT")  # Переходим в режим редактирования меша, чтобы получить доступ к фейсам
        delta = 0.03+random.random()/10   # Задаём случайную величину фаски
        bpy.ops.mesh.bevel(offset_type='OFFSET', offset=delta, segments=1, profile=0.5, vertex_only=False)  # Применяем bevel, где назначаем offset
        bpy.ops.object.mode_set(mode="OBJECT")  # Переходим в объектный режим, чтобы дать возможность циклу работать со следующим объектом
        ob.select = False  # Снимаем выделение с объекта, чтобы следующий объект выделился один одинёшенек.

--- Конец кода ---
:)


[вложение удалено Администратором]

LanuHum:
Ну, вот нам подкинули темку. Попробуем произвести рендер анимации, где анимироваться будут даже слои.
Разумеется, написанного выше будет очень недостаточно.
Нам нужно погуглить и отыскать руководство по пользованию модулем os
Нам нужно подключить аддон api-navigator, что в разделе development. Этот аддон помогает отыскивать пути к крутилкам, которыми мы пользуемся, используя мышку и клавиатуру. При наведении на крутилки вплывают подсказки, указывающие, цели, а навигатор напишет нам правильно путь.
Теперь прикинем, что мы будем писать в операторе:

--- Код: ---import os
import bpy
scn=bpy.context.scene
start=scn.frame_start
end=scn.frame_end
format=scn.render.image_settings.file_format.lower()
for i in range(start,end):
    scn.frame_set(i,0.0)
    scn.layers[0]=scn.lay_anim_0
    scn.layers[1]=scn.lay_anim_1
    scn.layers[2]=scn.lay_anim_2
    scn.layers[3]=scn.lay_anim_3
    scn.layers[4]=scn.lay_anim_4
    scn.layers[5]=scn.lay_anim_5
    scn.layers[6]=scn.lay_anim_6
    scn.layers[7]=scn.lay_anim_7
    scn.layers[8]=scn.lay_anim_8
    scn.layers[9]=scn.lay_anim_9
    scn.layers[10]=scn.lay_anim_10
    scn.layers[11]=scn.lay_anim_11
    scn.layers[12]=scn.lay_anim_12
    scn.layers[13]=scn.lay_anim_13
    scn.layers[14]=scn.lay_anim_14
    scn.layers[15]=scn.lay_anim_15
    scn.layers[16]=scn.lay_anim_16
    scn.layers[17]=scn.lay_anim_17
    scn.layers[18]=scn.lay_anim_18
    scn.layers[19]=scn.lay_anim_19
    scn.update()
    bpy.ops.render.render('INVOKE_REGION_WIN')
    image = bpy.data.images["Render Result"]
    filepath = "/tmp/RenderResult_%s.%s"%(i,format)
    if os.path.exists(filepath):
        os.remove(filepath)
    image.save_render(filepath=filepath, scene=None)

--- Конец кода ---
А, завтра, попробуем закончить. :)

Навигация

[0] Главная страница сообщений

[#] Следующая страница

Перейти к полной версии