文系の blender 4.0 python で作る 奇妙なアトラクタ
Strange Attractor (奇妙なアトラクタ)は、カオスやフラクタル理論でよくみる曲線のことで、それじたいは単純な数式で生成されていますが、繰り返しを重ねることで、確かに奇妙で複雑な紐のような図形が現れます。
書籍などでみる図の多くは2次元上のプロットですが、3DCGらしく3次元上に生成してみます。ここでは、python で作ってみました。
環境 Blender 4.0.2 , Mac Mini M1 OS 14.2
Lorenz
Edward Norton Lorenz(エドワード・ローレンツ)は「バタフライ・エフェクト」で有名なアメリカの気象学者。気象現象のように複雑な系であっても、もとは比較的単純な数式の繰り返しによるものだ、というフラクタル理論の骨子を具象化している。すこし蝶にも似ている。
# Define the Lorenz equations
def strange(x, y, z, sigma=8, rho=28, beta=8/3):
dx = sigma * (y - x)
dy = x * (rho - z) - y
dz = x * y - beta * z
return dx, dy, dz
# Parameters
num_steps = 1000
dt = 0.02
x, y, z = 0.1, 0.0, 0.0
# Define the Lorenz equations
def strange(x, y, z, sigma=18, rho=18, beta=8/3):
dx = sigma * (y - x)
dy = x * (rho - z) - y
dz = x * y - beta * z
return dx, dy, dz
# Parameters
num_steps = 3000
dt = 0.02
x, y, z = 0.1, 0.0, 0.0
# Define the Lorenz equations
def strange(x, y, z, sigma=28, rho=14, beta=8/3):
dx = sigma * (y - x)
dy = x * (rho - z) - y
dz = x * y - beta * z
return dx, dy, dz
# Parameters
num_steps = 3000
dt = 0.02
x, y, z = 0.1, 0.0, 0.0
Rössler
Otto Eberhard Rössler(オットー・レスラー)はドイツの生物化学者。このRössler attractorを含むカオス理論の研究で知られる。
# Define the Rössler equations
def strange(x, y, z, ra=0.1, rb=0.1, rc=14):
dx = -y - z
dy = x + (ra * y)
dz = z * (x - rc) + rb
return dx, dy, dz
# Parameters
num_steps = 18000
dt = 0.02
x, y, z = 0.1, 0.0, 0.0
# Define the Rössler equations
def strange(x, y, z, ra=0.3, rb=0.3, rc=2):
dx = -y - z
dy = x + (ra * y)
dz = z * (x - rc) + rb
return dx, dy, dz
# Parameters
num_steps = 10000
dt = 0.02
x, y, z = 0.1, 0.0, 0.0
Sprott
Julien Clinton Sprott はアメリカの物理学者。カオス理論についての一般向書籍の執筆や、物理学に関する講演活動などを行っている。
# Define the sprott equations
def strange(x, y, z, sa=0.4, sb= 1.2, sc= 1):
dx = sa * y * z
dy = x - sb * y
dz = sc - x * y
return dx, dy, dz
# Parameters
num_steps = 3000
dt = 0.1
x, y, z = 0.1, 0.0, 0.0
# Define the sprott equations
def strange(x, y, z, sa=0.1, sb= 1.6, sc= 2):
dx = sa * y * z
dy = x - sb * y
dz = sc - x * y
return dx, dy, dz
# Parameters
num_steps = 6000
dt = 0.1
x, y, z = 0.1, 0.0, 0.0
コード
コード自体は単純で短いものです。
各Attractorの関数とパラメータ(上で付記)を記述。下はLorenzの場合。
import bpy
import numpy as np
# Define the lorenz equations
def strange(x, y, z, sa=0.4, sb= 1.2, sc= 1):
dx = sa * y * z
dy = x - sb * y
dz = sc - x * y
return dx, dy, dz
# Parameters
num_steps = 3000
dt = 0.1
x, y, z = 0.1, 0.0, 0.0
関数で生成された座標を配列に保存。
# Generate trajectory
trajectory = []
for i in range(num_steps):
trajectory.append([x, y, z])
dx, dy, dz = strange(x, y, z)
x += dt * dx
y += dt * dy
z += dt * dz
NURB カーブを作成し、座標の数の spline point を加え、それぞれのpointに(x, y, z)座標と nurbs weight を設定。
# make a new curve
crv = bpy.data.curves.new('crv', 'CURVE')
crv.dimensions = '3D'
# make a new spline in that curve
spline = crv.splines.new(type='NURBS')
# a spline point for each point
spline.points.add(len(trajectory)-1) # theres already one point by default
for p, new_co in zip(spline.points, trajectory):
p.co = (new_co + [1.0]) # (add nurbs weight)
生成したカーブをオブジェクトとしてシーンに追加。
# make a new object with the curve
obj = bpy.data.objects.new('strangers', crv)
bpy.context.scene.collection.objects.link(obj)
コード全体
Lorenzの場合。アトラクタを変更する場合は、上部の equations and parameters 枠を、それぞれの記述に変更する。
import bpy
import numpy as np
#equations and parameters
#--------------------------------------------
# Define the lorenz equations
def strange(x, y, z, sa=0.4, sb= 1.2, sc= 1):
dx = sa * y * z
dy = x - sb * y
dz = sc - x * y
return dx, dy, dz
# Parameters
num_steps = 3000
dt = 0.1
x, y, z = 0.1, 0.0, 0.0
#--------------------------------------------
# Generate trajectory
trajectory = []
for i in range(num_steps):
trajectory.append([x, y, z])
dx, dy, dz = strange(x, y, z)
x += dt * dx
y += dt * dy
z += dt * dz
# make a new curve
crv = bpy.data.curves.new('crv', 'CURVE')
crv.dimensions = '3D'
# make a new spline in that curve
spline = crv.splines.new(type='NURBS')
# a spline point for each point
spline.points.add(len(trajectory)-1) # theres already one point by default
for p, new_co in zip(spline.points, trajectory):
p.co = (new_co + [1.0]) # (add nurbs weight)
# make a new object with the curve
obj = bpy.data.objects.new('stranger', crv)
bpy.context.scene.collection.objects.link(obj)
# Optionally, add materials or lights to enhance the visualization
スクリプトの実行
blender では、python スクリプトの実行自体は簡単。
Scripting メニューを選択しスクリプトワークスペースへ切り替える。
New(新規)ボタンを押し、スクリプトをコピー・ペーストする。
画面右の実行ボタン ▷ を押す。
画面左の3Dビューポート画面に、「奇妙な」カーブが表示されるはずだ。適宜、カーブに厚みをつける。
まとめ
以前、p5.js という javascript のグラフィックス系ライブラリに取り組んだことがあり、そのときもローレンス曲線を生成したことがあります。ただ、そのときは平面上のプロットだったので、いずれ3次元でと思っていました。
最初は、ジオメトリノードの学習も兼ねていたのですが、数式をノードで細々とつながなくてはならない時点で我慢がきかなくなり、python に切り替えることにしました。
ジオメトリノードはラーニングカーブが少しきつめな感じで、初歩的なプログラミングの知識があれば、いっそ python をいちから習ったほうがはやいのではないか、とも思えますが、どちらも得意なところや不得意なところがありますので、どちらもある程度できればそれにこしたことはないのでしょう。
参考
この記事が気に入ったらサポートをしてみませんか?