« C.O.F.F.E.E.で重たい処理をした時に、プログレスバーを表示させる。 | トップページ | 今までのC4Dユーザスクリプトを振り返る… »

C.O.F.F.E.E.やユーザスクリプトから、C4D標準マテリアルのパラメータを調整する。

さて、C4D以外の3Dモデルをインポートしたとき、マテリアルの全てが真っ黒になっていた事はないだろうか?

Material_01

マテリアルを覗いて見ると、確かに色の設定はされているものの明るさが0%になっていたりする。

そんな時は、真っ黒のマテリアルの全てを選択し、属性マネージャで全てのマテリアルの明るさを一気に変えることができます。が…

これを、ユーザスクリプトで実行して見ましょう。

まず、C.O.F.F.E.E.SDKによると…

マテリアル一つ一つがBaseMaterialクラスで…
その中の「カラー」「拡散」「発光」「透過」「鏡面反射」…がBaseChannelクラス

という事である。

このクラスからパラメータにアクセスしてみよう。

マテリアルマネージャの先頭にあるマテリアルのカラーにアクセスしてみよう。
マテリアルのカラーのRを0にします。

/*
マテリアルマネージャの先頭のマテリアルのカラーにアクセスする。
2009.4.29
*/


var mat = doc->GetFirstMaterial();//ドキュメントのマテリアルマネージャの先頭のマテリアルを取得
if(!mat)return;    //マテリアルが1つも無ければ終了

var col_chn = mat->GetChannel(CHANNEL_COLOR);//マテリアルからカラーチャンネルを取得
var col_ct = col_chn->GetContainer();        //パラメータを格納しているコンテナを取得
var col_col = col_ct->GetData(CH_COLOR);     //コンテナからカラーを取得

println(col_col);  //コンソールにRGB値(ベクトル値)を表示

col_col.x = 0.0;   //rを0.0に設定
col_ct->
SetData(CH_COLOR , col_col);//コンテナにカラーを格納
col_chn->
SetContainer(col_ct);      //チャンネルにコンテナを適用

ユーザスクリプトのmain(doc , op)に渡されるopは、オブジェクトマネージャのオブジェクトなのでマテリアルではありません。

任意のマテリアルを取得するには…
BaseDocumentクラスのGetFirstMaterial()メンバ関数を使いマテリアルマネージャの先頭のマテリアルを取得します。
先頭のマテリアルからマテリアルマネージャ内を捜査して任意のマテリアルを取得します。

マテリアルから任意のチャンネルのBaseChannelを取得してBaseChannelからパラメータを格納しているコンテナを取得します。

現在のパラメータから新たな値を導くのであればコンテナからパラメータを取得し変更します。

カラーは、ベクトル型でRGBそれぞれ0.0~1.0です。

変更したパラメータをコンテナに格納します。

最後はBaseChannelクラスにパラメータを格納したコンテナを適用して終わりです。
不思議ではありますが、変更したBaseChannelクラスをBaseMaterialクラスに設定しません。
BaseChannelは、マテリアルから独立しているのだろうか?

これが、マテリアル中のパラメータにアクセスする基本です。
ですが、これは取得するチャンネルやパラメータの定数を覚えなくてはいけません。

もっと手軽にパラメータにアクセスする方法(定数を属性マネージャからドラッグ&ドロップ)があります。

/*
マテリアルマネージャの先頭のマテリアルのカラーにアクセスする。
定数を属性マネージャからドラッグ&ドロップ
2009.4.29
*/


var mat = doc->GetFirstMaterial();//ドキュメントのマテリアルマネージャの先頭のマテリアルを取得
if(!mat)return;//マテリアルが1つも無ければ終了

var col_col = mat#MATERIAL_COLOR_COLOR; //マテリアルからカラーチャンネルのカラーを取得。属性マネージャからドロップ

println(col_col);//コンソールにRGB値(ベクトル値)を表示

col_col.x = 0.0; //rを0.0に設定

mat#MATERIAL_COLOR_COLOR = col_col;     //チャンネルにコンテナを適用

比較する為、変数名は上のコードと同じにしました。

マテリアルから直接カラーチャンネルのカラーを取得しました。
チャンネルもコンテナも取得していません。

最後にマテリアルに直接、カラーチャンネルのカラーを適用してます。

では次に、選択されたマテリアル全てのカラーチャンネルの明るさを100%にして見ます。

/*
選択された全マテリアルのカラーチャンネルの明るさを100%にする。
2009.4.29
*/


var mat = doc->GetFirstMaterial();//ドキュメントのマテリアルマネージャの先頭のマテリアルを取得
if(!mat)return;    //マテリアルが1つも無ければ終了

if(!(mat->GetBit(BIT_AMAT)))mat = mat->SearchNext(BIT_AMAT);//最初のマテリアルが選択されていなければ次の選択マテリアルを探す。

while(mat){        //選択されたマテリアルがなくなるまでループを繰り返す
  mat#MATERIAL_COLOR_BRIGHTNESS = 1.0;//マテリアルのカラーチャンネルの明るさを1.0にする
  mat = mat->SearchNext(BIT_AMAT);    //次の選択マテリアルを探す
}

マテリアルマネージャの最初のマテリアルを取得し、そのマテリアルが選択されていれば、最初の選択されたマテリアルになります。

取得したマテリアルが選択されているか判定するためにBaseList2DクラスのGetBit()を使います。

マテリアルマネージャの最初のマテリアルが選択されていなければBaseList2DクラスのSearchNext()メンバ関数を使って次の選択マテリアルを探します。

選択されたマテリアルのカラーチャンネルの明るさを強制的に100%にし、次の選択されたマテリアルを取得し、選択されたマテリアルが無くなるまで繰り返します。

これを実行して気づいたと思います。
属性マネージャのプレビューは更新されたのに…
マテリアルマネージャのマテリアルサムネイルが更新されない。

残念な事に、マテリアルサムネイルは自動更新されません。

更新の為に1行だけ追加します。

/*
選択された全マテリアルのカラーチャンネルの明るさを100%にする。
2009.4.29
*/


var mat = doc->GetFirstMaterial();
if(!mat)return;

if(!(mat->GetBit(BIT_AMAT)))mat = mat->SearchNext(BIT_AMAT);

while(mat){
  mat#MATERIAL_COLOR_BRIGHTNESS = 1.0;
  mat->Update();// <----------------------マテリアルを更新
  mat = mat->SearchNext(BIT_AMAT);
}

これで、終わりだろうか?

これにはマテリアルタイプのチェックが無い為、標準マテリアル以外(シェーダ、霧、地形、等)が選択されるとC.O.F.F.E.E.エラーが発生して処理を中断します。

では、マテリアルタイプのチェックをするにはどうしたらいいのでしょう。
C.O.F.F.E.E.SDKを見ても、新規でマテリアルを割り当てる為のタイプは指定できるものの、
既に存在するマテリアルタイプの取得らしきものはありません。

打つ手は無いのだろうか?

マテリアルタイプチェックができないなら、
試しに実行してエラーが出たら処理を飛ばし次の処理に移る。
そんな機能はC.O.F.F.E.E.にはあるのだろうか?

try-catch

と言うものがあります。これを使ってみることにします。
これは、エラーのタイプによって処理が選べます。switch-caseの様に…

エラーの起こる場所は、

mat#MATERIAL_COLOR_BRIGHTNESS = 1.0;

です。
カラーチャンネルがあり、更に「明るさ」を持っているマテリアルでなければエラーが出ます。
エラーのタイプは…

try-catchでの明確なエラーの種類に当てはまらないので、全てのエラーに対応する「ExLastException」を使ってみよう。

/*
選択された全マテリアルのカラーチャンネルの明るさを100%にする。
2009.4.29
*/


var mat = doc->GetFirstMaterial();
if(!mat)return;

if(!(mat->GetBit(BIT_AMAT)))mat = mat->SearchNext(BIT_AMAT);

while(mat){
  try{    //試しに実行してエラーが起きたら対応するルーチンに飛ぶ
    mat#MATERIAL_COLOR_BRIGHTNESS = 1.0;
    mat->Update();// <----------------------マテリアルを更新
  }catch(ExLastException){//全てのエラーに対応
   
println(mat->GetName() , "は、処理できませんでした。");
  }

  mat = mat->SearchNext(BIT_AMAT);
}

このスクリプトは、的確なエラー処理をしているわけではなく、エラーが起きたらコンソールにメッセージを表示し、次の処理をしているだけです。

メニューの状態は…

var mat = doc->GetFirstMaterial();
if(!mat)ENABLE = FALSE;else
if(mat->GetBit(BIT_AMAT))ENABLE = TRUE;else
if(mat->SearchNext(BIT_AMAT))ENABLE = TRUE;else
    ENABLE = FALSE;

今回のファイルは、「MaterialColorBrightnessMax.ZIP」です。

では最後に、try-catchの種類を見てみよう。

ExOutOfMemory メモリー不足
ExToMuchParameter パラメータが多い
ExToLessParameter パラメータが少ない
ExBadType タイプが違っている
ExNotAFunction 変数を関数として使用
ExNotAMethod メンバー変数を関数として使用
ExNotAMember メンバ関数がない
ExMemberNotPublic メンバはPublicではない
ExIsProtected メンバはProtected
ExIsPrivate メンバはPrivate
ExOutOfRange 配列の外を指定
ExDivisionByZero ゼロ割
ExLastException 全てを対応

と、いう事らしい。

|

« C.O.F.F.E.E.で重たい処理をした時に、プログレスバーを表示させる。 | トップページ | 今までのC4Dユーザスクリプトを振り返る… »