« C4D HyperNURBSで円柱… | トップページ | C4D TP「PVolumePosition」ノードの位置の分布 »

C4D artist sideC4Dコミュでの「透明樹脂で固めたラメを表現する」回答分

以前どこか…フォーラムだったか…?ブログだったか…?
「ラメ」がネタになっていたような…
かすかに記憶に残っているんですが…

その時の記憶で…「ラメって英語ではどんなスペルだっけ?」
辞書を引いた記憶があるんですが…

試しに「C4D Cinema 4D lame shader」って検索してみたけど…
そう簡単にはヒットしないようで…

ところで、日本人が言っている「ラメ」って、英語圏の人は「lame」って言っているのだろうか?
この時点で検索ワードが適切なのかが、凄く怪しいのだ…
辞書を引くと…
「金や銀の糸を織り込んだ織物」
なんか検索ワードとして使うには、怪しいですね…

シェーダの事は、少しあきらめて…また余裕があるときにでも検索する事にします。
覚えていればの話ですが…

この記事は少し遅れましたが、artist sideでの回答を読んでくれたユーザで、興味をもたれた方へ…

この様な処理には、MoGraphかThinkingParticlesを使用する事でしょう。
手持ちのモジュールはThinkingParticlesしかないので、TPでの作業の様子です。
Demo版には、MoGraphはありますけどね…MoGraphって便利ですね…

次の様にartist sideで回答しました…

  • TPの「PBorn」ノードでパーティクルを生成
  • 「PVolumePosition」ノードで任意のオブジェクト内の座標を取得
  • 「PSetData」ノードでパーティクルに適用
  • 必要なパラメータは、ユーザデータを使って与える

こんな具合です。

「PVolumePosition」ノードの以前の記事だと…
C4D ThinkingParticles ポリゴンオブジェクト内にパーティクルを配置する。
C4D ThinkingParticles ポリゴンオブジェクト内にパーティクルを配置する-02

今回の記事の後半は、C4Dが「反応なし」の状態になるかもしれませんので、重要なファイルは保存し閉じてください。

シーンの構成は以下の通りです。

Lames_01

「PVolumePosition」ノードでTPパーティクルをオブジェクト内に配置する為に設定できるパラメータに「深さ」があります。
ただし、この「深さ」の設定にはオフセットがありません。
ですから、パーティクルが表面に配置される可能性があり、オブジェクトからハミ出す可能性があります。
ハミ出し防止の為に「一回り小さいオブジェクト」を用意してその中にTPパーティクルを配置します。
「一回り小さいオブジェクト」は配置の為だけに使用しますので、レンダリングやエディタでの表示は「隠す」にします。
パーティクルのマスタオブジェクト「ポリゴン」も同様に「隠す」にします。

「一回り小さいオブジェクト」の作成方法は、下の方にある「HyperNURBS」+「立方体」をコピーし…
HyperNURBS分割レベルを2に下げて「編集可能の状態」をしてポリゴンオブジェクトにします。
今回は分割レベルを2にしましたが、必要に応じて設定してください。
後は、全てのポリゴンを選択して、「構造」メニューの「法線方向に沿って移動」で適当な数値で内側に移動させました。

Lames_03

「パーティクルジオメトリ」のパーティクルグループは「All」を指定しておきます。

Lames_02

ちなみに、TPパーティクルを大量に生成して「パーティクルジオメトリ」を「編集可能の状態」にすると…
大変な事になるかも知れませんので、注意してください。

一番下のヌルオブジェクト「オブジェクト内にTPを発生」にXPressoを取り付けThinkingParticlesを設定していきます。
データの設定にユーザデータを使います。

Lames_04

見ての通りで、特別なものはありません。

1つ目のXPressoは、TPパーティクルの生成部分です。

Lames_05

時間0で初期化する為のブール値。
有効期限を開始フレームと終了フレームから算出します。
ユーザデータからのデータの受け渡しです。
「パーティクル数」と上の2つをパーティクルを生成する「PBorn」ノードへ渡します。
「TP Group」「中のオブジェクト」をパーティクルに設定します。

2つ目のXPressoは、ポリゴンオブジェクト内にTPパーティクルを配置します。

Lames_06

「PPass」へユーザデータからのTPGroupを渡します。
「PPass」から「PVolumePosition」へTPパーティクルを渡し、位置と配置を取得します。
更に「PSetData」へ渡してTPパーティクルに適用します。
こちらの配置処理をするXPressoは全てのフレームで実行されます。

Lames_07

パーティクル数は800で、こんな具合です。

「thinkingparticles_ame.ZIP」

上のファイルはartist side C4Dコミュより若干変更を加えました。
この記事とも、若干違います。
TPパーティクルの配置(角度)を「ランダム」ノードを使って処理するように変更しました。

TPノードは、イベントに反応しないので、ビュー操作でTPパーティクルを追従させるには、アニメーションを再生状態にするしかないのかなぁ…

自分の所では、4,000位でオブジェクトをドラッグ操作するとガクガクしています。

Lames_20

ThinkingParticlesは、1つのノードから1粒づつパーティクルを渡します。
XPresso自体が処理速度が遅いのに、ThinkingParticlesで更に遅くなります。

大量のTPパーティクルを扱うより、同数のポリゴン数のポリゴンオブジェクト1つを扱う方が、処理に負担がかかりません。

ThinkingParticlesを4,000パーティクル使用したシーンと…
平面プリミティブで縦横の分割数65:4225ポリゴンを使用したシーンでのビュー操作と比べると…
TPパーティクルよりポリゴンオブジェクトの方が、スムーズにオブジェクトを動かす事ができます。
ポイントが隣のポリゴンと共有しているので、ポイントのデータは少ないですが…

ThinkingParticlesのパーティクルを使わず、ポリゴンオブジェクト1つで処理をする方法

簡易のポリゴンオブジェクト内のポリゴンをランダム配置するC.O.F.F.E.E.エクスプレッションです。

/*
簡易版:ポリゴンオブジェクト内のポリゴンをランダム配置
ポリゴンオブジェクト内のポリゴンは、全て分離させておくこと…
*/


main(doc , op)
{
  if(!instanceof(op , PolygonObject))return;
  var pts = op->GetPoints();       //ポイント配列の取得
  var pls = op->GetPolygons();     //ポリゴン配列の取得
  var plc = op->GetPolygonCount(); //ポリゴン数の取得
  var rnd = new(Random);           //ランダム座標を取得するためのRandomクラスの割り当て
  var area_size = vector(100.0 , 200.0 , 300.0);//ランダムに配置するエリア
  var bits_size = 10.0;            //配置するポリゴンの大きさ
  var pos;
  var c;

  //変数の調整
  area_size *= 0.5;
  bits_size *= 0.5;

  for(c = 0 ; c < plc ; c++){
    //ポリゴンを配置するランダム座標の取得
    pos = vector(rnd->Get11() * area_size.x ,
                rnd->Get11() * area_size.y ,
                rnd->Get11() * area_size.z);

    //配置するランダム座標を中心にポリゴンの4点を決める
    pts[pls[c*4    ]] = pos + vector( bits_size , 0.0 , bits_size);
    pts[pls[c*4 + 1]] = pos + vector( bits_size , 0.0 ,-bits_size);
    pts[pls[c*4 + 2]] = pos + vector(-bits_size , 0.0 ,-bits_size);
    pts[pls[c*4 + 3]] = pos + vector(-bits_size , 0.0 , bits_size);
  }

  op->SetPoints(pts);      //変更ポイントの適用
  op->Message(MSG_UPDATE); //オブジェクトの更新を適用させる
}

このC.O.F.F.E.E.エクスプレッションは、元のポリゴンの形や大きさは無視して大きさbits_sizeの[+Y]向きの正方形にしたものをランダムに配置します。

これを実行するには、条件があります。
あらかじめ、ポリゴンオブジェクト内のポリゴンを1枚づつに分離しておくことです。
分離しておかないと、思ったような結果にはなりません。

では実際に適用してみます。
新規のシーンで平面オブジェクトを「編集可能な状態」にしてポリゴンを分離します。

Lames_08

分割数は20×20で400ポリゴン。

Lames_09

全てのポリゴンを選択して、「ファンクション」メニューの「分離」を実行します。

Lames_10

「グループ維持」をOffにして「OK」を押すと全てのポリゴンが1枚づつに分離します。

これに、先ほどのC.O.F.F.E.E.エクスプレッションを取り付け実行します。

Lames_11

オブジェクト軸を中心に指定したarea_size内にランダムに大きさbits_sizeのポリゴンが配置されます。

「PolygonRandomeAlign.ZIP」

もしもポリゴンを分離しないで実行すると…

Lames_12

思ったような効果にはなりません。

ポリゴン数を増やしてみます。
全てのポリゴンを選択した状態で、「ファンクション」メニューの「細分化...」を実行します。

Lames_13_2

分割数が3の場合だと…
400×(2の3乗 = 8)×(2の3乗 = 8) = 25,600ポリゴンになります。

分割数をたった1増やしただけで総ポリゴン数がかなり増えます。ご注意を…
5にすると400ポリゴンが、409,600ポリゴンになります。
こんな場合には処理に若干時間がかかるので、処理が終わるまで画面上をクリック等しないでください。
C4Dが「応答なし」の状態に陥るかもしれません。

今回は、分割数は3です。
このまま先ほどと同じく、ポリゴンを分離させます。

Lames_14_2

25,600ポリゴンでは、まだ余裕があると思いますが…
イベントが起こるたびに、処理が速くないC.O.F.F.E.E.エクスプレッションが実行されるので、ビューポートでのオブジェクトの移動や回転が、思うようにできない場合があるかもしれません。
C.O.F.F.E.E.エクスプレッションの属性マネージャで「使用する」をOffにします。

Lames_15

多分、問題なく移動や回転ができていると思います。

Lames_16

これは、25,600ポリゴンあります。
もしこれを、ThinkingParticlesで25,600パーティクルを生成する事を想像してください。
メモリを十分に搭載していないマシーンでは、全てのパーティクルが生成できるかが心配です。

ただ、困ったことに、透明樹脂にあたる不定形(穴があるかもしれない)のオブジェクトの中にC.O.F.F.E.E.で配置するには、自分でポリゴンオブジェクト内外の判定を書かなくてはいけません。

数学が得意なら、問題ないのでしょうが…

そんなときは…
ポリゴンを任意のポリゴンオブジェクト内にランダムに配置するために、ThinkingParticlesを使います。

ん!?…

って思った方も…
配置のみに使用しますので、配置後はTPのXPressoは削除、もしくは機能停止にします。

ThinkingParticlesのノードは、パーティクルの為に作られたものですが、パーティクル以外に使ってはいけないと言うものではありません。
幸いにも「PVolumePosition」ノードの出力「位置」は単純なベクトル型です。

ただし、TPノードはパーティクルをまとめて渡すことができないので、1粒づつ出力されます。
全てのポリゴンを並べ終わるには、かなり時間がかかります。
配置後はTPを使用しませんので、並べるまでの辛抱です。

先ほどの、C.O.F.F.E.E.エクスプレッションをC.O.F.F.E.E.ノード用に変更します。
ポリゴンをまとめて処理していたのですが、1実行で1ポリゴンの処理にします。
このノードに外部からの必要なデータは…

  • ポリゴン番号(パーティクル番号) : P_Number
  • ポリゴンの位置(PVolumePositionノードからの出力座標) : P_Pos
  • ラメ用のポリゴンオブジェクト : P_Obj

最低限は、この3つだろうか…
とりあえず、ポリゴンのサイズ等は内部変数で…

/*
ポリゴンオブジェクト内のポリゴンを配置
ポリゴンオブジェクト内のポリゴンは、全て分離させておくこと…
*/


main()
{
  if(!instanceof(P_Obj , PolygonObject))return; //渡されたオブジェクトがポリゴンオブジェクトでなければ、処理を中断
  var plc = P_Obj->GetPolygonCount();           //ポリゴン数の取得のRandomクラスの割り当て
  P_Number = int(Clamp(0 , plc - 1 , P_Number));//指定したポリゴン番号が範囲外の場合は強制的に範囲内にする
  var bits_size = 10.0;                        //配置するポリゴンの大きさ
  var ply = P_Obj->GetPolygon(P_Number);        //P_Numberが示すポリゴンを取得
  var c;

  //変数の調整
  bits_size *= 0.5;

  P_Obj->SetPoint(ply->a , P_Pos + vector( bits_size , 0.0 , bits_size));
  P_Obj->SetPoint(ply->b , P_Pos + vector( bits_size , 0.0 ,-bits_size));
  P_Obj->SetPoint(ply->c , P_Pos + vector(-bits_size , 0.0 ,-bits_size));
  P_Obj->SetPoint(ply->d , P_Pos + vector(-bits_size , 0.0 , bits_size));

  P_Obj->Message(MSG_UPDATE); //オブジェクトの更新を適用させる
}

単純に、受け取った座標にポリゴンを配置するだけのC.O.F.F.E.E.ノードなので…
ポイントやポリゴンは配列ではなく、1つづつ取得しています。

これを最初のシーンファイルに組み込みます。
パーティクルにデータを適用する「PSetData」の代わりに、このC.O.F.F.E.E.ノードをハメ込みます。

パーティクルとして使用するわけではないので、必要ではないものが幾つかありますので、削除します。

Lames_17

ユーザデータで設定していたパーティクル数(ショット)にラメポリゴンとして使用する大量のポリゴンを格納しているポリゴンオブジェクト(中のオブジェクト)のポリゴン数を使います。

Lames_19

「PShape」ノードは必要ないので削除します。
「パーティクルジオメトリ」等も必要ないので削除します。

Lames_21

最初のシーンファイルに先ほどの「編集可能な状態」にしてポリゴンを「分離」した平面オブジェクトをコピーして、ユーザデータの「中のオブジェクト」に適用しました。

タイムスライダを0フレームに戻して計算をさせます。
少し時間がかかります。

Lames_18

配置が問題なければ、TPの配置する方のXPressoを属性で「使用する」をOffにします。

Lames_22

全てのポリゴンを選択して「ファンクション」メニューの「法線に沿ってスケール」でポリゴンの大きさを調整する事ができます。
もちろん、C.O.F.F.E.E.でも大きさを調整できますけどね…

「polygons_ame.ZIP」

これも、記事とは若干変更を加えました。
ユーザデータよりポリゴンのサイズを指定できます。
処理経過をコンソールに表示します。今回は、プログレスバーは理由があって使えません。

ポリゴンはランダム配置はしましたが、[+Y]方向を向いたままです。
ランダムな方向を向く処理は、自力で組み込んで見てください。
重要な事を書いていませんが、「PVolumePosition」から出力される「位置」はグローバル座標です…
ポリゴンに適用する前には、ローカル座標に変換する必要があります。
合わせて自力で組み込んでみてください。

最終的に、こんな具合です。
奥のポリゴンの大きさと手前のポリゴンの大きさは違いますけど、数は同じ60,000です。

Lames_23

わかり易いように、最後まで赤色でしたが…
興味のあるユーザは、金でも銀でも好きな色で試してみてください。
内部拡散シェーダ等を適用すると、面白いものができないだろうか…?
もちろん、いろんな意味で保証はしませんけどね…

そもそもC.O.F.F.E.E.でポリゴンオブジェクトの内外判定が可能であれば、XPressoなんて使わずに、MenuPluginの形で作成できるのですが…

今回の後半は、ポリゴンオブジェクトを操作してランダムに配置しましたが、Py4Dを使えれば、直接TPを操作できるはず…
PythonタグでTPを操作したら60,000パーティクルでもサクサク動くのだろうか…?
Py4Dも放ったらかしの状態で…
何にしても勉強不足ですね…

やはり、簡単にラメを表現するにはラメシェーダがあれば良いんですけどね…
本当に、誰も知らないのかなぁ…

こんな事なら、C.O.F.F.E.E.チャンネルシェーダをもっと積極的に学習しておくんでした…
放ったらかしにしてしまいましたが…
「ラメシェーダ…?、あるよっ!」って一言。ラメシェーダをヒョイと出せるレベルだったら…
でも、学習したらラメシェーダの様な物は作れるのかな…

今回のartist sideでの回答方法は、少し反省すべきかな…
回答の内容が、このブログチックになってしまいました。
公けでの質問なので、いろんなユーザが読んでくれる事を前提に回答を考えるのですが、質問者が望んでいない様な事も混ぜてしまいました。
他のユーザにも興味を持ってもらえると思い、ついね…
空気を読んでいませんでした…
簡単明瞭明確な回答になるように心がける様にするべきですね…

ところで…

C++でプラグインの作成は難しいのかなぁ…
C++がなんとなく読めても…
VC++EX_Editionの使い方も覚えないと…
artist sideでanoanoさん指名で質問したら回答してくれるかなぁ…
ブログを読むと忙しそうだし…

C++SDKR11.5を全頁の頭の部分だけ一通り眺めましたが… 英語なので眺めただけ…
1400ページぐらいあるんですね…
覚える自信がありません…
まずは、必要な情報がどの頁を参照すれば良いのかが判らないと…
今は、無理なので保留…

最後に、試しに色を変えてみました…
いつもの様に適当ですが…

Lames_24

追伸…
「PVolumePosition」ノードに設定するオブジェクトのポリゴン数が少ないと出力する「位置」にムラができます。

最終ファイルです。

「Polygons_lame2.ZIP」

|

« C4D HyperNURBSで円柱… | トップページ | C4D TP「PVolumePosition」ノードの位置の分布 »