# let's create animations showcasing the effects of various particle system parameters
import bpy
def grass_group():
return bpy.data.groups.get("grasses")
def make_PS_dupli(name):
ps = bpy.data.particles.new(name)
set_PS_dupli(ps)
def set_PS_dupli(ps):
ps.type = 'HAIR'
ps.render_type = 'GROUP'
ps.dupli_group = grass_group()
print(ps.dupli_group)
ps.use_advanced_hair = True
ps.child_type = 'INTERPOLATED'
ps.count=100
ps.material_slot = 'grass 1'
def set_PS_path(ps):
ps.type = 'HAIR'
ps.render_type = 'PATH'
ps.use_advanced_hair = True
ps.child_type = 'INTERPOLATED'
ps.count=100
ps.material_slot = 'grass 1'
def particle_mesh():
name = "particle emitter"
mesh = bpy.data.meshes.get(name)
if mesh is None:
mesh = bpy.data.meshes.new(name)
verts = ( [8,8,0],
[-8,8,0],
[-8,-8,0],
[8,-8,0])
mesh.from_pydata(verts, [], [ [0,1,2,3] ])
mesh.materials.append(bpy.data.materials.get("dirt"))
mesh.materials.append(bpy.data.materials.get("grass 1"))
obj = bpy.data.objects.new(name, mesh)
return obj
def set_flash_keyframes(hide, fr):
# the curve started out empty, let's add 4 points
hide.keyframe_points.add(4)
kp = hide.keyframe_points
# start hidden
kp[0].co = (1, True)
# appear at fr
kp[1].co = (fr, False)
# disappear at fr+1
kp[2].co = (fr + 1, True)
# make all the objects reappear at frame 999 (well beyond the animation end)
kp[3].co = (999, False)
for bt in kp:
bt.interpolation = 'CONSTANT'
if fr==1:
# in this case, the object starts visible, not hidden, so we remove a conflicting point
kp.remove(kp[0])
def get_flash_action(fr):
"""
:param fr: what frame should the object appear at (and disappear immediately after?
:return: an action datablock to make the object appear at the targeted frame and disappear immediately afterward
"""
name = "action flash %d"%fr
rval = bpy.data.actions.get(name)
# it is not very commmon for objects to reuse actions outside of an NLA context,
# but since I'm making a lot of animations that have text armies that
# appear and disappear in a similar manner, I decided to reuse the actions.
if rval is None:
# the action I want does not exist yet. Make it.
rval = bpy.data.actions.new(name)
# this curve will control the object's visibilty in the 3D view
h1 = rval.fcurves.new("hide")
# this curve will control the object's visibility in the rendered scene
h2 = rval.fcurves.new("hide_render")
set_flash_keyframes(h1, fr)
set_flash_keyframes(h2, fr)
return rval
def label_material():
rval = bpy.data.materials.get("label")
if rval is None:
rval = bpy.data.materials.new("label")
rval.emit = 1
rval.diffuse_intensity = 0
rval.specular_intensity = 0
rval.diffuse_color = (1,1,1)
return rval
def value_overlay(msg, fr, scn):
"""
create a text message that appears at fr and disappears immediately after
:param msg: the body of the text
:param fr: frame number for the text object to appear
:param scn: the scene the object will be linked to.
"""
curve = bpy.data.curves.new("value_overlay", 'FONT')
curve.body = msg
curve.size = 0.5
curve.materials.append(label_material())
obj = bpy.data.objects.new("value_overlay", curve)
obj.animation_data_create()
obj.animation_data.action=get_flash_action(fr)
cns = obj.constraints.new("CHILD_OF")
cns.target= scn.camera
obj.location = (-4.3, 1.8, -10)
scn.objects.link(obj)
def animate_parameter(ps, data_path, keyframes, extra = {}):
for key, value in extra.items():
setattr(ps, key, value)
ps.animation_data_create()
ac = bpy.data.actions.new("ps action %s" % data_path)
ps.animation_data.action = ac
fc = ac.fcurves.new(data_path=data_path)
fc.keyframe_points.add(len(keyframes))
for i in range(len(keyframes)):
bt = fc.keyframe_points[i]
bt.co = keyframes[i]
bt.interpolation = 'LINEAR'
return fc
def fabricate_text_animation(scn, ps, fc, extra={}):
# clobber old text
for obj in scn.objects:
if obj.type=='FONT':
scn.objects.unlink(obj)
extra_msg = ""
data_path = fc.data_path
for key, value in extra.items():
extra_msg = extra_msg + "\n" + key + "=" + str(value)
for fr in range(scn.frame_start, scn.frame_end + 1):
value_overlay("%s=%.2f%s" % (data_path, fc.evaluate(fr), extra_msg), fr, scn)
def find_particle_system_settings(scn):
"""scan the objects to find one with a particle system"""
for obj in scn.objects:
if obj.particle_systems is None:
continue
print ( len(obj.particle_systems))
return obj.particle_systems[-1].settings
return None
def make_scene_for(name, data_path, keyframes, ps_func, extra={}):
scn = bpy.data.scenes.get(name)
if scn is not None:
print("not creating scene %s"%name)
return
scn = bpy.data.scenes.new(name)
scn.frame_end = keyframes[-1][0]
s2= bpy.data.scenes.get("lights camera")
for obj in s2.objects:
scn.objects.link(obj)
if obj.type == 'CAMERA':
scn.camera = obj
scn.world = s2.world
scn.render.tile_x = 64
scn.render.tile_y = 64
scn.render.use_overwrite = False
scn.render.image_settings.compression=100
obj = particle_mesh()
scn.objects.link(obj)
scn.update()
print(scn.camera)
bpy.context.screen.scene = scn
scn.objects.active = obj
bpy.ops.object.particle_system_add()
ps = obj.particle_systems[-1].settings
ps_func(ps)
scn.render.filepath = "/var/tmp/blender/%s/%s/"%(ps.render_type,name)
#
fc = animate_parameter(ps, data_path, keyframes, extra)
fabricate_text_animation(scn, ps, fc, extra)
return scn
#
#
def child_parameters_1(ps_func=set_PS_dupli):
global KF_10
KF_10 = [[1, 0], [60, 1], [120, 4], [180, 10]]
KF_1_0 = [[1, 1], [60, 0]]
KF_1 = [[1, 0], [60, 1]]
# this can not be keyframed
# make_scene_for("hair_length", "hair_length", [ [1,4], [60,0], [61,4], [75,4], [135,10]], set_PS_dupli)
make_scene_for("length_random", "length_random", KF_1, ps_func)
make_scene_for("clump_factor", "clump_factor", [[1, -1], [61, 0], [120, 1]], ps_func)
make_scene_for("clump_shape", "clump_shape", [[1, -1], [60, 0], [76, 0], [135, 1]], ps_func, {"clump_factor":-1})
make_scene_for("child_length", "child_length", KF_1_0, ps_func)
make_scene_for("child_length_threshold", "child_length_threshold", KF_1_0, ps_func,
{"child_length": 0.3})
# parting?
make_scene_for("roughness_1", "roughness_1", [[1, 0], [60, 0.2], [120, 1], [180, 4]], ps_func)
make_scene_for("roughness_1_size", "roughness_1_size", KF_10, ps_func, {"roughness_1": 1})
make_scene_for("roughness_endpoint", "roughness_endpoint", [[1, 0], [60, 1], [120, 4]], ps_func)
make_scene_for("roughness_end_shape", "roughness_end_shape", KF_10, ps_func,
{"roughness_endpoint": 1})
make_scene_for("roughness_2", "roughness_2", KF_10, ps_func)
make_scene_for("roughness_2_size", "roughness_2_size", KF_10, ps_func, {"roughness_2":1})
make_scene_for("roughness_2_threshold", "roughness_2_threshold", KF_1, ps_func, {"roughness_2":1})
|
Blender python API quick-start
Syntax highlighting by Pygments.