アニメ風レンダリングが簡単にできるBlenderのFreestyleを試してみた。

Blender2.67から利用できるようになったFreestyleレンダリングが面白そうだったので、以前作ってみた動画で試してみました。

以前作った動画

今までにBlenderpythonを使って下記のような記事と動画を作りました。

Blenderの物理シミュレーションをpythonスクリプトで作成 - 株式会社CFlatの明後日スタイルのブログ

ミルククラウンをBlenderのpythonスクリプトで作成 - 株式会社CFlatの明後日スタイルのブログ

カオス的挙動をBlenderのpythonスクリプトで作成 - 株式会社CFlatの明後日スタイルのブログ

Freestyleでレンダリング

FreestyleでレンダリングするにはBlenderのバージョンを2.67以降に上げて、動画作成前に下記のコードを挿入するだけです。 bpy.data.scenes["Scene"].render.use_freestyle = True

ちなみに下記のコードを2回呼ばないと駄目だった不思議な現象はバージョンを上げると直っていました。 bpy.ops.object.forcefield_toggle()

実際の動画

下記がFreestyleでレンダリングした動画です。手作りアニメ風に仕上がっていて、物理シミュレーションなんて使っていないように見えるから不思議です。


Blenderの物理シミュレーション結果をFreestyleでレンダリング - YouTube


Blenderの物理シミュレーション結果をFreestyleでレンダリング2 - YouTube

流体シミュレーションのFreestyleレンダリング

ミルククラウンの動画についてはこんな問題があって修正に手間が掛かりそうだったので保留にしました。気が向けば作成するかもしれません。

カオス的挙動をBlenderのpythonスクリプトで作成

Blenderシリーズ第3段はカオス的挙動に挑戦してみました。

カオス的挙動

Blenderでは簡単に力場を設定できるので、もしかしたら簡単にカオス的挙動が作れるのではと思い実際にやってみました。
結果は最後に動画を載せておきますが、それっぽい動きをしてくれました。
序盤でポテンシャルの谷に捕まったかと思いきや、抜け出して全く違う方向に進むのが良い感じです。
結果が面白かったので力場の値を強くしましたが、動きが速すぎるのがちょっと残念でした。
もちろん力場の値を弱くしてもそれっぽい動きはしてくれます。
5つ設定した力場の内、真ん中が斥力、他の4つが引力に設定されています。

pythonスクリプト

下記が実際に使用したpythonスクリプトです。
玉と球形の土台を用意して、5つの力場を設定するだけです。
力場を設定するときになぜかbpy.ops.object.forcefield_toggle()を2回呼ぶ必要があったので注意して下さい。
pythonファイルの使用方法は以前の記事を参考にして下さい。
Blenderのバージョンは剛体シミュレーションが簡単になった2.66以上をお使い下さい。

# -*- coding: utf-8 -*-

import os
import bpy
import math

# 球を作成 (ブーリアンで使用した後、シミュレーションで使用)
bpy.ops.mesh.primitive_uv_sphere_add( location = ( 0, 0, 1 ) )
sphere = bpy.data.objects["Sphere"]
bpy.ops.object.shade_smooth()

# 球を後々の為に動的オブジェクトに指定しておく
bpy.ops.rigidbody.object_add()
sphere.rigid_body.mass = 0.1
sphere.rigid_body.friction = 0.0

# デフォルトで存在する立方体から球をブーリアンで引く
cube = bpy.data.objects["Cube"]
bpy.context.scene.objects.active = cube
bpy.ops.object.shade_smooth()
bpy.ops.object.modifier_add( type = 'BOOLEAN' )
cube.modifiers["Boolean"].operation = 'DIFFERENCE'
cube.modifiers["Boolean"].object = sphere
bpy.ops.object.modifier_apply( modifier = "Boolean" )

# 立方体を静的オブジェクトに指定
bpy.ops.rigidbody.object_add( type='PASSIVE' )
cube.rigid_body.friction = 0.0

# 球を転がす用のサイズに変更
sphere.location = ( 0.9, 0, 1 )
sphere.scale = ( 0.1, 0.1, 0.1 )

# 5つの空のオブジェクトを配置
bpy.ops.object.empty_add(type = 'SPHERE', location = (0, 0, 0 ))
empty0 = bpy.data.objects["Empty"]
bpy.ops.object.empty_add(type = 'SPHERE', location = (0.7, 0, 0 ))
empty1 = bpy.data.objects["Empty.001"]
bpy.ops.object.empty_add(type = 'SPHERE', location = (0, 0.7, 0 ))
empty2 = bpy.data.objects["Empty.002"]
bpy.ops.object.empty_add(type = 'SPHERE', location = (-0.7, 0, 0 ))
empty3 = bpy.data.objects["Empty.003"]
bpy.ops.object.empty_add(type = 'SPHERE', location = (0, -0.7, 0 ))
empty4 = bpy.data.objects["Empty.004"]
empty = [empty0, empty1, empty2, empty3, empty4]

# 空のオブジェクトに力場を設定。なぜかforcefield_toggle()を2回呼ぶ必要がある
for e in empty:
  bpy.context.scene.objects.active = e
  bpy.ops.object.forcefield_toggle()
  bpy.ops.object.forcefield_toggle()
  e.field.strength = -300

empty0.field.strength = 250

# カメラ
bpy.data.objects["Camera"].location = ( 2, 2, 5 )
bpy.data.objects["Camera"].rotation_euler = ( math.pi/6, 0, math.pi*3/4 )
bpy.data.cameras["Camera"].lens = 30

# 照明
bpy.data.objects["Lamp"].location = (0, 1, 10)
bpy.data.objects["Lamp"].rotation_euler = ( -math.pi/60, -math.pi/120, math.pi/12 )
bpy.data.lamps["Lamp"].type = 'SUN'

# 物理シミュレーション
bpy.ops.ptcache.bake_all()

# 動画作成
bpy.context.scene.render.resolution_x = 400
bpy.context.scene.render.resolution_y = 300
bpy.context.scene.render.resolution_percentage = 100
bpy.context.scene.render.image_settings.file_format = 'AVI_JPEG'
bpy.data.scenes["Scene"].render.filepath = "test.avi"
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = 250
bpy.ops.render.render(animation=True)

# 保存
savePath = os.path.abspath(os.path.dirname(__file__))
bpy.path.relpath(savePath)
bpy.ops.wm.save_as_mainfile(filepath="test.blend", relative_remap=True)

動画完成

それではカオス的挙動を動画でご覧下さい。

ミルククラウンをBlenderのpythonスクリプトで作成

こんにちは、株式会社CFlatです。

blenderの流体シミュレーションを試してみたかったので、pythonスクリプトミルククラウンを作ってみることにしました。
適当にオブジェクトを配置して、特にパラメーターを凝らなくても下図にあるミルククラウン風の結果が出たのでちょっと驚きました。

それではここからpythonファイルの解説をしていきます。最後に動画も載せておきます。

ミルクのマテリアル設定

ミルクのマテリアルはここからダウンロードしました。
ダウンロードしたmilk.blendをpythonファイルと同じディレクトリにおいてappendすればmilk.blend内のマテリアルが利用できます。

流体シミュレーションの設定

このpythonファイルを実行するときは重いので注意して下さい。私の環境で5分ほど掛かります。
もっと軽くしたければドメインのResolution値を小さくしたり、フレーム数を小さくして下さい。
流体のパラメーターはpresetにあったoilの値を使用しました。
流体シミュレーションの設定はここに詳しく書かれています。

流体シミュレーションの終了通知

bpy.ops.fluid.bake("INVOKE_DEFAULT")で流体シミュレーションが開始されますが別スレッドで実行されるため、
そのままだと流体シミュレーションが終わる前に動画作成を行ってしまいます。
流体シミュレーションの終了通知が分からなかったので、今回はキャッシュファイルの存在を調べることで代用しました。
スクリプトを実行する際はpythonファイルと同じディレクトリにcacheフォルダを作成してから実行する必要があります。
誰かもっと良い方法を知っていれば教えて下さい。

pythonスクリプト

下記が実際に使用したpythonスクリプトです。
ドメインを作成して、水たまりと水滴をFluidに設定するだけで簡単に流体シミュレーションが実行できます。
pythonファイルの使用方法は以前の記事を参考にして下さい。

# -*- coding: utf-8 -*-

import os
import bpy
import math
import time

#デフォルトで存在しているメッシュやマテリアルを全て削除
for item in bpy.context.scene.objects:
  if item.type == 'MESH':
    bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
  if item.type == 'MESH':
    bpy.data.objects.remove(item)
for item in bpy.data.meshes:
  bpy.data.meshes.remove(item)
for item in bpy.data.materials:
  bpy.data.materials.remove(item)

#Cubeを追加し流体シミュレーションのドメインに指定
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0))
cube = bpy.data.objects["Cube"]
bpy.context.scene.objects.active = cube
bpy.ops.object.modifier_add(type='FLUID_SIMULATION')
cube.modifiers["Fluidsim"].settings.type = 'DOMAIN'
cube.modifiers["Fluidsim"].settings.end_time = 1
cube.modifiers["Fluidsim"].settings.viscosity_base = 5.0
cube.modifiers["Fluidsim"].settings.viscosity_exponent = 5
cube.modifiers["Fluidsim"].settings.filepath = "cache"

#ミルクのマテリアルを設定
bpy.ops.wm.link_append(directory="./milk.blend/Material/", link=False, filename="Milk.001")
obj = bpy.context.scene.objects.active
obj.data.materials.append(bpy.data.materials['Milk.001'])

cube.select = False

#ドメインの底に水を張る
bpy.ops.mesh.primitive_cube_add(location=(0, 0, -0.9))
bottom = bpy.data.objects["Cube.001"]
bpy.context.scene.objects.active = bottom
bottom.scale.z = 0.1

#bottomをFluidに設定
bpy.ops.object.modifier_add(type='FLUID_SIMULATION')
bottom.modifiers["Fluidsim"].settings.type = 'FLUID'

#透明マテリアルを作成してbottomに設定
transparent_mat = bpy.data.materials.new("transparent")
obj = bpy.context.scene.objects.active
obj.data.materials.append(bpy.data.materials['transparent'])
transparent_mat.type = 'VOLUME'
transparent_mat.volume.density_scale = 0
transparent_mat.use_raytrace = False

bottom.select = False

#水滴を作成
bpy.ops.mesh.primitive_uv_sphere_add(location=(0, 0, 0.5))
sphere = bpy.data.objects["Sphere"]
bpy.context.scene.objects.active = sphere
sphere.scale = ( 0.2, 0.2, 0.2 )

#sphereをFluidに設定
bpy.ops.object.modifier_add(type='FLUID_SIMULATION')
sphere.modifiers["Fluidsim"].settings.type = 'FLUID'

#水滴に透明マテリアルを設定
obj = bpy.context.scene.objects.active
obj.data.materials.append(bpy.data.materials['transparent'])

sphere.select = False

#カメラ
bpy.data.objects["Camera"].location = (2, 2, 1)
bpy.data.objects["Camera"].rotation_euler = ( math.pi/3, 0, math.pi*3/4 )
bpy.data.cameras["Camera"].lens = 20

#照明
bpy.data.objects["Lamp"].location = (-2, 2, 10)
bpy.data.objects["Lamp"].rotation_euler = ( math.pi/6, 0, math.pi*7/6 )
bpy.data.lamps["Lamp"].type = 'SUN'

#ドメインをアクティブにして流体シミュレーション
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = 240
bpy.context.scene.objects.active = cube
bpy.ops.fluid.bake("INVOKE_DEFAULT")

#流体シミュレーションが終わるまで待機
while True:
  print('now simulationing...')
  if os.path.exists("cache/fluidsurface_final_0240.bobj.gz"):
    break
  else:
    time.sleep(3)

# 動画作成
bpy.context.scene.render.resolution_x = 400
bpy.context.scene.render.resolution_y = 300
bpy.context.scene.render.resolution_percentage = 100
bpy.context.scene.render.image_settings.file_format = 'AVI_JPEG'
bpy.data.scenes["Scene"].render.filepath = "test.avi"
bpy.ops.render.render(animation=True)

# 保存
savePath = os.path.abspath(os.path.dirname(__file__))
bpy.path.relpath(savePath)
bpy.ops.wm.save_as_mainfile(filepath="test.blend", relative_remap=True)

動画完成

前回と同じく出力されたtest.aviをaviutlを使用して逆再生+再生すれば下記の動画が出来上がります。
ミルククラウンとしての完成度は低いですが、パラメーターをきちんと設定すればもっときれいなミルククラウンができると思います。

Blenderの物理シミュレーションをpythonスクリプトで作成

こんにちは、株式会社CFlatです。

この動画が面白かったので、似たような動画をpythonスクリプトで作ってみることにしました。
環境はmac+Blender2.66以上ですが、windowsでも下にあるpythonファイルを使えば簡単に実行できると思います。

ターミナルでBlenderを起動する

pythonスクリプトBlender起動中にも実行できますが、今回はターミナルから実行したいと思います。
ターミナルでBlenderを起動するには下記のようなaliasを.bash_profileに設定しておくと便利です。

alias blender='/Applications/blender/blender.app/contents/MacOS/blender'

.bash_profileを変更した後は"source .bash_profile"を一度入力して下さい。以降は"blender"と入力するだけでBlenderが起動します。
Blenderを起動した後にtest.pyを実行するには下記のようにターミナルで実行します。

blender --python test.py

Blenderをバックグラウンドで実行するには下記のように--backgourndを付け加えます。

blender --background --python test.py

pythonスクリプト

下記が実際に使用したpythonスクリプトです。
立方体と平面を作成して、それぞれ動的と静的な剛体に設定するだけで簡単に物理シミュレーションが実行できます。

# -*- coding: utf-8 -*-

import os
import bpy
import math

#デフォルトで存在しているCubeを削除
bpy.ops.object.delete()

#Cube作成
N = 10
for x in range(0, N):
  for y in range(0, N):
    for z in range(0, N):
      bpy.ops.mesh.primitive_cube_add(location=(x*2, y*2, z*2))
      bpy.ops.rigidbody.object_add()

#平面作成
bpy.ops.mesh.primitive_plane_add(location=(N-1, N-1, -10))
bpy.ops.rigidbody.object_add(type='PASSIVE')
bpy.data.objects["Plane"].scale = (N+10, N+10, 1)

#カメラ
bpy.data.objects["Camera"].location = (N+20, N+20, N+20)
bpy.data.objects["Camera"].rotation_euler = (math.pi/6, 0, math.pi*3/4)
bpy.data.cameras["Camera"].lens = 10

#照明
bpy.data.objects["Lamp"].location = (0, 0, N+10)
bpy.data.lamps["Lamp"].type = 'SUN'

# 物理シミュレーション
bpy.ops.ptcache.bake_all()

# 動画作成
bpy.context.scene.render.resolution_x = 400
bpy.context.scene.render.resolution_y = 300
bpy.context.scene.render.resolution_percentage = 100
bpy.context.scene.render.image_settings.file_format = 'AVI_JPEG'
bpy.data.scenes["Scene"].render.filepath = "test.avi"
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = 200
bpy.ops.render.render(animation=True)

# 保存
savePath = os.path.abspath(os.path.dirname(__file__))
bpy.path.relpath(savePath)
bpy.ops.wm.save_as_mainfile(filepath="test.blend", relative_remap=True)

動画完成

出力されたtest.aviをaviutlを使用して逆再生+再生すれば下記の動画が出来上がります。
逆再生動画って面白いですよね。他にも色々作ってみたいと思います。