- Blender Python スクリプト -

スクリプト集

ちょっとしたスクリプトを、コピペで貼って再利用しようという意図での自分用倉庫です。

毎フレーム処理が必要な場合のハンドラー関数の登録

import bpy

def Function(scene):
    #Do something

def handler(scene):
    #frame = scene.frame_current
    #print (frame)
    Function(scene)

bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(handler)
#bpy.app.handlers.render_pre.clear()
#bpy.app.handlers.render_pre.append(handler)

選択しているオブジェクト群を、流体の障害物に設定(アニメーションメッシュ有)

import bpy

for object in bpy.context.selected_objects:
    bpy.context.scene.objects.active = object
    bpy.ops.object.modifier_add(type='FLUID_SIMULATION')
    object.modifiers["Fluidsim"].settings.type = 'OBSTACLE'
    object.modifiers["Fluidsim"].settings.use_animated_mesh=True

パーティクルの回転方向を45度刻みでランダム回転(ものの配置など用)

パーティクルの設定がNewtonian でないと、回転が戻ってしまうのに注意

def RotateParticles(scene):
    obj = scene.objects['Town']
    ptr = obj.particle_systems["ParticleSystem"].particles
    
    random.seed(1)
    print ('rotate')
    print (len(ptr))
    for p in ptr:        
        #print (p.rotation) 
        rotangle = random.randint(0, 7)  * 45
        mat_rot = mathutils.Matrix.Rotation(radians(rotangle), 4, 'Z')
        qtr_rot = mat_rot.to_quaternion()
        p.rotation = mathutils.Quaternion((1,0,0,0)) * qtr_rot 

    bpy.context.scene.objects.active = bpy.context.scene.objects.active    #trigger refresh

RotateParticles(bpy.context.scene)

メッシュの名前をオブジェクトの名前と同一にする

シングルユーザーで無い場合はスキップします

import bpy
for item in bpy.context.selected_objects:
    name = item.name
    if (item.data.users == 1):
        item.data.name = name;
        print (name)

メタボールのメッシュ形状をオブジェクトにコピー(On the fly)

import bpy

def handler(scene):
    objTarget = bpy.data.objects['Target']
    meshTargetOld = objTarget.data
    materialTargetOld = objTarget.material_slots[0].material
    objSource = bpy.data.objects['Mball']

    mesh = objSource.to_mesh(scene, True, 'PREVIEW')
    mesh.materials.append(materialTargetOld)

    objTarget.data = mesh
    bpy.data.meshes.remove(meshTargetOld)
   
bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(handler)

メタボールのメッシュ形状をオブジェクトにコピー(メッシュは再利用のため記憶)

import bpy

def handler(scene):
    frame = scene.frame_current
    name = "MeshSeq.%04d" % frame
        
    objTarget = bpy.data.objects['Target']
    meshTargetOld = objTarget.data
    materialTargetOld = objTarget.material_slots[0].material
    objSource = bpy.data.objects['Mball']

    mesh = objSource.to_mesh(scene, True, 'PREVIEW')
    mesh.materials.append(materialTargetOld)
    
    for meshItem in bpy.data.meshes:
        if (meshItem.name == name):
            meshItem.use_fake_user = False
            bpy.data.meshes.remove(meshItem)
            print("remove:" + name)
    
    mesh.name = name
    mesh.use_fake_user = True

    objTarget.data = mesh
    #bpy.data.meshes.remove(meshTargetOld)
    print(name)
   
bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(handler)

外部のライブラリから連番メッシュを読み込む。

同じライブラリから同名メッシュを読んでも、同じものが複数作られることはなさそうなので、複数回実行しても問題ない。
別ライブラリから同名メッシュは読めて同名のメッシュが登録される点に留意。

import bpy

directory = "D:\\cygwin64\\home\\takedatk\\BLENDER\\TESTS2\\SmokeMeshExplosion01.blend\\Mesh\\"

for i in range(1,200):
    print(i)
    name = "MeshSeq.%04d" % i
    
    bpy.ops.wm.link(directory=directory, filename=name)

オブジェクトに毎フレームごと別メッシュを割り振る

外部ライブラリのメッシュを使うときには、同一名のメッシュがありえるので、directory 情報を使う
directry は相対パスと絶対パスなどで間違えやすいので、読み込んだメッシュに対して
bpy.data.mesh['MeshSeq.0010'].library.filepath
などであらかじめ確認すると良さそう。

import bpy

def Link(objName, directory, frame):
    if (frame < 0):
        frame = 1
    name = "MeshSeq.%04d" % frame
    bpy.data.objects[objName].data = bpy.data.meshes.get((name, directory))

def handler(scene):
    directory = "//file.blend" # None for local data
    frame = scene.frame_current
    Link('Target', directory, frame)

bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(handler)

なんちゃって多足歩行用足先移動スクリプト



Follow Path と Shrinkwrap のオフセット値を歩く雰囲気で変化させる。

WalingTip.blend

import bpy
import fnmatch
import math
import mathutils

# Accuracy of height depends on accuracy of shrinkwrap constraints.
# Sometimes shrinkwrap acts oddly.

def WalkingTip(scene):
    frame = scene.frame_current
    data = bpy.data
    skip = [ 0, 0, 0 ]
    offset = [ 0, 12, 0]
    cycle = [ 12, 12, 1] # not used for body. must not be 0.
    smooth = [0, 0, 1] # 0=tip 1=body
    for num in range (0, 3):
        
        name = "Tip.%03d" % num
        if not name in (scene.objects):
            continue
        if (skip[num] == 1):
            continue
        
        obj = scene.objects[name]
    
        timeScaling = 1
        speed = 2
        rotCycle = cycle[num]
        localTime = timeScaling * frame + offset[num]
        normedTheta = localTime / rotCycle
        modTheta = normedTheta % 2

        if (modTheta >=1):
            eval = speed * (localTime/ 2 - (modTheta - 2) * rotCycle / 2 ) # flat           
        else:
            theta = 3.14159*2*normedTheta;
            eval = speed * ((localTime + modTheta * rotCycle)/2 - 2*3.14159 / rotCycle * math.sin(theta))
            
        if (smooth[num] == 1):
            eval = speed * localTime / 2
            
        obj.constraints['Follow Path'].offset = -eval #-100 + eval;
        
        if 'Shrinkwrap' in (obj.constraints):
            distance = 0
            if (modTheta < 1):
                distance = 0.1 * math.sin(theta/2)
            if (smooth[num] == 1):
                distance = 2 + 0.5 * math.sin(normedTheta*3.14159) # oscilation of body;
                
            obj.constraints['Shrinkwrap'].distance = distance

def handler(scene):
    WalkingTip(scene)

bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(handler)

inserted by FC2 system