LoginSignup
3
1

More than 3 years have passed since last update.

Blenderスクリプトでプロシージャルにいのちを輝かせる

Posted at

image.png

 Blenderのスクリプトで、万博で話題になったアレのような何かを生み出していきます。乱数を基にプロシージャルに生み出しているので、無数のパターンのアレを生み出せます。Blenderのバージョンは2.8です。

第1段階 球の生成

image.png

import bpy
import numpy as np

#ここで赤マテリアルを設定
bpy.data.materials.new(name = 'red')
mat_red = bpy.data.materials['red']
mat_red.use_nodes = False
mat_red.diffuse_color = (1,0,0,1)

#球の生成
bpy.ops.mesh.primitive_uv_sphere_add(radius=1,location=(0,0,0))
bpy.ops.object.material_slot_add()
bpy.context.object.active_material=mat_red

 プリミティブの生成と簡単なマテリアルの指定で赤い球を生み出していきます。bpy.ops.mesh.primitive_uv_sphere_addでUV球を生み出すことができます。

第2段階 球の増殖

 この赤球を無数に生み出したいところですが、単なるfor文でやるよりも、何らかの連続性があった方がいのちが輝いてる感が出てくるので、ここは再帰関数を使って実装していくことにします。再帰関数とは自分自身をコピーしながら生み出してくようなプログラムのことです(超適当)。
image.png

import bpy
import numpy as np

#ここで赤マテリアルを設定
bpy.data.materials.new(name = 'red')
mat_red = bpy.data.materials['red']
mat_red.use_nodes = False
mat_red.diffuse_color = (1,0,0,1)

def add_sphere(r,x,y,z,count):
    if count > 20: #これがないと無限ループ
        return
    bpy.ops.mesh.primitive_uv_sphere_add(radius=r,location=(x,y,z))
    bpy.ops.object.material_slot_add()
    bpy.context.object.active_material=mat_red
    add_sphere(r,x+1,y,z,count+1) #自分自身のコピーを呼び出す
    return

add_sphere(1,0,0,0,1)

 add_sphereという関数で球を生成していますが、この中で更にadd_sphereという関数を呼び出しています。しかしまったく同じではなく、自分自身よりxに1ずれたコピーを生み出します。そのコピーはさらに1ずらした……という無限ループが発生し、連続性を持ったプロセスをシンプルに記述できます。これは単に横移動しただけですが、例えばadd_sphere(1.1*r,y,x+1,z,count+1)のようなコマンドにすれば、以下のようになります。

image.png

 生命の神秘を感じますね。

第3段階 ランダム性を加える

 しかしこれだと規則的すぎていまいち輝きを感じません。元ネタを見ると、いくつもの大きさが異なる赤球がつらなってリング状になっているようです。やはり大きさに多少バリエーションがあった方が生命感が出るようです。お互いの発生位置も、親から子にぎりぎり接しながら伸びていくような形にします。

image.png

import bpy
import numpy as np #numpyを追加インポート

#ここで赤マテリアルを設定
bpy.data.materials.new(name = 'red')
mat_red = bpy.data.materials['red']
mat_red.use_nodes = False
mat_red.diffuse_color = (1,0,0,1)

def add_sphere(r,x,y,z,count):
    if count > 20: #これがないと無限ループ
        return
    bpy.ops.mesh.primitive_uv_sphere_add(radius=r,location=(x,y,z))
    bpy.ops.object.material_slot_add()
    bpy.context.object.active_material=mat_red
    #ランダムに経度と緯度を指定
    theta = np.random.rand()*np.pi*2
    phi = (np.random.rand()-0.5)*np.pi
    #新しい座標を指定
    nr = r*(0.5 + np.random.rand())#子の球は親の0.5倍~1.5倍
    nx = x+(r+nr)*np.cos(theta)*np.cos(phi)
    ny = y+(r+nr)*np.sin(theta)*np.cos(phi)
    nz = z+(r+nr)*np.sin(phi)
    add_sphere(nr,nx,ny,nz,count+1)#自分自身のコピーを呼び出す
    return

add_sphere(1,0,0,0,1)

第4段階 目玉を加える

 キュートな目玉を加えていきます。テクスチャを設定できれば楽ですが、ここはプリミティブだけで描画することにします。

image.png

 だいぶ輝いてきました。あとは少しシェーディングを整えてレンダリングすれば、冒頭のようないのち輝く画像を生成することができます。

 コードは、ちょっと冗長な部分が多くなるので、一部を関数化して簡略化しています。

import bpy
import numpy as np #numpyを追加インポート

#マテリアルの設定を3つ書くのは長くなるので関数化
def create_material(color_name,r,g,b):
    bpy.data.materials.new(name = color_name)
    mat = bpy.data.materials[color_name]
    mat.use_nodes = False
    mat.diffuse_color = (r,g,b,1)
    return mat

mat_red = create_material('red',1,0,0)
mat_white = create_material('white',1,1,1)
mat_eye = create_material('eye',0,1.5,1)

#座標の指定を3つ書くのは長くなるので一部関数化
def next_params(x,y,z,theta,phi,dist):
    nx = x + dist*np.cos(theta)*np.cos(phi)
    ny = y + dist*np.sin(theta)*np.cos(phi)
    nz = z + dist*np.sin(phi)
    return nx,ny,nz

#UV球の生成を3つ書くのは長くなるので一部関数化
def create_sphere(r,x,y,z,mat):
    bpy.ops.mesh.primitive_uv_sphere_add(radius=r,location=(x,y,z))
    bpy.ops.object.material_slot_add()
    bpy.context.object.active_material=mat
    return

#ついでに角度の生成も関数化
def create_angular():
    theta = np.random.rand()*np.pi*2
    phi = (np.random.rand()-0.5)*np.pi
    return theta,phi

def add_sphere(r,x,y,z,count):
    if count > 20: #これがないと無限ループ
        return
    create_sphere(r,x,y,z,mat_red)
    theta,phi = create_angular()
    nr = r*(0.5 + np.random.rand())
    nx,ny,nz = next_params(x,y,z,theta,phi,r+nr)
    add_sphere(nr,nx,ny,nz,count+1)#自分自身のコピーを呼び出す
    #白目を生成(これはただの関数)
    theta,phi = create_angular()
    nx,ny,nz = next_params(x,y,z,theta,phi,r/3)
    create_sphere(0.8*r,nx,ny,nz,mat_white)
    #瞳を生成(これはただの関数)
    nx,ny,nz = next_params(x,y,z,theta,phi,r/2)
    create_sphere(0.65*r,nx,ny,nz,mat_eye)
    return

add_sphere(1,0,0,0,1)

第5段階 パラメータ調整

 途中で二股に分かれるようにしたり、子の球のサイズを小さくするようにすると、また違った生命の美しさを見ることができます。

image.png

 興味のある方は、色々とパラメータを変えて遊んでみるのも良いかもしれません。ただし、count > 20のあたりを変更すると、プログラムの組み方によってはオブジェクト量が指数関数的に増えてBlenderがフリーズすることがあるのでご注意ください。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1