From BlenderWiki

Jump to: navigation, search

Simulazioni

In questa sezione accederemo alle capacità di simulazione di Blender, mediante Python. Molti degli esempi sono ispirati dal libro Bounce, Tumble and Splash by Tony Mullen. Tuttavia molti render, non sembrano belli come quelli del libro di Mullen, poiché lo scopo di queste note non è quello di trovare il modo ottimale per modificare i parametri, ma piuttosto quello di illustrare come si possono modificare da Python.

Particelle

Questo programma aggiunge due sistemi particellari. Code Snippets Paticle.png

#---------------------------------------------------
# File particle.py
#---------------------------------------------------
import bpy, mathutils, math
from mathutils import Vector, Matrix
from math import pi
 
def run(origo):
    # Add emitter mesh
    origin = Vector(origo)
    bpy.ops.mesh.primitive_plane_add(location=origin)
    emitter = bpy.context.object
 
    # --- Particle system 1: Falling and blowing drops ---
 
    # Add first particle system
    bpy.ops.object.particle_system_add()    
    psys1 = emitter.particle_systems[-1]
    psys1.name = 'Drops'
 
    # Emission    
    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)
 
    # Physics
    pset1.physics_type = 'NEWTON'
    pset1.mass = 2.5
    pset1.particle_size = 0.3
    pset1.use_multiply_size_mass = True
 
    # Effector weights
    ew = pset1.effector_weights
    ew.gravity = 1.0
    ew.wind = 1.0
 
    # Children
    pset1.child_nbr = 10
    pset1.rendered_child_count = 10
    pset1.child_type = 'SIMPLE'
 
    # Display and render
    pset1.draw_percentage = 100
    pset1.draw_method = 'CROSS'
    pset1.material = 1
    pset1.particle_size = 0.1    
    pset1.render_type = 'HALO'
    pset1.render_step = 3
 
    # ------------ Wind effector -----
 
    # Add wind effector
    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
 
    # Field settings
    fld = wind.field
    fld.strength = 2.3
    fld.noise = 3.2
    fld.flow = 0.3    
 
    # --- Particle system 2: Monkeys in the wind ----
 
    # Add monkey to be used as dupli object
    # Hide the monkey on layer 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
 
    #Add second particle system
    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'
 
    # Emission
    pset2.count = 4
    pset2.frame_start = 1
    pset2.frame_end = 50
    pset2.lifetime = 250
    pset2.emit_from = 'FACE'
    pset2.use_render_emitter = True
 
    # Velocity
    pset2.factor_random = 0.5
 
    # Physics
    pset2.physics_type = 'NEWTON'
    pset2.brownian_factor = 0.5
 
    # Effector weights
    ew = pset2.effector_weights
    ew.gravity = 0
    ew.wind = 0.2
 
    # Children
    pset2.child_nbr = 1
    pset2.rendered_child_count = 1
    pset2.child_size = 3
    pset2.child_type = 'SIMPLE'
 
    # Display and render
    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)

Capelli

Questo programma aggiunge una sfera con capelli. Un filo luminoso e costruito per i capelli. Code Snippets Hair.png

#---------------------------------------------------
# File hair.py
#---------------------------------------------------
import bpy
 
def createHead(origin):
    # Add emitter mesh
    bpy.ops.mesh.primitive_ico_sphere_add(location=origin)
    ob = bpy.context.object
    bpy.ops.object.shade_smooth()
 
    # Create scalp vertex group, and add verts and weights
    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):
    # Some material for the skin
    skinmat = bpy.data.materials.new('Skin')
    skinmat.diffuse_color = (0.6,0.3,0)
 
    # Strand material for hair
    hairmat = bpy.data.materials.new('Strand')
    hairmat.diffuse_color = (0.2,0.04,0.0)
    hairmat.specular_intensity = 0
 
    # Transparency
    hairmat.use_transparency = True
    hairmat.transparency_method = 'Z_TRANSPARENCY'
    hairmat.alpha = 0
 
    # Strand. Must use Blender units before sizes are pset.
    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
 
    # Texture
    tex = bpy.data.textures.new('Blend', type = 'BLEND')
    tex.progression = 'LINEAR'
    tex.use_flip_axis = 'HORIZONTAL'
 
    # Create a color ramp for color and alpha
    tex.use_color_ramp = True
    tex.color_ramp.interpolation = 'B_SPLINE'
    # Points in color ramp: (pos, rgba)
    # Have not figured out how to add points to ramp
    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
 
    # Add blend texture to hairmat
    mtex = hairmat.texture_slots.add()
    mtex.texture = tex
    mtex.texture_coords = 'STRAND'
    mtex.use_map_color_diffuse = True 
    mtex.use_map_alpha = True 
 
    # Add materials to mesh    
    ob.data.materials.append(skinmat)    # Material 1 = Skin
    ob.data.materials.append(hairmat)    # Material 2 = Strand
    return    
 
def createHair(ob):    
    # Create hair particle system
    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'
 
    # Emission
    pset.count = 40
    pset.hair_step = 7
    pset.emit_from = 'FACE'
 
    # Render
    pset.material = 2
    pset.use_render_emitter = True
    pset.render_type = 'PATH'
    pset.use_strand_primitive = True
    pset.use_hair_bspline = True
 
    # Children
    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))

Capelli modificabili

Questo programma aggiunge una sfera con capelli modificabili dalle guipoe per capelli date. Se andiamo in Edit Mode tutti i fili si raddrizzanoe quindi la modifica viene persa. Questo è evitato se passi a Particle Mode, selezioni l'oggetto, e torni in Object Mode. Purtroppo non ho trovato un modo per fare questo con uno script. Code Snippets EditHair.png

#---------------------------------------------------
# File edit_hair.py
# Has flaws, but may be of interest anyway.
#---------------------------------------------------
import bpy
 
def createHead():
    # Add emitter mesh
    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])
 
    # Create hair particle system
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.particle_system_add()
    psys = ob.particle_systems.active
    psys.name = 'Hair'
 
    # Particle settings
    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
 
    # Children
    pset.child_type = 'SIMPLE'
    pset.child_nbr = 6
    pset.rendered_child_count = 300
    pset.child_length = 1.0
    pset.child_length_threshold = 0.0
 
    # Disconnect hair and switch to particle edit mode
    bpy.ops.particle.disconnect_hair(all=True)
    bpy.ops.particle.particle_edit_toggle()
 
    # Set all hair-keys
    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
 
    # Toggle particle edit mode
    bpy.ops.particle.select_all(action='SELECT')
    bpy.ops.particle.particle_edit_toggle()
 
    # Connect hair to mesh
    # Segmentation violation during render if this line is absent.
    bpy.ops.particle.connect_hair(all=True)
 
    # Unfortunately, here a manual step appears to be needed:
    # 1. Toggle to particle mode
    # 2. Touch object with a brush
    # 3. Toggle to object mode
    # 4. Toggle to edit mode
    # 5. Toggle to object mode
    # This should correspond to the code below, but fails due to
    # wrong context
    '''
    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
 
# Hair guides. Four hair with five points each.
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))

Cloth

Questo programma aggiunge un piano con un modificatore Cloth. Il piano è imparentato a un cerchio che si muove verso il basso dove incontra una sfera come ostacolo. L'influenza del modificatore Cloth è controllata da un vertex group, questo significa che gli angoli si muovono con il cerchio mentre il centro è deformato dall'ostacolo. Al piano è dato un materiale con trasparenza stress-mapped. Code Snippets Cloth.png

#----------------------------------------------------------
# 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
 
    # Add a sphere acting as a collision object
    bpy.ops.mesh.primitive_ico_sphere_add(location=origin)
    sphere = bpy.context.object
    bpy.ops.object.shade_smooth()
 
    # Add a collision modifier to the sphere    
    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')
 
    # Add ring
    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
 
    # Add a plane over the sphere and parent it to ring
    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
 
    # Create vertex group. Object must not be active?
    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')
 
    # Reactivate plane
    scn.objects.active = plane
 
    # Add cloth modifier
    cloth = plane.modifiers.new(name='Cloth', type='CLOTH')
    cset = cloth.settings
    cset.use_pin_cloth = True
    cset.vertex_group_mass = 'Group'
    # Silk presets, copied from "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
 
    # Smooth shading
    plane.select = True
    bpy.ops.object.shade_smooth()
    bpy.ops.object.modifier_add(type='SUBSURF')
 
    # Blend texture
    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 material
    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'
 
    # Add material to plane
    plane.data.materials.append(mat)    
 
    # Animate ring 
    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()

Softbodies

Questo programma aggiunge una sfera con un modificatore softbody e un piano come ostacolo. Code Snippets Softbody.png

#----------------------------------------------------------
# File softbody.py
#----------------------------------------------------------
import bpy
import mathutils
from mathutils import Vector
 
def run(origin):
    # Add materials
    red = bpy.data.materials.new('Red')
    red.diffuse_color = (1,0,0)
    blue = bpy.data.materials.new('Blue')
    blue.diffuse_color = (0,0,1)
 
    # Add a cone
    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')
 
    # Weirdly, need new mesh which is a copy of
    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)
 
    # Set faces smooth
    for f in me2.faces:
        f.use_smooth = True
 
    # Add new object and make it active
    ob2 = bpy.data.objects.new('Drop', me2)
    scn = bpy.context.scene
    scn.objects.link(ob2)
    scn.objects.unlink(ob1)
    scn.objects.active = ob2
 
    # Add vertex groups
    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)
 
    # Add a softbody modifier
    mod = ob2.modifiers.new(name='SoftBody', type='SOFT_BODY')
    sbset = mod.settings
 
    # Soft body
    sbset.friction = 0.6
    sbset.speed = 0.4
    sbset.mass = 8.1
 
    # Goal
    sbset.goal_default = 0.7
    sbset.goal_spring = 0.3
    sbset.goal_friction = 0.0
    sbset.vertex_group_goal = 'Top'
 
    # Soft body edges
    sbset.pull = 0.6
    sbset.push = 0.1
    sbset.bend = 0.1
    sbset.aerodynamics_type = 'LIFT_FORCE'
    sbset.aero = 0.5
 
    # Add a vortex
    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'
 
    # Add collision plane
    # Warning. Collision objects make simulation very slow!
    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)

Cloth, softbodies e displacement textures

Questo programma mostra tre differenti metodi per fare una bandiera sventolante: con un modificatore cloth, con un modificatore softbody, e con una texture displacement animata. Code Snippets Flags.png

#----------------------------------------------------------
# File flags.py
# Creates a softbody flag and a cloth flag in the wind.
# Update to API rev. 36816
#----------------------------------------------------------
import bpy, mathutils, math
from mathutils import Vector
from math import pi
 
# Flag size, global variables
xmax = 40
zmax = 24
ds = 2.0/xmax
 
def makeFlag(name, origin, invert):
    # Add new mesh that will be the flag    
 
    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
 
    # Build flag mesh
    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
 
    # Add vertex groups
    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
 
    # Soft body
    sbset.friction = 0.3
    sbset.speed = 1.4
    sbset.mass = 0.9
 
    # Goal
    sbset.goal_default = 0.3
    sbset.goal_spring = 0.1
    sbset.goal_friction = 0.1
    sbset.vertex_group_goal = 'Pole'
 
    # Soft body edges
    sbset.pull = 0.1
    sbset.push = 0.1
    sbset.bend = 0.1
    sbset.aerodynamics_type = 'LIFT_FORCE'
    sbset.aero = 0.5
 
    #Effector weights
    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'
 
    #Effector weights
    ew = cset.effector_weights
    ew.gravity = 0.1
    ew.wind = 1.0
    return
 
 
def addWindEffector(origin):    
    # Add wind effector
    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):        
    # Flag texture
    tex = bpy.data.textures.new('Flag', type = 'WOOD')
    tex.noise_basis_2 = 'TRI'
    tex.wood_type = 'RINGS'
 
    # Create material
    mat = bpy.data.materials.new(name)
    mat.diffuse_color = color1
 
    # Add texture slot for color texture
    mtex = mat.texture_slots.add()
    mtex.texture = tex
    mtex.texture_coords = 'ORCO'
    mtex.use_map_color_diffuse = True
    mtex.color = color2
 
    # Add material to flags
    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
    # Store texture in material for easy access. Not really necessary
    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):
    # Create flags and poles
    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)))
 
    # Materials
    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)
 
    # Add modifiers and wind
    addSoftBodyModifier(flag1)
    addClothModifier(flag2)
    addWindEffector(origin+Vector((-1,-2,0)))
 
    # Create displacement
    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()

Particelle e modificatore explode

Un proiettile con un sistema di particelle invisibili è sparato a una sfera di cristallo. La sfera è fatta a pezzi, e i pezzi cadono sul pavimento.

L'effetto è ottenuto dando alla sfera un modificatore explode che è attivato da un sistema particellare. L'idea era di fare questo in un sistema particellare a reazione, che è attivato dal sistema particellare del proiettile. Tuttavia le particella reattore, sembra che non siano ancora state implementate in Blender 2.5, così, le particelle della sfera sono impostate per essere emesse in un momento specifico.. Code Snippets Crystal.png

#----------------------------------------------------------
# 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
 
    # Floor material
    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):
    # ----------- Materials
    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 - a small sphere
    bullet = addSphere('Bullet', 0.2, origin)
    bullet.data.materials.append(grey)
 
    # Animate bullet
    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 particle system for bullet
 
    bpy.ops.object.particle_system_add()    
    trail = bullet.particle_systems[0]
    trail.name = 'Trail'
    fset = trail.settings
    # Emission    
    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
    # Velocity
    fset.normal_factor = 1.0
    fset.factor_random = 0.5    
    # Physics
    fset.physics_type = 'NEWTON'
    fset.mass = 0
    # Set all effector weights to zero
    ew = fset.effector_weights
    ew.gravity = 0.0
    # Don't render
    fset.draw_method = 'DOT'
    fset.render_type = 'NONE'
 
    # -------------- Ball    
    ball = addSphere('Ball', 1.0, origin)
    ball.data.materials.append(red)
 
    # Particle system
    bpy.ops.object.particle_system_add()    
    react = ball.particle_systems[0]
    react.name = 'React'
    fset = react.settings
    # Emission    
    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
    # Velocity
    fset.normal_factor = 5.0
    fset.factor_random = 2.5    
    # Physics
    fset.physics_type = 'NEWTON'
    fset.mass = 1.0
    # Don't render
    fset.draw_method = 'CROSS'
    fset.render_type = 'NONE'
 
    # Explode modifier
    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
 
    # ----------- Hidden floor with collision modifier
    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()
 
    # Camera, lights
    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)))

Particelle, fuoco e fumo

Questo programma aggiunge due sistemi particellari per fuoco e fumo. Le particelle sono renderizzate come billboards con texture procedurali. Code Snippets Fire.png

#---------------------------------------------------
# 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):    
    # Add first particle system
    bpy.context.scene.objects.active = emitter
    bpy.ops.object.particle_system_add()    
    fire = emitter.particle_systems[-1]
    fire.name = 'Fire'
    fset = fire.settings
 
    # Emission    
    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)
 
    # Velocity
    fset.normal_factor = 0.55
    fset.factor_random = 0.5
 
    # Physics
    fset.physics_type = 'NEWTON'
    fset.mass = 1.0
    fset.particle_size = 10.0
    fset.use_multiply_size_mass = False
 
    # Effector weights
    ew = fset.effector_weights
    ew.gravity = 0.0
    ew.wind = 1.0
 
    # Display and render
    fset.draw_percentage = 100
    fset.draw_method = 'RENDER'
    fset.material = 1
    fset.particle_size = 0.3
    fset.render_type = 'BILLBOARD'
    fset.render_step = 3
 
    # Children
    fset.child_type = 'SIMPLE'
    fset.rendered_child_count = 50
    fset.child_radius = 1.1
    fset.child_roundness = 0.5
    return fire
 
def createSmoke(emitter):    
    # Add second particle system
    bpy.context.scene.objects.active = emitter
    bpy.ops.object.particle_system_add()    
    smoke = emitter.particle_systems[-1]
    smoke.name = 'Smoke'
    sset = smoke.settings
 
    # Emission    
    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'
 
    # Velocity
    sset.normal_factor = 0.0
    sset.factor_random = 0.5
 
    # Physics
    sset.physics_type = 'NEWTON'
    sset.mass = 2.5
    sset.particle_size = 0.3
    sset.use_multiply_size_mass = True
 
    # Effector weights
    ew = sset.effector_weights
    ew.gravity = 0.0
    ew.wind = 1.0
 
    # Display and render
    sset.draw_percentage = 100
    sset.draw_method = 'RENDER'
    sset.material = 2
    sset.particle_size = 0.5    
    sset.render_type = 'BILLBOARD'
    sset.render_step = 3
 
    # Children
    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
 
    # Field settings
    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)

Fumo

Questo programma imposta una simulazione per fumo e gli assegna un materiale voxel. Code Snippets Smoke.png

#----------------------------------------------------------
# File smoke.py
# Creates smoke and smoke material. 
# Heavily inspired by Andrew Price's tutorial at
# http://www.blenderguru.com/introduction-to-smoke-simulation/
#----------------------------------------------------------
import bpy, mathutils, math
from mathutils import Vector
from math import pi
 
def createDomain(origin):
    # Add cube as domain
    bpy.ops.mesh.primitive_cube_add(location=origin)
    bpy.ops.transform.resize(value=(4, 4, 4))
    domain = bpy.context.object
    domain.name = 'Domain'
 
    # Add domain modifier
    dmod = domain.modifiers.new(name='Smoke', type='SMOKE')
    dmod.smoke_type = 'DOMAIN'
    dset = dmod.domain_settings
 
    # 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
 
    # Effector weights
    ew = dset.effector_weights
    ew.gravity = 0.4
    ew.force = 0.8
    return domain
 
def createFlow(origin):
    # Add plane as flow
    bpy.ops.mesh.primitive_plane_add(location = origin)
    bpy.ops.transform.resize(value=(2, 2, 2))
    flow = bpy.context.object
    flow.name = 'Flow'
 
    # Add smoke particle system
    pmod = flow.modifiers.new(name='SmokeParticles', type='PARTICLE_SYSTEM')
    pmod.name = 'SmokeParticles'
    psys = pmod.particle_system
    psys.seed = 4711
 
    # Particle settings
    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
 
    # Add smoke modifier
    smod = flow.modifiers.new(name='Smoke', type='SMOKE')
    smod.smoke_type = 'FLOW'
    sfset = smod.flow_settings
 
    # 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)
    # To remove pixelation effects
    vol.step_size = 0.05
 
    # Add voxdata texture
    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):
    # Create floor that receives transparent shadows
    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
    # Blue blend sky
    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()
    # Lights and camera
    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()

Simulazione Rigid body

Questo programma utilizza il motore di gioco di Blender per simulare un mucchio di oggetti che cade a terra. L'animazione è segistrata, e può essere riprodotta in seguito. Code Snippets Pile.png

#----------------------------------------------------------
# File pile.py
#----------------------------------------------------------
import bpy, mathutils, math, random
from mathutils import Vector
 
NObjects = 7
Seed = 444
 
def addSceneGameSettings(scn):
    # SceneGameData
    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):        
    # GameObjectSettings
    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):
    # Change render engine from BLENDER_RENDER to BLENDER_GAME
    bpy.context.scene.render.engine = 'BLENDER_GAME'
 
    # Create floor
    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)
 
    # Create a pile of objects
    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)
 
    # Set game settings for floor        
    fset = floor.game
    fset.physics_type = 'STATIC'
 
    # Set game settings for monkeys
    for n in range(NObjects):
        addMonkeyGameSettings(objects[n])
 
    # Set game settings for scene
    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()

Fluidi

Questo programma imposta una simulazione fluidi con un dominio, un fluido, un ostacolo in movimento un inflow e un outflow e tre tipi di gocce. Nota che dobbiamo prima fare il bake della simulazione; Note that we must bake the simulation first.

L'immagine è presa al fotogramma 57, dopo che alcuni materiali sono stati aggiunti. La goccia domina il rendering completamente a meno che non gli viene fornita una bassa opacità, alpha = 0.2. Code Snippets Fluid1.png

Code Snippets Fluid.png

#----------------------------------------------------------
# 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()
    # Add domain modifier
    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
    # Add fluid modifier. 
    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'
    # Add fluid modifier
    bpy.ops.object.modifier_add(type='FLUID_SIMULATION')
    mod = obst.modifiers[-1]
    mod.settings.type = 'OBSTACLE'
 
    # Animate 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'
    # Add fluid modifier
    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'
    # Add fluid modifier
    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
    # Add fluid modifier
    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
 
    # Setting type to particle created a particle system
    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()