« ただの暇つぶし… | トップページ | C4D C.O.F.F.E.E.のRandomクラスのガウス分布の確認。 »

C4D C.O.F.F.E.E.Randomクラスを使ってポリゴンオブジェクトを変形させる。

変形させると言っても、「デフォーマオブジェクト」ではなく、「ポイントの位置を設定」に似ています。

さて、Randomクラスは…

ランダムな数値を発生させます。

Randomクラスのメンバ関数です。

[boid]Init([int]seed) ランダムシーケンスの初期化 0~2000000000
[float]Get01() 0.0~1.0までの乱数 出現分布は均等
[float]Get11() -1.0~1.0までの乱数 出現分布は均等
[float]GetG01() 0.0~1.0までの乱数 出現分布は0.5をピークとしたガウス
[float]GetG11() -1.0~1.0までの乱数 出現分布は0.0をピークとしたガウス

ランダムな数値と言っても、完全なランダムな数値ではなく擬似的なのもです。
約2000000000枚の乱数表の中の1枚の、上から順番に出力されると思ってください。
近い乱数表のランダムな値は似たような数値の並びになっています。

Init()
乱数表の番号を指定すると思ってください。0~2000000000までの番号です。

Get01()
0.0~1.0までの実数が返ってきます。出現分布は均等です。
もし整数0~500までの乱数が欲しいなら、int(xxx->Get01() * 500)とします。

Get11()
-1.0.~1.0までの実数が返ってきます。出現分布は均等です。

GetG01()
0.0~1.0までの実数が返ってきます。出現分布は0.5をピークとしたガウスです。
Romdom01
0.5付近が一番多く出現します。

GetG11()
0.0~1.0までの実数が返ってきます。出現分布は0.0をピークとしたガウスです。
Romdom02
0.0付近が一番多く出現します。

では、平面オブジェクトを追加し編集可能にして、COFFEEエクスプレッションタグを取り付けます。

Romdom03

このポリゴンオブジェクトのポイントをRandomクラスでY軸方向に変形させます。
ランダム数値の幅は0.0~100.0とします。

COFFEEエクスプレッションは、次のように入力しました。

/*
ポイントオブジェクトのポイントのYの値を0.0~100.0のランダム値にします。
2009.6.19
*/


main(doc , op)
{
  if(!instanceof(op , PointObject))return;//ポイントオブジェクトなのでスプラインでもOK

  var pts = op->GetPoints();    //ポイントの取得
  var ptc = op->GetPointCount();//ポイント数の取得

  var rnd = new(Random);        //ランダム

  var i;  //カウンタ変数

  //ポイントの変更
  for(i = 0 ; i < ptc ; i++){
    pts[i].y = rnd->Get01() * 100.0;
  }

  //オブジェクトの更新
  op->SetPoints(pts);
  op->Message(MSG_UPDATE);
}

結果です。

Romdom04

このCOFFEEエクスプレッションは、オブジェクトの元の形には全く関係なく Y の値を0.0~100.0のランダムな数値に強制します。
たまたま、このオブジェクトが平面オブジェクトで向きがXZ平面だったので、ランダムに隆起したように感じますが、他のオブジェクトでは全く違う意味合いになります。

さて、このコードはCOFFEEエクスプレッションに入力されたので、アニメーションに対応していると思った方もいると思います。
が、アニメーションタイムスライダーを動かしても、もしくは再生しても、最初の形から変化しません。

アニメーションでランダム値を使うには、他にすることがありますし、注意する事もあります。
が、今回は、取り上げません。

Randomクラスが出力するランダム値は、あくまでも擬似ランダムです。
Randomクラスを宣言し初期化された時点を起点にメンバ関数で乱数表の順番で出力されます。

さて、ここからはユーザスクリプトに移ります。
と言うか…最初からユーザスクリプトで良かったんじゃ…?

次のスクリプトは、オブジェクトに関係はありません。

/*
Randomクラスの確認
2009.6.19
*/


main(doc , op)
{
  var rnd = new(Random);
  var seed;
  var i;


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);

  for(i = 0 ; i < 10 ; i++)println(i , " : " , rnd->Get01());


  seed = 2000000000;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);

  for(i = 0 ; i < 10 ; i++)println(i , " : " , rnd->Get01());


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);

  for(i = 0 ; i < 10 ; i++)println(i , " : " , rnd->Get01());
}

シード0のランダム値を10個取得した後、シード2000000000のランダム値を10個取得。
その後、シード0のランダム値を10個再取得します。

random seed 0
0 : 0.000032
1 : 0.221482
2 : 0.526160
3 : 0.359956
4 : 0.805756
5 : 0.779681
6 : 0.774022
7 : 0.951885
8 : 0.764386
9 : 0.371560
random seed 2000000000
0 : 0.518938
1 : 0.548041
2 : 0.667278
3 : 0.209591
4 : 0.221215
5 : 0.128129
6 : 0.748033
7 : 0.913802
8 : 0.371442
9 : 0.132156
random seed 0
0 : 0.000032
1 : 0.221482
2 : 0.526160
3 : 0.359956
4 : 0.805756
5 : 0.779681
6 : 0.774022
7 : 0.951885
8 : 0.764386
9 : 0.371560

ランダム値は、シード値で初期化された時点で乱数表の最初に戻り、順番に出力されます。

Randomクラスが割り振られた変数を何度でも初期化する事ができます。その都度、乱数表の最初に戻ります。

今回は、RandomクラスのGet01()メンバ関数だけでしたが、他のメンバ関数をシード番号の途中で使用した場合はどうでしょう?

/*
Randomクラスの確認
2009.6.19
*/


main(doc , op)
{
  var rnd = new(Random);
  var seed;
  var i;


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);
  println("Get01()");
  for(i = 0 ; i < 10 ; i++)println(i , " : " , rnd->Get01());


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);
  println("Get11()");
  for(i = 0 ; i < 10 ; i++)println(i , " : " , rnd->Get11());


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);
  println("Get11()");
  for(i = 0 ; i < 5 ; i++)println(i , " : " , rnd->Get11());
  println("Get01()");
  for(i = 0 ; i < 5 ; i++)println(i+5 , " : " , rnd->Get01());
}

初期化してGet11()で-1.0~1.0のランダム値を5個取得し、そのまま初期化せずGet01()で0.0~1.0のランダム値を5個取得します。

random seed 0
Get01()
0 : 0.000032
1 : 0.221482
2 : 0.526160
3 : 0.359956
4 : 0.805756
5 : 0.779681
6 : 0.774022
7 : 0.951885
8 : 0.764386
9 : 0.371560
random seed 0
Get11()
0 : -0.999936
1 : -0.557036
2 : 0.052320
3 : -0.280088
4 : 0.611513
5 : 0.559362
6 : 0.548045
7 : 0.903771
8 : 0.528772
9 : -0.256880
random seed 0
Get11()
0 : -0.999936
1 : -0.557036
2 : 0.052320
3 : -0.280088
4 : 0.611513
Get01()
5 : 0.779681
6 : 0.774022
7 : 0.951885
8 : 0.764386
9 : 0.371560

さて、結果は他のメンバ関数が混ざっていても順番通り出力されます。

Get01()とGet11()は別々にランダム表が、用意されているのだろうか?
それとも…

それとも、同じ乱数表を、ただスケーリングして出力しているのかなぁ?

更に確認のスクリプト。

/*
Randomクラスの確認
2009.6.19
*/


main(doc , op)
{
  var rnd = new(Random);
  var seed;
  var f;
  var i;


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);
  println("Get01()");
  for(i = 0 ; i < 10 ; i++)println(i , " : " , rnd->Get01());


  seed = 0;
  rnd->Init(seed);//初期化
  println("random seed : " , seed);
  println("Get11()          (Get11() + 1) / 2.0");
  for(i = 0 ; i < 10 ; i++){
    f = rnd->Get11();
    println(i , " : " , f , "   " , (f + 1) / 2.0);

    //間違って、変数を使わないでこんな風にすると、正確な比較にはならないよ。
    //println(i , " : " , rnd->Get11() , "   " , (rnd->Get11() + 1) / 2.0);

  }
}

やはり、同一の乱数表をスケーリングしていただけなのね。

random seed 0
Get01()
0 : 0.000032
1 : 0.221482
2 : 0.526160
3 : 0.359956
4 : 0.805756
5 : 0.779681
6 : 0.774022
7 : 0.951885
8 : 0.764386
9 : 0.371560
random seed 0
Get11()          (Get11() + 1) / 2.0
0 : -0.999936   0.000032
1 : -0.557036   0.221482
2 : 0.052320   0.526160
3 : -0.280088   0.359956
4 : 0.611513   0.805756
5 : 0.559362   0.779681
6 : 0.548045   0.774022
7 : 0.903771   0.951885
8 : 0.528772   0.764386
9 : -0.256880   0.371560

ガウス分布のメンバ関数も、多分同じ乱数表を使っているのだろう。
今回は、ガウス分布は保留します。

Randomクラスが、2000000000枚の乱数表を用意していますが、1枚の乱数表には幾つの乱数があるのだろう…
一応1000000000個を確認しましたが、これ以上あるようです。

では、ポリゴンオブジェクトをRandomクラスを使って変形させるスクリプトを作ってみよう。

/*
ポイントオブジェクトを±10でランダム変形させる
2009.6.19
*/


Deform(obj , f)
{

  var pts = obj->GetPoints();
  var ptc = obj->GetPointCount();
  var rnd = new(Random);
  var i;

  for(i = 0 ; i < ptc ; i++){
    pts[i] += vector(rnd->Get11() * f , rnd->Get11() * f , rnd->Get11() * f);
  }

  obj->SetPoints(pts);
  obj->Message(MSG_UPDATE);
}


main(doc , op)
{
  if(!instanceof(op , PointObject))return;

  doc->StartUndo();
  doc->AddUndo(UNDO_OBJECT_BASEDATA , op);
  doc->EndUndo();

  Deform(op , 10);
}

今回は、オブジェクトを変形する関数をつくり、オブジェクトと変化量を変形関数に渡しています。

これで、ポイントオブジェクトのポイントの現座標を±10で変化させます。
試しに、ポリゴンオブジェクトを選択し実行してください。
問題なく変化したと思います。

コードを見てわかるように、複数選択には対応していません。

では、このスクリプトをポリゴンオブジェクトに、数回実行してください。
どのポイントも、一度移動した方向にしか変化しません。

なぜ変化が同じなのかは、説明しなくてもわかると思います。
そうですね、RandomクラスのInit()で指定できるシード値が同じだからですね。

では最後に、このシード値を変更するためにダイアログを使ってみよう。
一緒に、変化量も変更できるようにしてみます。

ダイアログは過去の記事を参照してください。
http://villager-and-c4d.cocolog-nifty.com/blog/2008/06/post_2438.html

/*
ポイントオブジェクトをランダムに変形させる。
2009.06.19
*/


class tools_dialog : GeModalDialog
{
  public:
    var seed;
    var def;

    tools_dialog();
    Init();
    CreateLayout();
    AskClose();
}

tools_dialog::tools_dialog()
{
  super();
  seed = 0;
  def = 10;
}

tools_dialog::Init()
{
  SetFloat(1002 , seed , 0 , 2000000000 , 1);
  SetFloat(1004 , def , 0 , 1000000000 , 1);
}

tools_dialog::CreateLayout()
{
  SetTitle("ポリゴンオブジェクトの変形");
  AddGroupBeginV(1000 , BFV_SCALEFIT , 2 , "tools group" , 0);
    AddStaticText(1001 , 0 , 0 , 0 , "シード" , 0);
    AddEditNumber(1002, 0, 150, 0);
    AddStaticText(1003 , 0 , 0 , 0 , "変化量" , 0);
    AddEditNumber(1004, 0, 150, 0);
  AddGroupEnd();
  AddDlgGroup(DR_DLGGROUP_OK | DR_DLGGROUP_CANCEL);
}

tools_dialog::AskClose()
{
  seed = GetFloat(1002);
  def = GetFloat(1004);
}

ToolsExecution(obj , def , seed)
{
  var pts = obj->GetPoints();
  var ptc = obj->GetPointCount();
  var rnd = new(Random);
  var i;

  rnd->Init(seed);

  for(i = 0 ; i < ptc ; i++){
    pts[i] += vector(rnd->Get11() * def , rnd->Get11() * def , rnd->Get11() * def);
  }

  obj->SetPoints(pts);
  obj->Message(MSG_UPDATE);
}


main(doc , op)
{
  if(!instanceof(op , PointObject))return;

  var t_dialog = new(tools_dialog);
  t_dialog->Open(-1 , -1);
  if(!(t_dialog->GetResult()))return;

  doc->StartUndo();
  doc->AddUndo(UNDO_OBJECT_BASEDATA , op);
  doc->EndUndo();

  ToolsExecution(op , t_dialog->def , t_dialog->seed);
}

これで、変化量とランダムシードの変更ができるようになりました。

|

« ただの暇つぶし… | トップページ | C4D C.O.F.F.E.E.のRandomクラスのガウス分布の確認。 »