球体から立方体への変形

CINEMA 4DおよびBodyPaint 3Dに関する一般的な議論や情報交換をするフォーラムです。
BUTTON_POST_REPLY
tofuji
記事COLON 828
登録日時COLON 2011年3月10日(木) 10:41
お住まいCOLON 東京都渋谷区

球体から立方体への変形

投稿記事 by tofuji » 2011年8月26日(金) 10:04

 先日の講習会で、MoGraphを使って「球体から立方体へ変形させる」という話が出たのでサンプルを作ってみました。

http://www2.11moon.com/sample_files/201 ... e_Cube.mp4
http://www2.11moon.com/sample_files/201 ... _Cube6.zip

 作り方の詳細については、追って説明します。
---

Toshio Fuji<gtofuji@gmail.com>

掲示板に書いたサンプルのまとめサイト
http://www2.11moon.com/index_as.html

miyata
記事COLON 512
登録日時COLON 2009年12月29日(火) 16:25

Re: 球体から立方体への変形

投稿記事 by miyata » 2011年8月26日(金) 19:12

継承エフェクタを使うと、クローンの配列を別の配列へ簡単に変更できます。

ただ、内部のクローンIDが一致する場所へ直線移動するので、動きとしてはあまり面白くないので、
ランダムエフェクタや簡易エフェクタで、線形減衰でクローンを先に動かしてから、
継承エフェクタで立方体へ変形させるといいかもしれません。
sp2cube.c4d.zip
(8.19 KiB) ダウンロード数: 221 回

tofuji
記事COLON 828
登録日時COLON 2011年3月10日(木) 10:41
お住まいCOLON 東京都渋谷区

Re: 球体から立方体への変形

投稿記事 by tofuji » 2011年9月05日(月) 04:59

 説明が足らなくてすみません。

 まず、この話は以下のムービーが発端になっているので、配置や動作にいくつかの制約があります。
http://vimeo.com/24427718

a. 小さなキューブは、最初球体に対して独特の配置になっていること。

b. キューブは、球体から立方体に向かってX、Y、Zの順で移動すること。

c. キューブは、球体に沿っている時と立方体に沿っている時で必然的に数が変る。
つまり、どこかに欠落ができるが、それを内部によせて「空洞」とすること。
 

 したがって、宮田さんの作ったサンプルのままだと条件を満たしていないし、
またMoGraphの機能を追加して条件を満たすのも難しいと思いました。もしかしたらMoGraphでも可能かもしれませんが、
こういう仕事はXPressoでやってしまった方が簡単です。

 ただし、元のムービーはHoudiniで作られているのですが、
Houdiniでは、XYZ順の移動に関しては標準機能のコンストレイントでやっているようです。


---

 それでは、「X、Y、Zの順で移動する」という部分についてだけ手順を詳しく説明します。
これは、「オブジェクトを動かすXPresso」の基本です。


1. まず最初に、「オブジェクトを移動させるXPresso」を作ります。オブジェクトを動かすのは簡単で、
「XPressoが実行されたら、オブジェクトの現在の位置に移動量(ここでは1)を加算して、自分の位置に戻す」
という手順で実行します。

 また、これだけならCOFFEEを使わなくても「計算」ノードで表現できます。
http://www2.11moon.com/sample_files/201 ... e_move.zip
http://www2.11moon.com/sample_files/201 ... e_move.mp4


2. これだけだと「ただ走り続けるだけのXPresso」なので、次に「ターゲットに向かって移動するXPresso」を作ります。
この場合、動作を2種類に切り分ける必要があります。つまり、「ターゲットの右にいたら左に移動」、「左にいたら右に移動」です。
簡単ですね。

 このぐらいまではCOFFEE無しで作れます。
http://www2.11moon.com/sample_files/201 ... target.zip
http://www2.11moon.com/sample_files/201 ... target.mp4


3. ただし、これだと「ターゲットの付近で行ったり来たりするXPresso」になってしまいます。
サンプルを見ると、ターゲット付近でブルブル震えているのがわかるはずです。
このままでは永久にターゲットに到着しません。そこで、次に「ターゲットで静止する機能」を追加します。

 具体的には、2.の動作を2種類から3種類に増やし、「ターゲットに近づいたら、ターゲットにジャンプする」という動作にします。

 ここらへんからは複雑になってくるので、COFFEEを使わないと無理です。
http://www2.11moon.com/sample_files/201 ... e_jump.zip
http://www2.11moon.com/sample_files/201 ... e_jump.mp4

 プログラムの全文は次のようになりますが、これを日本語訳すると以下のようになります。

コードCOLON 全て選択

main()
{
	if(pvx_in > 1)	pvx_out= pvx_in - 1;
	else if(pvx_in < -1)	pvx_out= pvx_in + 1;
	else pvx_out= 0;
}
 もし(オブジェクトの位置が移動量(ここでは1)より大きかったら)、現在のオブジェクトの位置から移動量を引く;
 またもし(オブジェクトの位置が移動量のマイナスより小さかったら)、移動量を足す;
 それ以外の場合は、オブジェクトの位置を0にする;


4. これで基本ユニットの構造は完成したのですが、現状では移動量が「1」、ターゲット位置が「0」で固定されています。
そこでこれらの値をポートから自由に指定できるように拡張します。
http://www2.11moon.com/sample_files/201 ... exible.zip
http://www2.11moon.com/sample_files/201 ... exible.mp4

 プログラムの全文は次のようになります。「移動量」が「spd_in」で、「ターゲット位置」が「tpvx_in」です。
最初のプログラムでは「1」や「0」といった「定数」を直接書き込んでいましたが、
これらを「spd_in」や「tpvx_in」といった「変数」に置き換えることで、状況に応じてプログラムの働きを変えられるようになります。

コードCOLON 全て選択

main()
{
	if(pvx_in > spd_in + tpvx_in)	pvx_out= pvx_in - spd_in;
	else if(pvx_in < -spd_in + tpvx_in)	pvx_out= pvx_in + spd_in;
	else pvx_out= tpvx_in;
} 

5. これで基本のユニットが完成です。ここまではX方向の位置だけをいじってきましたが、YZの位置も扱えるように拡張します。

 まず、ポートのデータタイプが「実数」から「ベクトル」に変っていることに気をつけて下さい。ベクトルというのは、
実数が3個パックになったものです。それだけです。
http://www2.11moon.com/sample_files/201 ... vector.zip
http://www2.11moon.com/sample_files/201 ... vector.mp4

 プログラムの全文は次のようになります。先頭に「var pv= pv_in;」という行が追加されました。
これは「変数pvを定義し、pv_inを入力する」という意味です。その理由は次に説明します。

 中央のプログラムをよく見ると、「pv.x」という表現が新しくでてきました。これは「pvベクトルのX成分」という意味です。
変数は、このように成分単位で値を取り出したり書き込んだりできます。しかし「pv_in」というのは「入力へのリンク」なので、
「pv_in.x」というような書き方ができません。同様に、「pv_out」というのも出力へのリンクなので、「pv_out.x」という書き方ができません。

 このような理由から、入力へのリンク「pv_in」を一度変数「pv」に置き換えてプログラムを書いているわけです。

 また、最後に「pv_out= pv;」という行が追加されましたが、その理由も入力の部分と同じです。
つまり、一度成分に分解して計算した変数ベクトルを、最後に出力へのリンクに渡しているわけです。

コードCOLON 全て選択

main()
{
	var pv= pv_in;

	if(pv.x > spd_in + tpv_in.x)	pv.x= pv.x - spd_in;
	else if(pv.x < -spd_in + tpv_in.x)	pv.x= pv.x + spd_in;
	else pv.x= tpv_in.x;

	pv_out= pv;
}

6. 最後に、XYZの移動が順番に行われるように、基本ユニットを3段重ねにします。具体的には、
「X方向の移動処理が終わったら、Y方向の移動処理を実行」、「Y方向の移動処理が終わったら、Z方向の移動処理を実行」という感じになります。
http://www2.11moon.com/sample_files/201 ... ve_XYZ.zip
http://www2.11moon.com/sample_files/201 ... ve_XYZ.mp4

 プログラムの全文は次のようになります。三段重ねになっているのですが、段を切り分けるために「else」の行が少し変っています。

 基本ユニットでは段を切り分ける必要がなかったので、elseの行は「それ以外の場合は、オブジェクトの位置をターゲットの位置にあわせる」
と簡単に書いていました。しかし、これだと段を切り分けることができないので、この行をさらに二つに分けます。
つまり、合計で4種類の動作になるわけです。

 具体的には、「オブジェクトの位置がターゲットの位置と違っていたら、オブジェクトの位置をターゲットの位置にあわせる」と、
「それ以外の場合は(つまり、オブジェクトの位置がターゲットに合ったら)、次の段に移る」となります。
なおここで「!=」は「等しくなかったら」という意味です。

コードCOLON 全て選択

main()
{
	var pv= pv_in;

	if(pv.x > spd_in + tpv_in.x)	pv.x= pv.x - spd_in;
	else if(pv.x < -spd_in + tpv_in.x)	pv.x= pv.x + spd_in;
	else if(pv.x != tpv_in.x)	pv.x= tpv_in.x;
	else
	{
		if(pv.y > spd_in + tpv_in.y)	pv.y= pv.y - spd_in;
		else if(pv.y < -spd_in + tpv_in.y)	pv.y= pv.y + spd_in;
		else if(pv.y != tpv_in.y)	pv.y= tpv_in.y;
		else
		{
			if(pv.z > spd_in + tpv_in.z)	pv.z= pv.z - spd_in;
			else if(pv.z < -spd_in + tpv_in.z)	pv.z= pv.z + spd_in;
			else if(pv.z != tpv_in.z)	pv.z= tpv_in.z;	
		}
	}

	pv_out= pv;
}

7. この後、MoGraphとTPを使って、このプログラムを多数のオブジェクトに適用していくのですが、
この部分は難しい上に応用もそんなにないので説明を省略します。
---

Toshio Fuji<gtofuji@gmail.com>

掲示板に書いたサンプルのまとめサイト
http://www2.11moon.com/index_as.html

BUTTON_POST_REPLY