« C4D ChannelShader…08再挑戦 | トップページ | C4D ChannelShader…10 testChannelPluginクラスの幾つかのメンバ関数にprintln()を取り付けて様子を見る。 »

C4D ChannelShader…09 前回の記事を参考に「ChannelShader…06」で失敗したコードを修正してみる

「ChannelShader…05」でノイズをサーフェスに適用し…
「ChannelShader…06」でダイアログを取り付けて、サーフェスに適用しているノイズスケールをチャンネルシェーダ毎に変更する。

結局完成できず、チャンネルシェーダ毎に変更できず、どれか1つを変更しても、シーン中の全てのチャンネルシェーダが同じ値になってしまいました。

「ChannelShader…06」で失敗したコードです。

/*
ChannelShaderPlugin
testChannelPlugin
*/


var pluginID = 1000007;


//enum ============================================================================

enum{
  sc_tx = 1000,
  sc_val
}



//testDialog ======================================================================
class testDialog:GeModalDialog
{
  public:
    var d_sc;
   
    testDialog();
    CreateLayout();
    Init();
    AskClose();
}
testDialog::testDialog(){super();}

testDialog::CreateLayout(){
  SetTitle("testCHShader");
 
  AddGroupBeginV(10000 , BFH_SCALEFIT , 2 , "group1" , 0);
    AddGroupBorder(BORDER_GROUP_IN);
    AddGroupBorderSpace(10 , 5 , 10 , 5);

    AddStaticText(sc_tx , BFH_LEFT , 0 , 0 , "スケール" , 0);
    AddEditNumber(sc_val , BFH_SCALEFIT , 150, 0);
  AddGroupEnd();
  AddDlgGroup(DR_DLGGROUP_OK | DR_DLGGROUP_CANCEL);
}

testDialog::Init(){
  SetFloat(sc_val , d_sc , 0.0 , 4.0 , 0.01);
}

testDialog::AskClose(){
  d_sc = GetFloat(sc_val);
}



//testChannelPlugin ===============================================================
class testChannelPlugin : ChannelPlugin
{
  public:
    var sc;

    testChannelPlugin();//コンストラクタ

    GetName();//チャンネルシェーダ名
    GetID();  //プラグインID

    EditData(settings);

    //ポイントPの色
    Output(settings , render , p , n , d , t , texflag , vd);
};

testChannelPlugin::testChannelPlugin(){super();}

testChannelPlugin::GetName(){return "testCHShader";}

// http://www.plugincafe.comから取得した、このプラグインの為のplugin idを戻す
//テストID:1000001-1000010

testChannelPlugin::GetID(){return pluginID;}

testChannelPlugin::EditData(settings){
  var dlg = new(testDialog);
  dlg->d_sc = sc;
  dlg->Open(-1 , -1);
  if(dlg->GetResult()){
    sc = dlg->d_sc;
    return TRUE;
  }
  return FALSE;
}

testChannelPlugin::Output(settings , rd , p , n , d , t , texflag , vd){
  if(!sc)sc = 1.0;
  var niz = new(Noise);
  var col = niz->Noise(p.x / sc , p.y / sc , t);

  return vector(col , col , col);
}



//main ============================================================================
main()
{
  Register(testChannelPlugin);
}

testChannelPluginクラスにはInitRender()/InitSettings()を使っていなかったんだね。
メンバ変数scを使ってダイアログの値をやり取りしてたんだ…

このやり方ではダメなんだね…
どうしてダメなのか未だに分かりませんが…

渡されたsettings/rdを使わないといけないようだ…

前回「ChannelShader…08」の記事のように変更すると…
ただし、testChannelPluginクラスのInitRender()メンバ関数と、このメンバ関数が返すべきRenderDataを使用しません。
引数として渡されるsettingsのみの使用です。

/*
ChannelShaderPlugin
testChannelPlugin
サーフェスにノイズを設定する最小限のチャンネルシェーダ---1
*/


var pluginID = 1000007;


//enum ============================================================================

enum{
  sc_tx = 1000,
  sc_val
}



//testDialog ======================================================================
class testDialog:GeModalDialog
{
  public:
    var d_sc;
   
    testDialog();
    CreateLayout();
    Init();
    AskClose();
}
testDialog::testDialog(){super();}

testDialog::CreateLayout(){
  SetTitle("testCHShader");
 
  AddGroupBeginV(10000 , BFH_SCALEFIT , 2 , "group1" , 0);
    AddGroupBorder(BORDER_GROUP_IN);
    AddGroupBorderSpace(10 , 5 , 10 , 5);

    AddStaticText(sc_tx , BFH_LEFT , 0 , 0 , "スケール" , 0);
    AddEditNumber(sc_val , BFH_SCALEFIT , 150, 0);
  AddGroupEnd();
  AddDlgGroup(DR_DLGGROUP_OK | DR_DLGGROUP_CANCEL);
}

testDialog::Init(){
  SetFloat(sc_val , d_sc , 0.0 , 4.0 , 0.01);
}

testDialog::AskClose(){
  d_sc = GetFloat(sc_val);
}



//testChannelPlugin ===============================================================
class testChannelPlugin : ChannelPlugin
{
  public:
    testChannelPlugin();//コンストラクタ

    GetName();//チャンネルシェーダ名
    GetID();  //プラグインID

    EditData(settings);

    InitSettings(settings);

    //ポイントPの色
    Output(settings , render , p , n , d , t , texflag , vd);
}

testChannelPlugin::testChannelPlugin(){super();}

testChannelPlugin::GetName(){return "testCHShader";}

// http://www.plugincafe.comから取得した、このプラグインの為のplugin idを戻す
//テストID:1000001-1000010

testChannelPlugin::GetID(){return pluginID;}

testChannelPlugin::EditData(settings){
  var dlg = new(testDialog);
  dlg->d_sc = settings->GetData(0);
  dlg->Open(-1 , -1);
  if(dlg->GetResult()){
    settings->SetData(0 , dlg->d_sc);
    return TRUE;
  }else return FALSE;
}

testChannelPlugin::InitSettings(settings){
  settings->SetData(0 , 1.0);
  return TRUE;
}

testChannelPlugin::Output(settings , rd , p , n , d , t , texflag , vd){
  var niz = new(Noise);
  var col = niz->Noise(p.x / settings->GetData(0) , p.y / settings->GetData(0) , t);

  return vector(col , col , col);
}



//main ============================================================================
main(){
  Register(testChannelPlugin);
}

「testCHShader_ReTry_Noize.ZIP」

変更箇所は、testChannelPluginクラスのメンバ変数scを削除しました。
そして、InitSettings()メンバ関数を追加しました。

InitSettings()メンバ関数には、引数として渡されたsettingsコンテナのID:0へ、ノイズスケール用の数値1.0を代入します。
最後にreturnでTRUEを返します。

EditData()メンバ関数は、引数として渡されたsettingsコンテナのID:0から数値をダイアログへ渡し、ダイアログで変更された値をsettingsコンテナのID:0へ戻しています。
数値がダイアログで変更された場合は、TRUE、そうでない場合はFALSEをこのメンバ関数が返します。

Output()メンバ関数は、渡されたsettingsコンテナのID:0をノイズのスケール値として使うように変更しました。

Channelshader_22

今回のInitRender()メンバ関数がない構造でもチャンネルシェーダ毎に値を保持する事ができ、レンダリングにも反映されています。

そうすると、引数として渡されるsettingsとrd(RenderData)の使い分けの基準が理解できません。

InitRender()メンバ関数はC.O.F.F.E.E.SDKでは…
典型的な使用は、三角関数の様なSin, Cos, noisesの割り当て等を前もって計算する事であるであろう。

どう言う事だろうか…
三角関数等を前もって計算したものをRenderDataに格納して返すと言う事だろうか…

そう言えば…

「Output()メンバ関数内にOSコールコマンドを使用してはいけない」と書いてありましたね…

C4Dのレンダラがレンダリング時に1ドットづつレイを計算する度にOutput()メンバ関数が呼ばれると言う事だよね…

640×480のサイズだと、最低でも307,200回呼ばれると言う事で…
それとも、シェーダか占めているピクセル領域だけなのか…
でもアンチエイリアス等のスーパーサンプリングだと、4倍、8倍、9倍…に膨らむね…
そうすると、1回のレンダリングで大量に呼ばれる中に、println()の様な処理速度の遅い関数を書き込むと…
レンダリングが何時になっても終わらない状態で、コンソールにはプリントされたデータで溢れ…
多分、C4Dが「応答なし」状態になるんだろうね…

と、言う事を想像すると、Output()メンバ関数内に実行速度を遅くする関数等を書き込むのは問題ありという事だろう…
そう考えると…
処理に時間がかかる割り当て… ノイズクラスの割り当てをOutput()メンバ関数内に書かずに、InitRender()で割り当てなさい。と、言う事だろう…

と言う事は、上のコードはあまり良くない事になりますね…

更に変更してみます。

/*
ChannelShaderPlugin
testChannelPlugin
サーフェスにノイズを設定する最小限のチャンネルシェーダ---2
*/


var pluginID = 1000007;


//enum ============================================================================

enum{
  sc_tx = 1000,
  sc_val
}



//testDialog ======================================================================
class testDialog:GeModalDialog
{
  public:
    var d_sc;
   
    testDialog();
    CreateLayout();
    Init();
    AskClose();
}
testDialog::testDialog(){super();}

testDialog::CreateLayout(){
  SetTitle("testCHShader");
 
  AddGroupBeginV(10000 , BFH_SCALEFIT , 2 , "group1" , 0);
    AddGroupBorder(BORDER_GROUP_IN);
    AddGroupBorderSpace(10 , 5 , 10 , 5);

    AddStaticText(sc_tx , BFH_LEFT , 0 , 0 , "スケール" , 0);
    AddEditNumber(sc_val , BFH_SCALEFIT , 150, 0);
  AddGroupEnd();
  AddDlgGroup(DR_DLGGROUP_OK | DR_DLGGROUP_CANCEL);
}

testDialog::Init(){
  SetFloat(sc_val , d_sc , 0.0 , 4.0 , 0.01);
}

testDialog::AskClose(){
  d_sc = GetFloat(sc_val);
}



//RenderData ===============================================================
class r_data
{
  public:
    var nz;
}



//testChannelPlugin ===============================================================
class testChannelPlugin : ChannelPlugin
{
  public:
    testChannelPlugin();//コンストラクタ

    GetName();//チャンネルシェーダ名
    GetID();  //プラグインID

    EditData(settings);

    InitSettings(settings);

    InitRender(settings);

    //ポイントPの色
    Output(settings , render , p , n , d , t , texflag , vd);
}

testChannelPlugin::testChannelPlugin(){super();}

testChannelPlugin::GetName(){return "testCHShader";}

// http://www.plugincafe.comから取得した、このプラグインの為のplugin idを戻す
//テストID:1000001-1000010

testChannelPlugin::GetID(){return pluginID;}

testChannelPlugin::EditData(settings){
  var dlg = new(testDialog);
  dlg->d_sc = settings->GetData(0);
  dlg->Open(-1 , -1);
  if(dlg->GetResult()){
    settings->SetData(0 , dlg->d_sc);
    return TRUE;
  }else return FALSE;
}

testChannelPlugin::InitSettings(settings){
  settings->SetData(0 , 1.0);
  return TRUE;
}

testChannelPlugin::InitRender(settings){
  var rd = new(r_data);
  rd->nz = new(Noise);
  return rd;
}

testChannelPlugin::Output(settings , rd , p , n , d , t , texflag , vd){
  var col = rd->nz->Noise(p.x / settings->GetData(0) , p.y / settings->GetData(0) , t);

  return vector(col , col , col);
}



//main ============================================================================
main(){
  Register(testChannelPlugin);
}

これで、ノイズクラスをInitRender()メンバ関数で割り当て、それをRenderDataへ格納して渡します。

見た目には、先ほどと変わりがありません。
この2つのチャンネルシェーダの違いを見たいのですが、あまりにもシンプルなので大差は出ないと思います。

とりあえず、レンダリング時間の差を確かめて見ます。
差の確認作業をしやすくする為に少々変更します。

「testCHShader_ReTry_ABcompare.ZIP」

Output()メンバ関数内でノイズを割り当てた方のIDを1000001へ、名前もtestCHShader-Aへ変更しました。
Output()メンバ関数が返すサーフェスの色をグレイ系から赤系へ変更。

InitRender()メンバ関数内でノイズを割り当てた方のIDを1000002へ、名前もtestCHShader-Bへ変更しました。
こちらは、緑系のサーフェスノイズに変更しました。

この2つを適用したマテリアルを背景オブジェクトに設定し比べてみる事にします。

Channelshader_25

今回はC4D R11.0 Demoを使い、サイズ480×360を91フレームレンダリングしてみます。

まずは、AのOutput()メンバ関数内でノイズクラスを割り当てている方から。

Channelshader_23

4分51秒かかりました。

BのInitRender()内でノイズクラスを割り当てた方です。

Channelshader_24

4分31秒でした。
劇的な差は出ませんでしたが、約1割分短縮されています。
やはり、ノイズクラスの割り当ては、InitRender()メンバ関数内で行う方が良いと言う事ですね。

2回目レンダリングしてみましたが…

A 4:53
B 4:26

まだ数回比較テストをした方が良いのですが、似た数値が出たので、比較は終了します。

これで、なんとなくChannelShaderの構造が掴めてきたような気がしますが… 気がするだけですけどね…

ダイアログで変更した数値が何故保持できているのかが、理解できていません。

そう言えば、ノイズクラスの割り当ては理解できたけど、Sin/CosをInitRender()内で先に計算って、どういう事だろう…
360度を幾つかに分割して、三角関数表のような配列でも用意して、Output()内で自分で補間するって事?

違うよね…

|

« C4D ChannelShader…08再挑戦 | トップページ | C4D ChannelShader…10 testChannelPluginクラスの幾つかのメンバ関数にprintln()を取り付けて様子を見る。 »