見出し画像

単純な本棚の本(マリオネットオブジェクト)

だいぶ前にvectorscriptをいじろうと思ったことがありました。

その時に単純なランダムの代わりに1/fゆらぎに近い間欠カオスを使ってルーバーやらのテストをしてたのですが、本棚の本の生成はマリオネットオブジェクトにすれば使えそうだと言うことで再度作ってみることに。

Stephan Moenninghoff氏のParametric Books

本のマリオネットオブジェクトとしては、Stephan Moenninghoff氏のものを以前みつけて使ってみたことがあります。

画像1

めちゃめちゃリアルで良いのですが、めちゃめちゃ重いです。

プレゼンの重要な場面で使うのには良さそうですが、私の環境では、普段遣いにするには少し負荷が大きすぎました。

ということで簡単なものを作ってみます。

ノード構成

ノードは下のような構成に

画像2

棚の横幅を決めるとその範囲に納まるように本(単純な箱)を生成します。

パラメーターとしては本の幅の最小値と最大値、および本の倒れ角の最大値が設定できるようにしています。

また、A6版からB4版まで、どのサイズを使用するかを選択できるようにしています。

画像3

コード

bookノードのコードは下のとおり。

@Marionette.NodeDefinition
class Params(metaclass = Marionette.OrderedClass):
#APPEARANCE
	#Name
	this = Marionette.Node( "book" )
	this.SetDescription( "本棚用のシンプルな本を作成" )

	#Input Ports
	w = Marionette.PortIn( 2000, 'nWidth' )
	w.SetDescription('本棚の幅')
	bwmin = Marionette.PortIn( 5, 'iBwMin' )
	bwmin.SetDescription('本の幅最小値')
	bwmax = Marionette.PortIn( 30, 'iBwMax' )
	bwmax.SetDescription('本の幅最大値')
	br = Marionette.PortIn( 6, 'iBR' )
	br.SetDescription('本の倒れ角最大値(br<15)')
	cls = Marionette.PortIn( '', 'class' )
	cls.SetDescription('本のクラス')
	bk1 = Marionette.PortIn( True, 'bB4' )
	bk2 = Marionette.PortIn(True, 'bA4' )
	bk3 = Marionette.PortIn( True, 'bB5' )
	bk4 = Marionette.PortIn( True, 'bA5' )
	bk5 = Marionette.PortIn( True, 'bB6' )
	bk6 = Marionette.PortIn( True, 'bA6' )


	#OIP Controls

	#Output Ports
	h = Marionette.PortOut()
	h.SetDescription('Handle to Symbol object')

#BEHAVIOR
	this.SetLinksObjects()
	
def RunNode(self):
	#inputs
	w = self.Params.w.value #本棚の幅	
	bwmin = self.Params.bwmin.value #本の幅最小値
	bwmax = self.Params.bwmax.value #本の幅最大値
	br = self.Params.br.value #本の倒れ角最大値
	cls = self.Params.cls.value #本のクラス
	bk = [] #種類ごとに使用するか
	bk.append(self.Params.bk1.value)
	bk.append(self.Params.bk2.value)
	bk.append(self.Params.bk3.value)
	bk.append(self.Params.bk4.value)
	bk.append(self.Params.bk5.value)
	bk.append(self.Params.bk6.value)
		
	#----------------------------------------------------------
	#script-----------------------------------------------------
	#----------------------------------------------------------
	import random as r
	import math
	
	def ichaos( a , min , max , step , cut ): #間欠カオス関数
		b = int ( a* ( max - min + step ) / step ) * step + min
		if a < 0.5:
			a = a+2*a*a
		else:
			a = a-2*(1-a)*(1-a)
		if a < cut or a > (a-cut):
			a = r.random()	
		return (a,b)
		
	size0 = [ (257,364),(210,297),(182,257),(148,210),(128,182),(105,148) ] #本の基本サイズ		

	if w < 300:
		w = 300
	if br < 0:
		br = 1
	if br > 15:
		br = 15
	if bwmin < 3:
		bwmin = 3
	if bwmax < bwmin:
		bwmax = bwmin + 1
	
	i = 0
	bksize = [] #使用する本のサイズリスト	
	for boo in bk:
		if boo :
			bksize.append(size0[i])
		i+= 1
	
	if len(bksize) == 0:
		i = r.randint(0,5)
		bksize.append( size0[i] )
	x = 0 #本のX座標		
	a1 = r.random() #Ichaos用 0≦a≦1
	a2 = r.random() #Ichaos用 0≦a≦1
	a3 = r.random() #Ichaos用 0≦a≦1
	a4 = r.random() #Ichaos用 0≦a≦1
	(a4 , bks) = ichaos( a4 , 0 , len(bksize)-1 , 1 , 0.05) #描画する本の種類	
	
	while x < w:
		(a1,w1) = ichaos(a1 , bwmin , bwmax , 1 , 0.01) #描画する本の幅	
		(a2,r1) = ichaos(a2 , 0 , br , 0.2 , 0.005) #描画する本の角度		
		(a3,han) = ichaos(a3 , 0 , 6 ,1 , 0.01) #本の種類変更判定用		
		if han < 1:
			(a4 , bks) = ichaos( a4 , 0 , len(bksize)-1 , 1 , 0.05)
		bd , bh = bksize[bks] #本の奥行きと高さ			
		rad = math.radians( r1 )
		x+= bh * math.sin( rad )
		vs.BeginXtrd( 0 , bh )	
		vs.Rect( x , 0 , x+w1 , -bd )
		objH = vs.LNewObj()
		vs.SetClass( objH, cls )
		vs.EndXtrd()
		objH = vs.LNewObj()
		vs.Set3DRot( objH , 0 , -r1 , 0 , x , 0 , 0 ) 
		x+= w1 + 1
		if x > w:
			vs.DelObject(objH)
	
	
	#----------------------------------------------------------
	#end script--------------------------------------------------
	#----------------------------------------------------------
	
	#outputs
	self.Params.h.value = sym

本を倒した時に、隣の本との関係を計算していないので、倒れ角を大きくすると不自然に隙間が空いてしまうのですが、今回はとりあえずこれで。

隣の本との接点をちゃんと計算したり、自然な倒れ方になるように角度の設定の仕方を工夫したり、横置きバージョンを間にいれたり、というのは必要であればチャレンジしても良いかもしれません。

間欠カオス法

単純な式で1/fゆらぎに似たゆらぎを生み出す間欠カオス法(Intermittent Chaos)というのがあります。

今回それを使っていますのでそこだけ解説しておきます。

X(t)<0.5の時
X(t+1) = X(t) + 2 * X(t) * X(t)
X(t)≧0.5の時
X(t+1) = X(t) – 2 * (1-X(t)) * (1-X(t))
(0<X(t)<1)

これを発生させるノードを作ってみたのですが、使い方が難しかったので、単純にコード内に関数として設定しました。

def ichaos( a , min , max , step , cut ): #間欠カオス関数
		b = int ( a* ( max - min + step ) / step ) * step + min
		if a < 0.5:
			a = a+2*a*a
		else:
			a = a-2*(1-a)*(1-a)
		if a < cut or a > (a-cut):
			a = r.random()	
		return (a,b)

引数のaが間欠カオス法によるベースの値です。これが0<a<1の範囲で変化するので乱数の代わりに使います。a(t+1)はa(t)によって決まるので、aの値はルーチンを通して残しておく必要がありますが、逆に言えばaさえ残しておけば間欠カオス法を継続できるので、a1,a2,a3等異なる変数を使えば、いくつもの値を並行して使えます。(今回もa1~a4まで並行して使っています。)

min,max,stepは0<a<1であるaの値をmin<b<max(ただしstepごとにまるめる。step=1のときはint関数と同様になる)となる数字に置き換えて戻り値として返すようにしています。

cutは
間欠カオス法 – オッサンとバイエル、ピアノ等

ただし、参考にさせていただいた各サイトによると、この間欠カオス法は、0.0付近や1.0付近に値が貼り付き易いので、0.0や1.0に近くなったら乱数を入れてやるとよいとのことである。

とのことなので、a<cut または a>(1-cut)となる場合に、aに乱数を入れ直す、というように使っています。(cutを大きくすると単純な乱数とあまり変わらなくなるので、いいところで加減したほうが良いです。0でもいいかも。)

今回は完結カオス法を使う効果がどの程度あったか分かりませんが、ルーバーなどもっと大量に繰り返されるものだとそれなりに効果があると思うので、何度も実行させて、結果を見て良さそうなのを採用する、というような使い方はできるかと思います。


プラグイン化したものとサンプルファイルはここに置いておきます。

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