Симуляции

В этом разделе мы обращаемся к потенциалу симуляций Блендера из Питона. Некоторые из примеров были вдохновлены книгой Bounce, Tumble and Splash Тони Муллена (ищите в Сети великолепный перевод от Morthan'а, пользуясь случаем, передаю ему большое СПАСИБО! - прим. пер.). Однако, большинство рендеров не выглядят так же хорошо, как в книге Муллена, так как целью этих заметок не было найти оптимальный способ для настройки параметров, а скорее чтобы показать, как их можно настраивать из Питона.


Частицы

Эта программа добавляет две системы частиц.



#--------------------------------------------------- 

# File particle.py 

#--------------------------------------------------- 

import bpy, mathutils, math 

from mathutils import Vector, Matrix 

from math import pi  


def run(origo): 

   # Добавление меша эмиттера

   origin = Vector(origo)

   bpy.ops.mesh.primitive_plane_add(location=origin)

   emitter = bpy.context.object  


   # --- Система частиц 1: Падение и сдувание капель ---  


   # Добавление первой системы частиц

   bpy.ops.object.particle_system_add()

   psys1 = emitter.particle_systems[-1]

   psys1.name = 'Drops'  


   # Эмиссия, испускание

   pset1 = psys1.settings

   pset1.name = 'DropSettings'

   pset1.frame_start = 40

   pset1.frame_end = 200

   pset1.lifetime = 50

   pset1.lifetime_random = 0.4

   pset1.emit_from = 'FACE'

  pset1.use_render_emitter = True

   pset1.object_align_factor = (0,0,1)  


   # Физика

   pset1.physics_type = 'NEWTON'

   pset1.mass = 2.5

   pset1.particle_size = 0.3

   pset1.use_multiply_size_mass = True  


   # Веса эффекторов

   ew = pset1.effector_weights

   ew.gravity = 1.0

   ew.wind = 1.0  


   # Дочерние частицы

   pset1.child_nbr = 10

   pset1.rendered_child_count = 10

   pset1.child_type = 'SIMPLE'  


   # Отображение и рендер

   pset1.draw_percentage = 100

   pset1.draw_method = 'CROSS'

   pset1.material = 1

   pset1.particle_size = 0.1

   pset1.render_type = 'HALO'

   pset1.render_step = 3  


   # ------------ Эффектор ветра -----  


   # Добавление эффектора ветра

   bpy.ops.object.effector_add(

     type='WIND',

     enter_editmode=False,

     location = origin - Vector((0,3,0)),

     rotation = (-pi/2, 0, 0))

   wind = bpy.context.object  


   # Настройки полей

   fld = wind.field

   fld.strength = 2.3

   fld.noise = 3.2

   fld.flow = 0.3  


   # --- Система частиц 2: Обезьяны на ветру ----  


   # Добавление обезьяны, используемой как объект размножения 

   # Скрытие обезьяны в слое 2

   layers = 20*[False]

   layers[1] = True

   bpy.ops.mesh.primitive_monkey_add(

     location=origin+Vector((0,5,0)),

     rotation = (pi/2, 0, 0),

     layers = layers)

   monkey = bpy.context.object  


   #Добавление второй системы частиц

   bpy.context.scene.objects.active = emitter

   bpy.ops.object.particle_system_add()

   psys2 = emitter.particle_systems[-1]

   psys2.name = 'Monkeys'

   pset2 = psys2.settings

   pset2.name = 'MonkeySettings'  


   # Эмиссия, испускание

   pset2.count = 4

   pset2.frame_start = 1

   pset2.frame_end = 50

   pset2.lifetime = 250

   pset2.emit_from = 'FACE'

   pset2.use_render_emitter = True  


   # Скорость

   pset2.factor_random = 0.5  


   # Физика

   pset2.physics_type = 'NEWTON'

   pset2.brownian_factor = 0.5  


   # Веса эффекторов

   ew = pset2.effector_weights

   ew.gravity = 0

   ew.wind = 0.2  


   # Дочерние частицы

   pset2.child_nbr = 1

   pset2.rendered_child_count = 1

   pset2.child_size = 3

   pset2.child_type = 'SIMPLE'  


   # Отображение и рендер

   pset2.draw_percentage = 1

   pset2.draw_method = 'RENDER'

   pset2.dupli_object = monkey

   pset2.material = 1

   pset2.particle_size = 0.1

   pset2.render_type = 'OBJECT'

   pset2.render_step = 3


   return  


if __name__ == "__main__":

   bpy.ops.object.select_by_type(type='MESH')

   bpy.ops.object.delete()

   run((0,0,0))

   bpy.ops.screen.animation_play(reverse=False, sync=False)


Волосы

Эта программа добавляет сферу с волосами. Для волос строится шейдер типа strand.



#--------------------------------------------------- 

#
 File hair.py 

#--------------------------------------------------- 

import bpy  


def createHead(origin): 

# Добавление меша эмиттера

bpy.ops.mesh.primitive_ico_sphere_add(location=origin)

 ob = bpy.context.object

 bpy.ops.object.shade_smooth()  


   # Создание группы вершин
 scalp (скальп), а также добавление вершин и весов

   scalp = ob.vertex_groups.new('Scalp')

   for v in ob.data.vertices:

     z = v.co[2]

     y = v.co[1]

     if z > 0.3 or y > 0.3:

       w = 2*(z-0.3)

       if w > 1:

         w = 1

       scalp.add([v.index], w, 'REPLACE')

   return ob  


def createMaterials(ob): 

   # Некоторый материал для кожи

   skinmat = bpy.data.materials.new('Skin')

   skinmat.diffuse_color = (0.6,0.3,0)  


   # Материал strand для волос

   hairmat = bpy.data.materials.new('Strand')

   hairmat.diffuse_color = (0.2,0.04,0.0)

   hairmat.specular_intensity = 0  


   # Прозрачность

   hairmat.use_transparency = True

   hairmat.transparency_method = 'Z_TRANSPARENCY'

   hairmat.alpha = 0  


   # Strand. Нужно включить use Blender units перед заданием разм
еров.

   strand = hairmat.strand

   strand.use_blender_units = True

   strand.root_size = 0.01

   strand.tip_size = 0.0025

   strand.size_min = 0.001 

   #strand.use_surface_diffuse = True 
# read-only

   strand.use_tangent_shading = True  


   # Текстура

   tex = bpy.data.textures.new('Blend', type = 'BLEND')

   tex.progression = 'LINEAR'

   tex.use_flip_axis = 'HORIZONTAL'  


   # Создание цветовой полосы для цвета и альфа-канала

   tex.use_color_ramp = True

   tex.color_ramp.interpolation = 'B_SPLINE' 

   # Точки на цветовой полосе: (pos, rgba) 

   # Не знаю, как добавлять точки на полосу

   rampTable = [

     (0.0, (0.23,0.07,0.03,0.75)), 

     #(0.2, (0.4,0.4,0,0.5)), 

     #(0.7, (0.6,0.6,0,0.5)),

     (1.0, (0.4,0.3,0.05,0))

   ]

   elts = tex.color_ramp.elements

   n = 0

   for (pos, rgba) in rampTable:

     elts[n].position = pos

    elts[n].color = rgba

     n += 1  


   # Добавление текстуры blend к hairmat

   mtex = hairmat.texture_slots.add()

   mtex.texture = tex

   mtex.texture_coords = 'STRAND'

   mtex.use_map_color_diffuse = True

   mtex.use_map_alpha = True  


   # Добавление материала к мешу

   ob.data.materials.append(skinmat) 
# Material 1 = Skin

   ob.data.materials.append(hairmat) 
# Material 2 = Strand

   return  


def createHair(ob): 

   # Создание системы частиц hair

   bpy.ops.object.particle_system_add()

   psys = ob.particle_systems.active

   psys.name = 'Hair' 

   # psys.global_hair = True

   psys.vertex_group_density = 'Scalp'


    pset = psys.settings

   pset.type = 'HAIR'

   pset.name = 'HairSettings'  


   # Эмиссия

   pset.count = 40

   pset.hair_step = 7

   pset.emit_from = 'FACE'  


   # Рендер

   pset.material = 2

  pset.use_render_emitter = True

   pset.render_type = 'PATH'

   pset.use_strand_primitive = True

   pset.use_hair_bspline = True  


   # Дочерние частицы

   pset.child_type = 'SIMPLE'

   pset.child_nbr = 10

   pset.rendered_child_count = 500

   pset.child_length = 1.0

   pset.child_length_threshold = 0.0


    pset.child_roundness = 0.4

   pset.clump_factor = 0.862

   pset.clump_shape = 0.999


    pset.roughness_endpoint = 0.0

   pset.roughness_end_shape = 1.0

   pset.roughness_1 = 0.0

   pset.roughness_1_size = 1.0

   pset.roughness_2 = 0.0

   pset.roughness_2_size = 1.0

   pset.roughness_2_threshold = 0.0


    pset.kink = 'CURL'

   pset.kink_amplitude = 0.2

   pset.kink_shape = 0.0

   pset.kink_frequency = 2.0


   return  


def run(origin):

   ob = createHead(origin)

   createMaterials(ob)

   createHair(ob) return  


if __name__ == "__main__":

   bpy.ops.object.select_by_type(type='MESH')

   bpy.ops.object.delete()

   run((0,0,0))


Редактируемые волосы

Эта программа добавляет сферу с редактируемыми волосами от полученных направляющих (guides) волос. Если мы переключаемся в режим редактирования, все пряди становятся прямыми, то есть результат редактирования теряется. Это можно предотвратить, если вы переключитесь в режим частиц, выберите объект, и переключитесь обратно в режим объекта. К сожалению, я не нашел способа сделать это с помощью скрипта.



#--------------------------------------------------- 

# File edit_hair.py 

# Имеет недостатки, но может быть интересна в любом случае. 

#--------------------------------------------------- 

import bpy  


def createHead(): 

   # Добавление меша эмиттера

   bpy.ops.mesh.primitive_ico_sphere_add()

   ob = bpy.context.object

   ob.name = 'EditedHair'

   bpy.ops.object.shade_smooth()

   return ob  


def createHair(ob, guides):

   nGuides = len(guides)

   nSteps = len(guides[0])  


   # Создание системы частиц hair

   bpy.ops.object.mode_set(mode='OBJECT')

   bpy.ops.object.particle_system_add()

   psys = ob.particle_systems.active

   psys.name = 'Hair'  


   # Настройки частиц

   pset = psys.settings

   pset.type = 'HAIR'

   pset
.name = 'HairSettings'

   pset.count = nGuides

   pset.hair_step = nSteps-1

  pset.emit_from = 'FACE'

   pset.use_render_emitter = True  


   # Дочерние частицы

   pset.child_type = 'SIMPLE'

   pset.child_nbr = 6

   pset.rendered_child_count = 300

   pset.child_length = 1.0

   pset.child_length_threshold = 0.0  


   # Отсоединение волос и переключение в режим редактирования частиц

   bpy.ops.particle.disconnect_hair(all=True)

   bpy.ops.particle.particle_edit_toggle()  


   # Настройка всех ключевых волос

   dt = 100.0/(nSteps-1)

   dw = 1.0/(nSteps-1)

   for m in range(nGuides):

     guide = guides[m]

    part = psys.particles[m]

    part.location = guide[0]

    for n in range(1, nSteps):

      point = guide[n]

      h = part.hair_keys[n-1]

      h.co_hair_space = point

      h.time = n*dt

      h.weight = 1.0 - n*dw  


   # Переключение режима редактирования частиц

   bpy.ops.particle.select_all(action='SELECT')

   bpy.ops.particle.particle_edit_toggle()  


   # Подсоединение волос к мешу 

   # Во время рендера случится Segmentation violation, если эта строка отсутствует.

   bpy.ops.particle.connect_hair(all=True)  


   # К сожалению, здесь шаг действий вручную представляется необходимым: 

   # 1. Переключиться в режим частиц 

   # 2. Прикоснуться к объекту с кистью 

   # 3. Переключиться в режим объектов 

   # 4. Переключиться в режим редактирования 

   # 5. Переключиться в режим объектов 

   # Это должно соответствовать коду ниже, но терпит неудачу из-за 

   # неверного контекста

   '''

   bpy.ops.particle.particle_edit_toggle()

   bpy.ops.particle.brush_edit()

   bpy.ops.particle.particle_edit_toggle()

   bpy.ops.object.editmode_toggle()

   bpy.ops.object.editmode_toggle()

   '''

   return  


# Направляющие волос. Четыре волоса с пятью точками. 

hairGuides = [

   [(-0.334596,0.863821,0.368362),

   (-0.351643,2.33203,-0.24479),

   (0.0811583,2.76695,-0.758137),

   (0.244019,2.73683,-1.5408),

   (0.199297,2.60424,-2.32847)],

   [(0.646501,0.361173,0.662151),

   (1.33538,-0.15509,1.17099),

   (2.07275,0.296789,0.668891),

   (2.55172,0.767097,-0.0723231),

   (2.75942,1.5089,-0.709962)],

   [(-0.892345,-0.0182112,0.438324),

   (-1.5723,0.484807,0.971839),

   (-2.2393,0.116525,0.324168),

   (-2.18426,-0.00867975,-0.666435),

   (-1.99681,-0.0600535,-1.64737)],

   [(-0.0154996,0.0387489,0.995887),

   (-0.205679,-0.528201,1.79738),

   (-0.191354,0.36126,2.25417),

   (0.0876127,1.1781,1.74925),

   (0.300626,1.48545,0.821801)] ]  


def run(origin):

   ob = createHead()

   createHair(ob, hairGuides)

   ob.location = origin

   return 


if __name__ == "__main__":

   run((0,0,0))


Ткань

Эта программа добавляет плоскость с модификатором ткани. У плоскости есть родитель — обруч, который движется вниз, где она встречается с препятствием-сферой. Влияние модификатора ткани находится под контролем группы вершин, а это значит, что углы движутся с обручем, в то время как середина деформируется препятствием. Плоскости присваивается материал со стресс-отображением прозрачности.



#---------------------------------------------------------- 

# File cloth.py 

#---------------------------------------------------------- 

import bpy, mathutils, math from mathutils import Vector  


def run(origin):

   side = 4

   diagonal = side/math.sqrt(2)

   hoopRad = 0.1

   eps = 0.75

   nDivs = 40


   scn = bpy.context.scene  


   # Добавление сферы, выступающей в качестве объекта столкновения

   bpy.ops.mesh.primitive_ico_sphere_add(location=origin)

   sphere = bpy.context.object

   bpy.ops.object.shade_smooth()  


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

   bpy.ops.object.modifier_add(type='COLLISION')

   cset = sphere.modifiers[0].settings

   cset.thickness_outer = 0.2

   cset.thickness_inner = 0.5

   cset.permeability = 0.2

   cset.stickness = 0.2

   bpy.ops.object.modifier_add(type='SUBSURF')  


   # Добавление кольца

   center = origin+Vector((0,0,2))

   bpy.ops.mesh.primitive_torus_add(

     major_radius= diagonal + hoopRad,

     minor_radius= hoopRad,

     location=center,

     rotation=(0, 0, 0))

   bpy.ops.object.shade_smooth()

   ring = bpy.context.object  


   # Добавление плоскости над сферой и привязка её к кольцу

   bpy.ops.mesh.primitive_plane_add(location=(0,0,0))

   bpy.ops.transform.resize(value=(side/2,side/2,1))

   bpy.ops.object.mode_set(mode='EDIT')

   bpy.ops.mesh.subdivide(number_cuts=nDivs)

   bpy.ops.object.mode_set(mode='OBJECT')

   plane = bpy.context.object

   plane.parent = ring

   me = plane.data  


   # Создание группы вершин. Объект не должен быть активным?

   scn.objects.active = None

   grp = plane.vertex_groups.new('Group')

   for v in plane.data.vertices:

     r = v.co - center

     x = r.length/diagonal

     w = 3*(x-eps)/(1-eps)

     if w > 1:

       w = 1

     if w > 0:

       grp.add([v.index], w, 'REPLACE')  


   # Активация плоскости снова

   scn.objects.active = plane  


   # Добавление модификатора cloth (ткань)

   cloth = plane.modifiers.new(name='Cloth', type='CLOTH')

   cset = cloth.settings

   cset.use_pin_cloth = True

   cset.vertex_group_mass = 'Group' 

   # Настройки шёлка, скопировано из "scripts/presets/cloth/silk.py"

   cset.quality = 5

   cset.mass = 0.150

   cset.structural_stiffness = 5

   cset.bending_stiffness = 0.05

   cset.spring_damping = 0

   cset.air_damping = 1  


   # Сглаженное затенение

   plane.select = True

   bpy.ops.object.shade_smooth()

   bpy.ops.object.modifier_add(type='SUBSURF')  


   # Текстура Blend

   tex = bpy.data.textures.new('Blend', type = 'BLEND')

   tex.progression = 'SPHERICAL'

   tex.intensity = 1.0

   tex.contrast = 1.0

   tex.use_color_ramp = True

   elts = tex.color_ramp.elements

   elts[0].color = (0, 0, 0, 1)

   elts[0].position = 0.56

   elts[1].color = (1, 1, 1, 0)

   elts[1].position = 0.63  


   # материал Rubber (Резиновый)

   mat = bpy.data.materials.new('Rubber')

   mat.diffuse_color = (1,0,0)

   mat.use_transparency = True

   mat.alpha = 0.25


   mtex = mat.texture_slots.add()

   mtex.texture = tex

   mtex.texture_coords = 'STRESS'

   mtex.use_map_color_diffuse = True

   mtex.diffuse_color_factor = 0.25

   mtex.use_map_alpha = True

   mtex.alpha_factor = 1.0

   mtex.blend_type = 'ADD'  


   # Добавление материала к плоскости

   plane.data.materials.append(mat)  


   # Анимация кольца

   ring.location = center

   ring.keyframe_insert('location', index=2, frame=1)

   ring.location = origin - Vector((0,0,0.5))

   ring.keyframe_insert('location', index=2, frame=20)

   ring.location = center


   return  


if __name__ == "__main__":

   bpy.ops.object.select_by_type(type='MESH')

   bpy.ops.object.delete()

   run(Vector((0,0,0)))

   scn = bpy.context.scene

   scn.frame_current = 1

   bpy.ops.screen.animation_play()


Мягкие тела

Эта программа добавляет конус с модификатором softbody (мягкое тело) и плоскость-препятствие.



#---------------------------------------------------------- 

# File softbody.py 

#---------------------------------------------------------- 

import bpy

import mathutils 

from mathutils import Vector  


def run(origin): 

   # Добавление материала

   red = bpy.data.materials.new('Red')

   red.diffuse_color = (1,0,0)

   blue = bpy.data.materials.new('Blue')

   blue.diffuse_color = (0,0,1)  


   # Добавление конуса

   bpy.ops.mesh.primitive_cone_add(

     vertices=4,

     radius=1.5,

     cap_end=True)

   ob1 = bpy.context.object

   me1 = ob1.data

   bpy.ops.object.mode_set(mode='EDIT')

   bpy.ops.mesh.subdivide(number_cuts=5, smoothness=1, fractal=1)

   bpy.ops.object.mode_set(mode='OBJECT')  


   # Странно, нужен новый меш, который является копией

   verts = []

   faces = []

   for v in me1.vertices:

     verts.append(v.co)

   for f in me1.faces:

    faces.append(f.vertices)

   me2 = bpy.data.meshes.new('Drop')

   me2.from_pydata(verts, [], faces)

   me2.update(calc_edges=True)  


   # Установка гладкости граням (smooth)

   for f in me2.faces: f.use_smooth = True  


   # Добавление нового объекта и его активация

   ob2 = bpy.data.objects.new('Drop', me2)

   scn = bpy.context.scene

   scn.objects.link(ob2)

   scn.objects.unlink(ob1)

   scn.objects.active = ob2  


   # Добавление групп вершин

   top = ob2.vertex_groups.new('Top')

   bottom = ob2.vertex_groups.new('Bottom')

   for v in me2.vertices:

     w = v.co[2] - 0.2

     if w < 0:

       if w < -1:

        w = -1

       bottom.add([v.index], -w, 'REPLACE'
)

     elif w > 0:

       if w > 1:

         w = 1

       top.add([v.index], w, 'REPLACE')

   bpy.ops.object.mode_set(mode='OBJECT')

   ob2.location = origin

   me2.materials.append(blue)  


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

   mod = ob2.modifiers.new(name='SoftBody', type='SOFT_BODY')

   sbset = mod.settings  


   # Мягкое тело

   sbset.friction = 0.6

   sbset.speed = 0.4

   sbset.mass = 8.1  


   # Цель

   sbset.goal_default = 0.7

   sbset.goal_spring = 0.3

   sbset.goal_friction = 0.0

   sbset.vertex_group_goal = 'Top'  


   # Края мягкого тела

   sbset.pull = 0.6

   sbset.push = 0.1

   sbset.bend = 0.1

   sbset.aerodynamics_type = 'LIFT_FORCE
'

  sbset.aero = 0.5  


   # Добавление вихря

   bpy.ops.object.effector_add(

      type='VORTEX',

      location=origin+Vector((0,0,-4)))

   vortex = bpy.context.object

   fset = vortex.field


   fset.strength = 4.5

   fset.shape = 'PLANE'

   fset.apply_to_location = False

   fset.apply_to_rotation = True

   fset.falloff_type = 'TUBE'  


   # Добавление плоскости столкновения 

   # Предупреждение. Столкновение объектов делает симуляцию очень медленной!

   bpy.ops.mesh.primitive_plane_add(

     location=origin-Vector((0,0,1.7)))

  bpy.ops.transform.resize(value=(4, 4, 4))

   plane = bpy.context.object

   plane.data.materials.append(red)

   mod
 = plane.modifiers.new(name='Collision', type='COLLISION')


  return  


if __name__ == "__main__":

   bpy.context.scene.frame_end = 600

   bpy.ops.object.select_all(action='SELECT')

   bpy.ops.object.delete()

   run(Vector((0,0,6)))

   bpy.ops.screen.animation_play() 

   #bpy.ops.render.opengl(animation=True)


Ткань, мягкие тела и текстуры displace

Эта программа показывает три различных метода размахивания флагом: модификатором ткани, модификатором мягких тел, и с помощью анимированных текстур смещения.



#---------------------------------------------------------- 

# File flags.py 

# Создает флаг из мягкого тела и флаг из ткани на ветру. 

# Update to API rev. 36816 

#---------------------------------------------------------- 

import bpy, mathutils, math 

from mathutils import Vector 

from math import pi 


# Размер флага, глобальные переменные 

xmax = 40

zmax = 24 

ds = 2.0/xmax  


def makeFlag(name, origin, invert): 

   # Добавление нового меша, который будет флагом


   me = bpy.data.meshes.new(name)

   flag = bpy.data.objects.new(name, me)

   scn = bpy.context.scene

   scn.objects.link(flag)

   scn.objects.active = flag  


   # Построение меша флага

   verts = []

   faces = []

   for x in range(xmax):

     for z in range(zmax):

       verts.append(((x+0.5)*ds, 0, z*ds))

       if x > 0 and z > 0:

         faces.append(((x-1)*zmax+(z-1), (x-1)*zmax+z, x*zmax+z, x*zmax+(z-1)))

   me.from_pydata(verts, [], faces)

   me.update(calc_edges=True)

   flag.location = origin  


   # Добавление групп вершин

   grp = flag.vertex_groups.new('Pole')

   for v in me.vertices:

     w = 1.5 - 7*v.co[0]

     if invert:

       if w > 1:

          grp.add([v.index], 0.0, 'REPLACE')

       else:

         grp.add([v.index], 1-w, 'REPLACE')

    else:

       if w > 1:

          grp.add([v.index], 1.0, 'REPLACE')

      elif w > 0:

         grp.add([v.index], w, 'REPLACE')


    bpy.ops.object.mode_set(mode='OBJECT')

   bpy.ops.object.shade_smooth()

   return flag  


def makePole(origin):

   bpy.ops.mesh.primitive_cylinder_add(

     vertices=32,

     radius=ds/2,

     depth=1,

    cap_ends=True)

   bpy.ops.transform.resize(value=(1, 1, 2.5))

   pole = bpy.context.object

   pole.location = origin

   return pole  


def addSoftBodyModifier(ob):

   mod = ob.modifiers.new(name='SoftBody', type='SOFT_BODY')

   sbset = mod.settings  


   # Мягкое тело

   sbset.friction = 0.3

   sbset.speed = 1.4

   sbset.mass = 0.9  


   # Цель

   sbset.goal_default = 0.3

   sbset.goal_spring = 0.1

   sbset.goal_friction = 0.1

   sbset.vertex_group_goal = 'Pole'  


   # Рёбра мягкого тела

   sbset.pull = 0.1

   sbset.push = 0.1

   sbset.bend = 0.1

   sbset.aerodynamics_type = 'LIFT_FORCE'

   sbset.aero = 0.5  


   #Веса эффектора

   ew = sbset.effector_weights

   ew.gravity = 0.
1

   ew.wind = 0.8

   return  


def addClothModifier(ob):

   cloth = ob.modifiers.new(name='Cloth', type='CLOTH')

   cset = cloth.settings 


   cset.quality = 4

   cset.mass = 0.2

   cset.structural_stiffness = 0.5

   cset.bending_stiffness = 0.05

   cset.spring_damping = 0

   cset.air_damping = 0.3

   cset.use_pin_cloth = True

   cset.vertex_group_mass = 'Pole'  


  #Веса эффектора

   ew = cset.effector_weights

   ew.gravity = 0.1

   ew.wind = 1.0 return  


def addWindEffector(origin): 

   # Добавление эффектора ветра

   bpy.ops.object.effector_add(

     type='WIND',

     location=origin,

    rotation=(pi/2,0,0))

   wind = bpy.context.object

   fset = wind.field


   fset.strength = -2.0

   fset.noise = 10.0

   fset.flow = 0.8

   fset.shape = 'PLANE'

   return  


def addFlagMaterial(name, ob, color1, color2): 

   # Текстура флага

   tex = bpy.data.textures.new('Flag', type = 'WOOD')

   tex.noise_basis_2 = 'TRI'

   tex.wood_type = 'RINGS'  


   # Создание материала

   mat = bpy.data.materials.new(name)

   mat.diffuse_color = color1  


   # Добавление текстурного слота для текстуры цвета

   mtex = mat.texture_slots.add()

   mtex.texture = tex

   mtex.
texture_coords = 'ORCO'

   mtex.use_map_color_diffuse = True

   mtex.color = color2  


   # Добавление материала к флагу

   ob.data.materials.append(mat)

   return mat  


def createDisplacementTexture(mat):

   tex = bpy.data.textures.new('Flag', type = 'WOOD')

   tex.noise_basis_2 = 'SIN'

   tex.wood_type = 'BANDNOISE'

   tex.noise_type = 'SOFT_NOISE'

   tex.noise_scale = 0.576

   tex.turbulence = 9.0 

   # Сохранение текстуры в материале для легкого доступа. Не необходимо на самом деле.

   mtex = mat.texture_slots.add()

   mtex.texture = tex

   mat.use_textures[1] = False

   return tex  


def addDisplacementModifier(ob, tex, vgrp, empty):

   mod = ob.modifiers.new('Displace', 'DISPLACE')

   mod.texture = tex

mod.vertex_group = vgrp

   mod.direction = 'NORMAL'

   mod.texture_coords = 'OBJECT'

   mod.texture_coords_object = empty

   mod.mid_level = 0.0

   mod.strength = 0.1

   print("'%s' '%s'" % (vgrp, mod.vertex_group))

   mod.vertex_group = vgrp

   print("'%s' '%s'" % (vgrp, mod.vertex_group))

   return mod  


def createAndAnimateEmpty(origin):

   bpy.ops.object.add(type='EMPTY', location=origin)

   empty = bpy.context.object

   scn = bpy.context.scene

   scn.frame_current = 1

   bpy.ops.anim.keyframe_insert_menu(type='Location')

   scn.frame_current = 26

   bpy.ops.transform.translate(value=(1,0,1))

   bpy.ops.anim.keyframe_insert_menu(type='Location')

   scn.frame_current = 1

   for fcu in empty.animation_data.action.fcurves:

     fcu.extrapolation = 'LINEAR'

     for kp in fcu.keyframe_points:

      kp.interpolation = 'LINEAR'

   return empty  


def run(origin): 

   # Создание флагов и полей

   flag1 = makeFlag('SoftBodyFlag', origin+Vector((-3,0,0)), False)

   flag2 = makeFlag('ClothFlag', origin+Vector((0,0,0)), False)

   flag3 = makeFlag('DisplacementFlag', origin+Vector((3,0,0)), True)

   pole1 = makePole(origin+Vector((-3,0,0)))

   pole2 = makePole(origin+Vector((0,0,0)))

   pole3 = makePole(origin+Vector((3,0,0)))  


# Материалы

   mat1 = addFlagMaterial('SoftBodyFlag', flag1, (1,0,0), (0,0,1))

   mat2 = addFlagMaterial('ClothFlag', flag2, (0,1,0), (1,1,0))

   mat3 = addFlagMaterial('DisplacementFlag', flag3, (1,0,1), (0,1,0))


   white = bpy.data.materials.new('White')

   white.diffuse_color = (1,1,1)

   pole1.data.materials.append(white)

   pole2.data.materials.append(white)

   pole3.data.materials.append(white)  


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

   addSoftBodyModifier(flag1)

   addClothModifier(flag2)

   addWindEffector(origin+Vector((-1,-2,0)))  


   # Создание смещения

   tex3 = createDisplacementTexture(mat3)

  empty = createAndAnimateEmpty(origin + Vector((3,0,0)))

   mod = addDisplacementModifier(flag3, tex3, 'POLE', empty)


   return  


if __name__ == "__main__":

   bpy.ops.object.select_by_type(type='MESH')

   bpy.ops.object.delete()

   run(Vector((0,0,0)))

   bpy.ops.screen.animation_play()


Частицы и модификатор Explode (взрыв)

Пуля с невидимой системой частиц стреляет в хрустальный шар. Шар разрушается, и части падают на пол.

Эффект достигается за счет придания шару модификатора взрыва, который запускается системой частиц. Идея заключалась в том, чтобы сделать это в системе частиц

reactor
, которая вызывается системой частиц пули. Тем не менее, частицы
reactor
, по-видимому, еще не включены в Blender 2.5, так что частицы шара устанавливаются на выброс в определенное время, а не по реакции.



#---------------------------------------------------------- 

# File crystal.py 

#---------------------------------------------------------- 

import bpy, mathutils, math 

from mathutils import *  


def addSphere(name, size, origin):

   bpy.ops.mesh.primitive_ico_sphere_add(

     subdivisions=2,

     size=size,

     location=origin)

   bpy.ops.object.shade_smooth()

   bpy.ops.object.modifier_add(type='SUBSURF')

   ob = bpy.context.object

   ob.name = name

   return ob  


def addFloor(name, origin, hidden):

   bpy.ops.mesh.primitive_plane_add(location=origin)

   bpy.ops.transform.resize(value=(30, 30, 30))

   floor = bpy.context.object

   floor.name = name

   if hidden:

   floor.hide = True

   floor.hide_render = True

   return floor  


   # Матариал пола

   voronoi = bpy.data.textures.new('Voronoi', type = 'VORONOI')

   voronoi.color_mode = 'POSITION'

   voronoi.noise_scale = 0.1


    plastic = bpy.data.materials.new('Plastic')

   plastic.diffuse_color = (1,1,0)

   plastic.diffuse_intensity = 0.1

   mtex = plastic.texture_slots.add()

   mtex.texture = voronoi

   mtex.texture_coords = 'ORCO'

   mtex.color = (0,0,1)

   floor.data.materials.append(plastic)

   return floor  


def run(origin): 

   # ----------- Материалы

   red = bpy.data.materials.new('Red')

   red.diffuse_color = (1,0,0)

   red.specular_hardness = 200

   rmir = red.raytrace_mirror

   
rmir.use = True

   rmir.distance = 0.001

   rmir.fade_to = 'FADE_TO_MATERIAL'

   rmir.distance = 0.0

   rmir.reflect_factor = 0.7

   rmir.gloss_factor = 0.4


   grey = bpy.data.materials.new('Grey'
)

   grey.diffuse_color = (0.5,0.5,0.5)  


# ----------- Пуля — маленькая сфера

 bullet = addSphere('Bullet', 0.2, origin)

 bullet.data.materials.append(grey)  


   # Анимация пули

   scn = bpy.context.scene

   scn.frame_current = 51

   bullet.location = origin

   bpy.ops.anim.keyframe_insert_menu(type='Location')

   bullet.location = origin+Vector((0,30,0))

   scn.frame_current = 251

   bpy.ops.anim.keyframe_insert_menu(type='Location')

   scn.frame_current = 1

   action = bullet.animation_data.action

   for fcu in action.fcurves:

     fcu.extrapolation = 'LINEAR'

     for kp in fcu.keyframe_points:

       kp.interpolation = 'LINEAR'  


   # Система частиц Trail (след) для пули


   bpy.ops.object.particle_system_add()

   trail = bullet.particle_systems[0]

   trail.name = 'Trail'

   fset = trail.settings 

   # Эмиссия

   fset.name = 'TrailSettings'

   fset.count = 1000 fset.frame_start = 1

   fset.frame_end = 250

   fset.lifetime = 25

   fset.emit_from = 'FACE'

   fset.use_render_emitter = True 

   # Скорость

   fset.normal_factor = 1.0

   fset.factor_random = 0.5 

   # Физика

   fset.physics_type = 'NEWTON'

   fset.mass = 0 

   # Установка всех эффекторных весов в ноль

   ew = fset.effector_weights

   ew.gravity = 0.0 

   # Не рендерить

   fset.draw_method = 'DOT'

   fset.render_type = 'NONE'  


   # -------------- Шар

   ball = addSphere('Ball', 1.0, origin)

   ball.data.materials.append(red)  


   # Система частиц

   bpy.ops.object.particle_system_add()

   react = ball.particle_systems[0]

   react.name = 'React'

   fset = react.settings 

   # Эмиссия

   fset.name = 'TrailSettings'

   fset.count = 50

   fset.frame_start = 47

fset.frame_end = 57

   fset.lifetime = 250

   fset.emit_from = 'FACE'

   fset.use_render_emitter = True 

   # Скорость

   fset.normal_factor = 5.0

   fset.factor_random = 2.5 

   # Физика

   fset.physics_type = 'NEWTON'

   fset.mass = 1.0 

   # Не рендерить

   fset.draw_method = 'CROSS'

   fset.render_type = 'NONE'  


   # Модификатор Explode

   mod = ball.modifiers.new(name='Explode', type='EXPLODE')

   mod.use_edge_cut = True

   mod.show_unborn = True

   mod.show_alive = True

   mod.show_dead = True

   mod.use_size = False  


   # ---- Скрытый пол с модификатором collision (столкновения)

   hidden = addFloor('Hidden', origin+Vector((0,0,-3.9)), True)

   mod = hidden.modifiers.new(name='Collision', type='COLLISION')

   mset = mod.settings

   mset.permeability = 0.01

   mset.stickness = 0.1

   mset.use_particle_kill = False

   mset.damping_factor = 0.6

   mset.damping_random = 0.2

   mset.friction_factor = 0.3

   mset.friction_random = 0.1


    addFloor('Floor', Vector((0,0,-4)), False)

   return  


if __name__ == "__main__":

   bpy.ops.object.select_all(action='SELECT')

   bpy.ops.object.delete()  


   # Камера, освещение

   bpy.ops.object.camera_add(

     location = Vector((12,-12,4)),

     rotation = Vector((70,0,45))*math.pi/180)

   cam = bpy.context.object.data

   cam.lens = 35

   bpy.ops.object.lamp_add(type='POINT',

     location = Vector((11,-7,6)))

   bpy.ops.object.lamp_add(type='POINT',

     location =Vector((-7,-10,2)))


   run(Vector((0,0,0)))


Частицы огня и дыма

Эта программа добавляет две системы частиц для огня и дыма. Частицы отображаются в виде билбордов с процедурными текстурами.



#--------------------------------------------------- 

# File fire.py 

#--------------------------------------------------- 

import bpy, mathutils, math 

from mathutils import Vector, Matrix 

from math import pi  


def createEmitter(origin):

   bpy.ops.mesh.primitive_plane_add(location=origin)

   emitter = bpy.context.object

   bpy.ops.mesh.uv_texture_add()

   return emitter  


def createFire(emitter): 

   # Добавление первой системы частиц — огня

   bpy.context.scene.objects.active = emitter

   bpy.ops.object.particle_system_add()

   fire = emitter.particle_systems[-1]

   fire.name = 'Fire'

   fset = fire.settings  


   # Эмиссия

   fset.name = 'FireSettings'

   fset.count = 100

   fset.frame_start = 1

   fset.frame_end = 200

   fset.lifetime = 70

   fset.lifetime_random = 0.2

   fset.emit_from = 'FACE'

   fset.use_render_emitter = False

   fset.distribution = 'RAND'

   fset.object_align_factor = (0,0,1)  


   # Скорость

   fset.normal_factor = 0.55

   fset.factor_random = 0.5  


   # Физика

   fset.physics_type = 'NEWTON'

   fset.mass = 1.0

   fset.particle_size = 10.0

fset.use_multiply_size_mass = False  


   # Веса эффекторов

   ew = fset.effector_weights

   ew.gravity = 0.0 ew.wind = 1.0  


   # Отображение и рендер

   fset.draw_percentage = 100

   fset.draw_method = 'RENDER'

   fset.material = 1

   fset.particle_size = 0.3

   fset.render_type = 'BILLBOARD'

   fset.render_step = 3  


   # Дочерние частицы

   fset.child_type = 'SIMPLE'

   fset.rendered_child_count = 50

   fset.child_radius = 1.1

   fset.child_roundness = 0.5 return fire  


def createSmoke(emitter): 

   # Добавление второй системы частиц — дыма

   bpy.context.scene.objects.active = emitter

   bpy.ops.object.particle_system_add()

   smoke = emitter.particle_systems[-1]

   smoke.name = 'Smoke' sset = smoke.settings  


   # Эмиссия

   sset.name = 'FireSettings'

  sset.count = 100

   sset.frame_start = 1

   sset.frame_end = 100

   
sset.lifetime = 70

   sset.lifetime_random = 0.2

   sset.emit_from = 'FACE'

   sset.use_render_emitter = False

   sset.distribution = 'RAND'  


   # Скорость

   sset.normal_factor = 0.0

   sset.factor_random = 0.5  


   # Физика

   sset.physics_type = 'NEWTON'

   sset.mass = 2.5

   sset.particle_size = 0.3

   sset.use_multiply_size_mass = True  


   # Веса эффекторов

   ew = sset.effector_weights

   ew.gravity = 0.0

   ew.wind = 1.0  


   # Отображение и рендер

   sset.draw_percentage = 100

   sset.draw_method = 'RENDER'

   sset.material = 2

   sset.particle_size = 0.5

   sset.render_type = 'BILLBOARD'

   sset.render_step = 3  


   # Дочерние частицы

   sset.child_type = 'SIMPLE'

   sset.rendered_child_count = 50

   sset.child_radius = 1.6 return smoke  


def createWind(origin): 

   # Создание ветра

   bpy.ops.object.effector_add(

     type='WIND',

     enter_editmode=False,

     location = origin - Vector((0,3,0)),

     rotation = (-pi/2, 0, 0))

   wind = bpy.context.object  


   # Настройки поля

   fld = wind.field

   fld.strength = 2.3

   fld.noise = 3.2

   fld.flow = 0.3

   return wind  


def createColorRamp(tex, values): 

   # Создание цветовой полосы

   tex.use_color_ramp = True

   ramp = tex.color_ramp

   for n,value in enumerate(values):

     elt = ramp.elements[n]

     (pos, color) = value

    elt.position = pos

     elt.color = color

   return  


def createFlameTexture():

   tex = bpy.data.textures.new('Flame', type = 'CLOUDS')

   createColorRamp(tex, [(0.2, (1,0.5,0.1,1)), (0.8, (0.5,0,0,0))])

   tex.noise_type = 'HARD_NOISE'

   tex.noise_scale = 0.7

   tex.noise_depth = 5

   return tex  


def createStencilTexture():

   tex = bpy.data.textures.new('Stencil', type = 'BLEND')

   tex.progression = 'SPHERICAL'

   createColorRamp(tex, [(0.0, (0,0,0,0)), (0.85, (1,1,1,0.6))])

   return tex  


def createEmitTexture():

   tex = bpy.data.textures.new('Emit',

   type = 'BLEND')

   tex.progression = 'LINEAR'

   createColorRamp(tex, [(0.1, (1,1,0,1)), (0.3, (1,0,0,1))])

   return tex  


def createSmokeTexture():

   tex = bpy.data.textures.new('Smoke', type = 'CLOUDS')

   createColorRamp(tex, [(0.2, (0,0,0,1)), (0.6, (1,1,1,1))])

   tex.noise_type = 'HARD_NOISE'

   tex.noise_scale = 1.05

   tex.noise_depth = 5

   return tex  


def createFireMaterial(textures, objects):

   (flame, stencil, emit) = textures 

  (emitter, empty) = objects


    mat = bpy.data.materials.new('Fire')

   mat.specular_intensity = 0.0

   mat.use_transparency = True

   mat.transparency_method = 'Z_TRANSPARENCY'

   mat.alpha = 0.0

   mat.use_raytrace = False

   mat.use_face_texture = True

   mat.use_shadows = False

   mat.use_cast_buffer_shadows = True


    mtex = mat.texture_slots.add()

   mtex.texture = emit

   mtex.texture_coords = 'UV'

   mtex.use_map_color_diffuse = True


    mtex = mat.texture_slots.add()

   mtex.texture = stencil

   mtex.texture_coords = 'UV'

   mtex.use_map_color_diffuse = False

   mtex.use_map_emit = True

   mtex.use_stencil = True


    mtex = mat.texture_slots.add()

   mtex.texture = flame

   mtex.texture_coords = 'UV'

   mtex.use_map_color_diffuse = True

   mtex.use_map_alpha = True 

   #mtex.object = empty

   return mat  


def createSmokeMaterial(textures, objects):

   (smoke, stencil) = textures

   (emitter, empty) = objects


 
  mat = bpy.data.materials.new('Smoke')

   mat.specular_intensity = 0.0

   mat.use_transparency = True

   mat.transparency_method = 'Z_TRANSPARENCY'

   mat.alpha = 0.0

   mat.use_raytrace = False

   mat.use_face_texture = True

   mat.use_shadows = True

   mat.use_cast_buffer_shadows = True


    mtex = mat.texture_slots.add()

   mtex.texture = stencil

   mtex.texture_coords = 'UV'

   mtex.use_map_color_diffuse = False

   mtex.use_map_alpha = True

   mtex.use_stencil = True


   mtex = mat.texture_slots.add()

   mtex.texture = smoke

   mtex.texture_coords = 'OBJECT'

   mtex.object = empty return mat  


def run(origin):

   emitter = createEmitter(origin) 

   #wind = createWind()

   bpy.ops.object.add(type='EMPTY')

   empty = bpy.context.object


    fire = createFire(emitter)

   flameTex = createFlameTexture()

   stencilTex = createStencilTexture()

   emitTex = createEmitTexture()

   flameMat = createFireMaterial(

     (flameTex, stencilTex, emitTex),

     (emitter, empty))

   emitter.data.materials.append(flameMat)


   smoke = createSmoke(emitter
)

   smokeTex = createSmokeTexture()

   smokeMat = createSmokeMaterial(

     (smokeTex, stencilTex), (emitter, empty))

   emitter.data.materials.append(smokeMat)

   return  


if __name__ == "__main__":

   bpy.ops.object.select_by_type(type='MESH')

   bpy.ops.object.delete()

   run((0,0,0))

   bpy.ops.screen.animation_play(reverse=False, sync=False)


Дым

Эта программа создает симуляцию дыма и присваивает воксельный материал.



#---------------------------------------------------------- 

# File smoke.py 

# Создание дыма и материала дыма. 

# Вдохновлен этим учебником Эндрю Прайса: 

# http://www.blenderguru.com/introduction-to-smoke-simulation/ 

#---------------------------------------------------------- 

import bpy, mathutils, math 

from mathutils import Vector 

from math import pi  


def createDomain(origin): 

   # Добавление куба в качестве домена

   bpy.ops.mesh.primitive_cube_add(location=origin
)

   bpy.ops.transform.resize(value=(4, 4, 4))

   domain = bpy.context.object domain.name = 'Domain'  


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

   dmod = domain.modifiers.new(name='Smoke', type='SMOKE')

   dmod.smoke_type = 'DOMAIN'

   dset = dmod.domain_settings  


   # Настройки домена

   dset.resolution_max = 32

   dset.alpha = -0.001

   dset.beta = 2.0

   dset.time_scale = 1.2

   dset.vorticity = 2.0

   dset.use_dissolve_smoke = True

   dset.dissolve_speed = 80

   dset.use_dissolve_smoke_log = True

   dset.use_high_resolution = True

   dset.show_high_resolution = True  


   # Веса эффекторов

   ew = dset.effector_weights

   ew.gravity = 0.4

   ew.force = 0.8

   return domain  


def createFlow(origin): 

   # Добавление плоскости как потока

   bpy.ops.mesh.primitive_plane_add(location = origin)

   bpy.ops.transform.resize(value=(2, 2, 2))

   flow = bpy.context.object flow.name = 'Flow'  


   # Добавление системы частиц дыма

   pmod = flow.modifiers.new(name='SmokeParticles', type='PARTICLE_SYSTEM')

   pmod.name = 'SmokeParticles'

   psys = pmod.particle_system

   psys.seed = 4711  


   # Настройки частиц

   pset = psys.settings

   pset.type = 'EMITTER'

   pset.lifetime = 1

   pset.emit_from = 'VOLUME'

   pset.use_render_emitter = False

   pset.render_type = 'NONE'

   pset.normal_factor = 8.0  


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

   smod = flow.modifiers.new(name='Smoke',

   type='SMOKE')

   smod.smoke_type = 'FLOW'

   sfset = smod.flow_settings  


   # Настройки потока

   sfset.use_outflow = False

   sfset.temperature = 0.7

   sfset.density = 0.8

   sfset.initial_velocity = True

   sfset.particle_system = psys

   return flow  


def createVortexEffector(origin):

   bpy.ops.object.effector_add(type='VORTEX', location=origin)

   vortex = bpy.context.object

   return vortex  


def createVoxelTexture(domain):

   tex = bpy.data.textures.new('VoxelTex', type = 'VOXEL_DATA')

   voxdata = tex.voxel_data

   voxdata.file_format = 'SMOKE'

   voxdata.domain_object = domain

   return tex  


def createVolumeMaterial(tex):

   mat = bpy.data.materials.new('VolumeMat')

   mat.type = 'VOLUME'

   vol = mat.volume

   vol.density = 0.0

vol.density_scale = 8.0

   vol.scattering = 6.0

   vol.asymmetry = 0.3

   vol.emission = 0.3

   vol.emission_color = (1,1,1)

   vol.transmission_color = (0.9,0.2,0)

   vol.reflection = 0.7

   vol.reflection_color = (0.8,0.9,0) 

   # Для удаления эффекта пикселизации

   vol.step_size = 0.05  


   # Добавление текстуры Voxel data

   mtex = mat.texture_slots.add()

   mtex.texture = tex

   mtex.texture_coords = 'ORCO'

   mtex.use_map_density = True

   mtex.use_map_emission = True

   mtex.use_map_scatter = False

   mtex.use_map_reflect = True

   mtex.use_map_color_emission = True

   mtex.use_map_color_transmission = True

   mtex.use_map_color_reflection = True


   mtex.density_factor = 1.0

   mtex.emission_factor = 0.2

   mtex.scattering_factor = 0.2

   mtex.reflection_factor = 0.3

   mtex.emission_color_factor = 0.9

   mtex.transmission_color_factor = 0.5

   mtex.reflection_color_factor = 0.6

   return mat  


def addFloor(origin): 

   # Создание пола, который принимает прозрачные тени

   bpy.ops.mesh.primitive_plane_add(

     location = origin,

     rotation = (0, 0, pi/4))

   bpy.ops.transform.resize(value=(4, 4, 4))

   bpy.ops.transform.resize(value=(2, 2, 2),

     constraint_axis=(True, False, False),

     constraint_orientation='LOCAL')

   floor = bpy.context.object

   mat = bpy.data.materials.new('Floor')

   mat.use_transparent_shadows = True

   floor.data.materials.append(mat)

   return  


def setupWorld():

   scn = bpy.context.scene

   
# Синее blend (смешанное) небо

   scn.world.use_sky_blend = True

   scn.world.horizon_color = (0.25, 0.3, 0.4)

   scn.world.zenith_color = (0, 0, 0.7)

# PAL 4:3 render

   scn.render.resolution_x = 720

   scn.render.resolution_y = 567

   return  


def run(origin):

   domain = createDomain(origin)

   flow = createFlow(origin-Vector((0,0,3.5)))

   vortex = createVortexEffector(origin)

   tex = createVoxelTexture(domain)

   mat = createVolumeMaterial(tex)

   domain.data.materials.append(mat)

   return  


if __name__ == "__main__":

   for ob in
 bpy.context.scene.objects:

   bpy.context.scene.objects.unlink(ob)


   addFloor(Vector((0,0,-4)))

   setupWorld()

# Освещение и камера

   bpy.ops.object.lamp_add( type = 'POINT',
 location=(4,6,1))

   bpy.ops.object.lamp_add( type = 'POINT', location=(-7,-5,0))

   bpy.ops.object.camera_add(location=Vector((8,-8,3)),

     rotation=(pi/3, 0, pi/6))


   run(Vector((0,0,0)))

   bpy.ops.screen.animation_play()


Симуляция твёрдого тела

Эта программа использует игровой движок Блендера для моделирования падения кучи объектов на землю. Анимации записываются и впоследствии могут быть воспроизведены.



#---------------------------------------------------------- 

# File pile.py 

#---------------------------------------------------------- 

import bpy, mathutils, math, random 

from mathutils import Vector  NObjects = 7Seed = 444  


def addSceneGameSettings(scn):

   
# Данные игровой сцены

   sgdata = scn.game_settings

   sgdata.fps = 25 sgdata.frequency = True

   sgdata.material_mode = 'GLSL'

   sgdata.show_debug_properties = True

   sgdata.show_framerate_profile = True

   sgdata.show_fullscreen = True

   sgdata.show_physics_visualization = True

   sgdata.use_animation_record = True return  


def addMonkeyGameSettings(ob): 

   # Настройки игрового объекта

   goset = ob.game

   goset.physics_type = 'RIGID_BODY'

   goset.use_actor = True

   goset.use_ghost = False

   goset.mass = 7.0

   goset.damping = 0.0


    goset.use_collision_bounds = True

   goset.collision_bounds_type = 'BOX'


    goset.show_actuators = True goset.show_controllers = True

   goset.show_debug_state = True

   goset.show_sensors = True goset.show_state_panel = True


   return  


def run(origin): 

   # Смена движка рендера с BLENDER_RENDER на BLENDER_GAME

   bpy.context.scene.render.engine = 'BLENDER_GAME'  


   # Создание пола

   bpy.ops.mesh.primitive_plane_add(location=origin)

   bpy.ops.transform.resize(value=(20, 20, 20))

   floor = bpy.context.object

   mat = bpy.data.materials.new(name = 'FloorMaterial')

   mat.diffuse_color = (0.5, 0.5, 0.5)  


   # Создание кучи объектов

   objectType = ["cube", "ico_sphere", "monkey"]

   objects = []

   deg2rad = math.pi/180

   random.seed(Seed)

   for n in range(NObjects):

     x = []

     for i in range(3):

       x.append( random.randrange(0, 360, 1) )

     dx = 0.5*random.random()

     dy = 0.5*random.random()

     obType = objectType[ random.randrange(0, 3, 1) ]

     fcn = eval("bpy.ops.mesh.primitive_%s_add" % obType)

     fcn(location=origin+Vector((dx, dy, 3*n+3)),

       rotation=deg2rad*Vector((x[0], x[1], x[2])))

     ob = bpy.context.object objects.append( ob )

    mat = bpy.data.materials.new(name='Material_%02d' % n) c = []

     for j in range(3):

     c.append( random.random() ) mat.diffuse_color = c

     ob.data.materials.append(mat)  


   # Установка игровых настроек для пола

   fset = floor.game

   fset.physics_type = 'STATIC'  


   # Установка игровых настроек для объектов

   for n in range(NObjects):

     addMonkeyGameSettings(objects[n])  


   # Установка игровых настроек для сцены

   scn = bpy.context.scene

   addSceneGameSettings(scn)

   scn.frame_start = 1

   scn.frame_end = 200 return  


if __name__ == "__main__":

   bpy.ops.object.select_by_type(type='MESH')

   bpy.ops.object.delete()

   run(Vector((0,0,0)))

   bpy.ops.view3d.game_start()


Жидкости

Эта программа настраивает симуляцию жидкости с доменом, жидкостью, движущимся препятствием, притоком, оттоком, и тремя видами капель. Обратите внимание, что мы должны запечь симуляцию сначала, я не думаю, что это было необходимо.

Изображение кадра 57, после добавления нескольких материалов. Капли в основном отрендерены полностью, если они имеют низкую прозрачность, около alpha = 0,2.





#---------------------------------------------------------- 

# File fluid.py 

#---------------------------------------------------------- 

import bpy, math 

from mathutils import Vector 

from math import pi  


def createDomain(origin): 

   # Домен

   bpy.ops.mesh.primitive_cube_add(location=origin)

   bpy.ops.transform.resize(value=(4, 4, 4))

   domain = bpy.context.object

   domain.name = 'Domain'

   bpy.ops.object.shade_smooth() 

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

   mod = domain.modifiers.new(name='FluidDomain', type='FLUID_SIMULATION') 

   # mod.settings is FluidSettings

  mod.settings.type = 'DOMAIN' 

   # mod.settings now changed to DomainFluidSettings

   settings = mod.settings

   settings.use_speed_vectors = False

   settings.simulation_scale = 3.0

   settings.slip_type = 'FREESLIP'

   settings.tracer_particles = 10

   settings.generate_particles = 1.5 

   #settings.start_time = 0.0 

   #settings.end_time = 2.0

   return domain  


def createFluid(origin): 

   # Жидкость

   bpy.ops.mesh.primitive_ico_sphere_add(

      size=3.5,

      subdivisions=1,

     location=origin)

   fluid = bpy.context.object

   fluid.name = 'Fluid'

   fluid.hide = True

   fluid.hide_render = True 

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

   mod = fluid.modifiers.new(name='Fluid', type='FLUID_SIMULATION')

   mod.settings.type = 'FLUID'

   return fluid  


def createObstacle(origin): 

   # Препятствие

   bpy.ops.mesh.primitive_cylinder_add(

     vertices=12,

     radius=0.3,

     depth=2,

     cap_ends=True,

    location=origin + Vector((0,0,-2.5)),

    rotation=(pi/2, 0, 0))

   bpy.ops.object.modifier_add(type='FLUID_SIMULATION')

   obst = bpy.context.object

   obst.name = 'Obstacle' 

   # Добавление модификатора препятствию

   bpy.ops.object.modifier_add(type='FLUID_SIMULATION')

   mod = obst.modifiers[-1]

   mod.settings.type = 'OBSTACLE'  


   # Анимация препятствия

   scn = bpy.context.scene

   scn.frame_current = 1

   bpy.ops.anim.keyframe_insert_menu(type='Rotation')

   scn.frame_current = 26

   bpy.ops.transform.rotate(value=(pi/2,), axis=(-0, -0, -1))

   bpy.ops.anim.keyframe_insert_menu(type='Rotation')

   scn.frame_current = 1

   for fcu in obst.animation_data.action.fcurves:

     fcu.extrapolation = 'LINEAR'

     for kp in fcu.keyframe_points:

       kp.interpolation = 'LINEAR'

   return obst  


def createInflow(origin): 

   # Приток

   bpy.ops.mesh.primitive_circle_add(

     radius=0.75,

     fill=True,

     location=origin+Vector((-3.9,0,3)),

    rotation=(0, pi/2, 0))

   inflow = bpy.context.object

   inflow.name = 'Inflow' 

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

   bpy.ops.object.modifier_add(type='FLUID_SIMULATION')

   mod = inflow.modifiers[-1]

   mod.settings.type = 'INFLOW'

   settings = mod.settings

   settings.inflow_velocity = (1.5,0,0
)

   settings.volume_initialization = 'SHELL'

   return inflow  


def createOutflow(origin): 

   # Отток

   bpy.ops.mesh.primitive_circle_add(

    radius=0.75,

     fill=True,

     location=origin+Vector((3.9,0,-3)),

    rotation=(0, -pi/2, 0))

  outflow = bpy.context.object

   outflow.name = 'Outflow' 

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

   bpy.ops.object.modifier_add(type='FLUID_SIMULATION')

   mod = outflow.modifiers[-1]

   mod.settings.type = 'OUTFLOW'

   mod.settings.volume_initialization = 'SHELL'

   return outflow  


def createFluidParticle(name, origin, data): 

   # Частицы жидкости

   bpy.ops.mesh.primitive_monkey_add(location=origin)

   monkey = bpy.context.object

   monkey.name = name 

   # Добавление модификатора жидкости-частиц

   bpy.ops.object.modifier_add(type='FLUID_SIMULATION')

   mod = monkey.modifiers[-1]

   mod.settings.type = 'PARTICLE'

   (drops, floats, tracer) = data

   mod.settings.use_drops = drops

   mod.settings.use_floats = floats

   mod.settings.show_tracer = tracer  


   # Настройка типа частиц созданной системы частиц

   psys = monkey.modifiers[-1].particle_system

   psys.name = name+'Psys' 

   #psys.settings.name = name+'Pset'

   return (mod.settings, None)  


def run(origin):

   domain = createDomain(origin)

   fluid = createFluid(origin)

   obst = createObstacle(origin)

   inflow = createInflow(origin)

   outflow = createOutflow(origin)


   (settings, pset) = createFluidParticle('Drops',

     origin+Vector((-2,7,0)), (True, False, False))

   settings.particle_influence = 0.7

   settings.alpha_influence = 0.3


   (settings, pset) = createFluidParticle('Floats',

     origin+Vector((0,7,0)), (False, True, False))


   (settings, pset) = createFluidParticle('Tracer',

     origin+Vector((2,7,0)), (False, False, True))

   settings.particle_influence = 1.5

   settings.alpha_influence = 1.2

   return  


if __name__ == "__main__":

   bpy.ops.object.select_all(action='SELECT')

   bpy.ops.object.delete() run(Vector((0,0,0))) 

   #bpy.ops.fluid.bake()




Загрузка...