XPresso 基礎

レベル/ 対象者:中級/ CINEMA 4Dを使えて、読み書きができる人
対象ソフトウエア、プラグイン:CINEMA 4D R12

プログラムは文章である。読み書きができる人間なら誰にでも書ける。

冨士 俊雄/ gtofuji@gmail.com
章番号 題名 内容、及び関連する章 作成日/注記
804 3_条件分岐 条件分岐、if文、switch文、条件分岐ノード、限定ノード、比較ノード、ブール演算ノード、1001章 2011.1.25
English Top

 

Step 1

if文

  XPressoにはいわゆる「if文」を表現するノードがありません。ループの場合もそうですが、ノードをワイアでつなぐタイプのプログラムでは、「くり返し」や「条件分岐」、「ジャンプ」といった複雑な構造を表現するのが難しいのです。それでも条件分岐なしでは何も作れないので、XPressoで条件分岐を表現するための方法をいろいろと説明します。

 まず、新規シーンを作成し、ヌルオブジェクトを作成し、XPressoタグを作成して下さい。今回は、このヌルオブジェクトのX方向の移動範囲を「-100から100の間に制限する」ことを考えます。

 テキストベースであれば、これは以下の3行のプログラムで簡単に表現できます。re

	if(f_in <= 100 && f_in >= -100)	f_out = f_in;
	else if(f_in > 100)	f_out = 100;
	else	f_out= -100;

 ここで、1行目の「if()」は条件文を表し、()の中の「&&」は「かつ」を表します。つまり、この行を日本語で表現すると、「もし、f_inが100と等しいか小さく、かつ、f_inが-100と等しいか大きい場合は、f_inをそのままf_outに出力する」となります。これはつまり、「何も制限しない」ということを意味します。

 2行目の「else if」は「そうでなく、もし」を表します。つまりこの行は、「そうでなく、もし、f_inが100より大きい場合は、f_outに100を出力する」となります。これはつまり、「上限値を100に制限する」ということを意味します。

 3行目の「else」は「そうでない場合は」を表します。つまりこの行は、「そうでない場合は、f_outに-100を出力する」となります。これはつまり、「下限値を-100に制限する」ということを意味します。

 実際このプログラムをCOFFEEノードに書き込んで、ヌルオブジェクトノードの間に挟めば、簡単に値を「-100から100の間に制限する」ことができます。

図804-1

 サンプル804aを開いて、エディタビューでヌルオブジェクトを動かしてみて下さい。

図804-2

 それでは同じことをXPressoで表現してみましょう。

 実は値を制限するだけなら簡単です。XPressoには「限定」という専用ノードがあるからです。「XPresso -> 計算」から限定ノードを作成し、COFFEEノードの代わりにヌルオブジェクトの間にはさみ、最大値を「100」、最小値を「-100」に変更してみて下さい。

図804-3

 サンプル804bを開いて、エディタビューでヌルオブジェクトを動かしてみると、先ほどのCOFFEEと同じように移動範囲が-100から100の間に制限されていることがわかるはずです。

 簡単ですか。しかしこのような専用ノードが用意されていること自体、「XPressoで条件分岐を表現するのが難しい」ということの証明なのです。

 

 

Step 2

ノードを組み合わせてif文を表現する

 しかし、値を制限することだけが条件分岐ではありません。もっと複雑な条件分岐を表現するには、XPressoノードを組み合わせてif文と同じ働きをする構造を作る必要があります。ただし、実用的ではないので制作過程は省略します。サンプル804cを開いて各自調べてみて下さい。

図804-4

 このXPressoは、おそらくステップ1でCOFFEEを使って書いたif文と同じ働きをします。それでは対応を見ていきましょう。

 一番左のノードは「f_in」に対応します。

 左から2、3列目の「比較」ノードは、if文に続く条件式「f_in <= 100」、「f_in >= -100」、「f_in >100」に対応します。

 4列目のブール演算ノードは「&&」と「else」に対応します。下のブール演算ノードの働きがちょっと判りにくいのですが、これは上のブール演算ノードの結果と、2列目下の比較ノードの値の両方が「偽(FALSE)」であった場合に「真(TRUE)」になります。

 5列目は確認用の結果ノードです。

 6列目は出力する値「f_in」、「100」、「-100」に対応します。7列目は出力先のヌルオブジェクトで、「on」ポートをオンオフすることにより、この入力を実行するかどうか決めています。

 ちなみに、1行目が「制限なし」、2行目が「上限値」、3行目が「下限値」に対応しています。

 これでif文を完全に再現できました。しかし、COFFEEのif文が不要な行をスキップするのに対して、XPressoでは全てのノードが必ず実行されます。つまりその分遅くなります。


 大変ですねえ。私もこんなものは初めて作りました。プログラムの経験がない人は何をやっているのかさっぱり判らないと思いますが、気にする必要はありません。悪いのはあなたではなくXPressoの方です。つまり、「XPressoではif文を表現できない」のです。

 if文は階層化できますが、XPressoで階層化されたif文を表現するのは事実上無理です。私はやったことありませんし、やってみたいとも思いません。COFFEEで書いた方がずっと簡単です。

 

 

Step 3

条件分岐ノード

 XPressoにはC言語のswitch文に似た働きをする「条件分岐」ノードがあります。「どうしてもCOFFEEを書きたくない」という人はこれを使うしかありませんが、あまりおすすめはできません。条件分岐ノードには、「複数の処理を実行できない」、「処理の続行やbreakの設定ができない」、「defaultの設定ができない」といった機能上の欠点があるからです。もちろんCOFFEEノードを使えばswitch文も普通に扱えます。

 それでは条件分岐ノードを使ってマテリアルを切り替える実験をしてみましょう。

 新規シーンを作成し、「立方体」オブジェクトを作成し、XPressoタグを作成して下さい。そして、マテリアルマネージャでカラーの異なるマテリアルを3個作って下さい。

 次に、立方体にマテリアルを適用し、テクスチャタグを作成して下さい。マテリアルはどれでも構いません。

図804-5

 次に、XPresso編集ウインドウに「立方体オブジェクト」、「テクスチャタグ」、「3個のマテリアル」をドラッグします。

図804-6

 それではこれから、「オブジェクトの高さ(Y方向の位置)に応じて色を変えるXPresso」を作ります。

 まず、「XPresso -> 論理」から「条件分岐」ノードを作成します。また、「XPresso -> 計算」から計算ノードを作成します。これで必要なノードは全てそろいました。

図804-7

 まず、立方体ノードに「位置.Y」出力ポートを作成し、計算ノードの入力につなぎます。計算ノードのデータタイプは「整数」、演算タイプは「除算」、入力2は「100」に変更して下さい。これによって、立方体の高さが100変った時に、出力が1変るように値がスケールされます。

 また同時に、位置データが浮動小数から整数に変換されます。

図804-8

 次に、計算ノードの出力を条件分岐ノードの「スイッチ」ポートにつないで下さい。条件分岐ノードは、スイッチポートの値が0の時に一番上の入力ポートにリンクされたデータを出力ポートに出力します。そして、スイッチポートの値が1の時に2番目の入力ポートのデータを出力します。入力ポートが多数ある場合は、順番にスイッチポートの値に対応したデータが出力されます。

 入力ポートはいくらでも増やせます。また、スイッチポートの値がマイナスの場合、一番上の入力ポートのデータが出力されます。また、スイッチポートの値が入力ポートの総数を超えた場合、一番上の入力ポートに戻ります。

 次に、マテリアルがリンクされた3個のオブジェクトノードに「オブジェクト」出力ポートを作成し、条件分岐ノードにつなぎます。条件分岐ノードのデータタイプは「リンク」に変更します。さらに、テクスチャタグノードに「タグの属性 -> マテリアル」入力ポートを作成し、条件分岐ノードの出力ポートにつなぎます。すると次のようになるはずです。

図804-9

 サンプル804dを開いて、立方体オブジェクトを上下に動かしてみて下さい。位置によって立方体に適用されるマテリアルが切り替わり、色が変わるはずです。

図804-10

 

 

Step 4

COFFEEでswitch文を使う

 それでは比較のために、COFFEEノードを使って同じXPressoを作ってみます。この場合、XPressoの構成は次のようになり。条件分岐ノードを使った場合と大差ありません。サンプル804eを開いて確認してみて下さい。

図804-11

 また、COFFEEノードの中のプログラムは次のようになります。

	switch(int(r_in/100))
	{
		case 0:l_out= l1_in;	break;
		case 1:l_out= l2_in;	break;
		case 2:l_out= l3_in;	break;
	}

 ここで、1行目の「switch()」はswitch文であることを表します。switch文の()の中には整数を入力する必要があり、これが実行する「行数」を表します。しかし、立方体の高さの値は連続的に変化する浮動小数(例、1.234)であるため、「int()」関数を使って整数(例、1)にキャスト(変換)しています。

 3行目の「case 0:」は0行目を表し、switchの値が0の時にこの行が実行されます。また、この行が実行された後、下の行も順番に全て実行されます。もしこの行だけで実行を停止したい場合には、行の最後に「break」を追加して止めます。

 4、5行目も同じです。

 switchの値に対応するcaseが存在しない場合、出力ポートのデータは変更されません。つまり、最後に出力されたデータがそのまま出力されます。このような場合に特別な処理をさせるには、「default:」という行を追加します。

 

 このXPressoに限れば、条件分岐ノードを使う方がCOFFEEノードを使うより簡単です。しかし、条件分岐ノードではこれ以上複雑な機能を表現できません。その点、COFFEEノードを使えばより複雑な機能を表現できます。ですから、なるべくCOFFEEノードを使うことをお勧めします。

 

 

Step 5

全部COFFEEで書く

 参考までに、全部をCOFFEEノード内部で処理する方法についてサンプル804fで説明します。これはCINEMA 4D R8でXPressoが導入されるまで、私たちがCOFFEEタグの中で普通にやっていたことです。

 XPressoの構成は確かに簡単になります。

 また、直接COFFEEタグの中に書き込むこともできます。もはやポートやワイアを作る必要は全くありません(サンプル804g)。

図804-12

 しかし、COFFEEはずいぶん複雑になります。

図804-13

	var doc= GetActiveDocument();
    
	var o1= doc->GetFirstObject();
    
	var t1= o1->GetFirstTag();	t1= t1->GetNext();	t1= t1->GetNext();
	var m0m= t1->GetMaterial();
	var pos= o1->GetPosition();
    
	var m1= doc->GetFirstMaterial();	var m1m= m1->GetMarker();
	var m2= m1->GetNext();	var m2m= m2->GetMarker();
	var m3= m2->GetNext();	var m3m= m3->GetMarker();
    
	switch(int(pos.y/100))
	{
		case 0:m0m= m1m;	break;
		case 1:m0m= m2m;	break;
		case 2:m0m= m3m;	break;
	}
    
	t1->SetMaterial(m0m); 

 ここで、1行目は現在のシーンファイルを取得しています(COFFEEタグの場合は自動的に取得されます)。

 3行目は、立方体オブジェクトを取得しています。ここでは、「オブジェクトマネージャの一番上にあるオブジェクト」として取得していますが、オブジェクトが増えた場合は名前や階層にしたがってオブジェクトを検索するプログラムを追加する必要があります(COFFEEタグの場合は自動的に取得されます)。

 5行目は、テクスチャタグを取得しています。ここでは「一番左にあるタグ、の右にあるタグ、の右にあるタグ」として取得していますが、タグが増えた場合は名前や順番にしたがってタグを検索するプログラムを追加する必要があります。

 6行目は、テクスチャタグにリンクされているマテリアルのマーカーを取得しています。

 7行目は、立方体の位置ベクトルを取得しています。

 9行目は、マテリアルマネージャの一番左(上)にあるマテリアルを取得し、さらにそのマーカーを取得しています。
 10行目は、一つ右(下)にあるマテリアルと、そのマーカーを取得しています。
 11行目は、さらに一つ右(下)にあるマテリアル、とそのマーカーを取得しています。

 13から18行目までは、変数名は変ってますが、ステップ4で説明したswitch文と全く同じです。ちなみに、13行目の「pos.y」は、「posベクトルのy成分」という意味です。

 20行目は、switch文の中で選択されたマテリアルのマーカーを、テクスチャタグに設定しています。


 ずいぶん面倒ですね。私もこのようなプログラムを書いたのは数年ぶりです。なぜなら、XPressoが導入されて以降、オブジェクトを取得するのにCOFFEEを使うことはほとんどなくなったからです。ここまでのステップを振り返ってみると、XPressoとCOFFEEの得手不得手がよくわかります。

1. XPressoは、オブジェクトやマテリアルを取得するのは得意だが、ループや条件分岐を処理するのが苦手。

2. COFFEEは、ループや条件分岐を処理するのは得意だが、オブジェクトやマテリアルを取得するのが苦手。

 つまり、XPressoとCOFFEEをうまく組み合わせて使うのが一番いいのです。今回の実験の中ではステップ4がそれに相当します。