見出し画像

文系の 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を含むカオス理論の研究で知られる。

CERNの大型ハドロン衝突型加速器が、ミニブラックホールを出現させる危険があるとして中止を求める訴訟を起こしたことでも有名。皮肉なことに、加速器にみえないこともない。

# 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

大型ハドロン衝突型加速器がミニ(マイクロ)ブラックホールを生む、という市民団体やレスラーらの訴えは結局退けられ、敗訴した。理論的にはできないこともないが、ごく微細でなんの影響もない、という説もあるようだが、わたしにはよくわからない。莫大な予算がよくわからない無駄な研究に費やされているという一般人の反感も含まれているようだ。

LHCで極小ブラックホール生成実験を行っても地球は消滅しない



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

講演活動をするスプロット教授。ちょっと昔のNHKの教育番組のようでなかなかおもしろい。Physics Demonstrations by Sprott(Youtube)


コード


コード自体は単純で短いものです。

  • 各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 スクリプトの実行自体は簡単。

  1.  Scripting メニューを選択しスクリプトワークスペースへ切り替える。

  2.  New(新規)ボタンを押し、スクリプトをコピー・ペーストする。

  3.  画面右の実行ボタン ▷ を押す。

画面左の3Dビューポート画面に、「奇妙な」カーブが表示されるはずだ。適宜、カーブに厚みをつける。

カーブプロパティ オブジェクトの高さ約 50 m



まとめ


以前、p5.js という javascript のグラフィックス系ライブラリに取り組んだことがあり、そのときもローレンス曲線を生成したことがあります。ただ、そのときは平面上のプロットだったので、いずれ3次元でと思っていました。

最初は、ジオメトリノードの学習も兼ねていたのですが、数式をノードで細々とつながなくてはならない時点で我慢がきかなくなり、python に切り替えることにしました。

ジオメトリノードはラーニングカーブが少しきつめな感じで、初歩的なプログラミングの知識があれば、いっそ python をいちから習ったほうがはやいのではないか、とも思えますが、どちらも得意なところや不得意なところがありますので、どちらもある程度できればそれにこしたことはないのでしょう。


参考


仕事の一部としてそれなりの時間を割いたこともあり、プログラムを書くのは嫌いではありません。コンピュータになにかをお願いするときのことばともいえるので、外国語の習得に近いと思っています。ただ、数式が混じってくると、とたんにスティーブン・キングの小説のような深い霧が脳内に満ちます。

この記事が気に入ったらサポートをしてみませんか?