« たまには、スペインのC4Dはどうだろう… | トップページ | C4D Maxon Twitterで紹介していた、星型プリミティブのプラグインは、もうダウンロードしました? »

Py4D Pythonタグを使ってみる… C.O.F.F.E.E.との比較

残念ながら、C4D R11.5Demoなので、C4Dのシーンファイルとして保存ができません。
テストコードのみです。

Pythontag_01

C.O.F.F.E.E.タグは、イベントを受けて実行されます。要するにマウス操作をしている間は、ほとんど実行状態にあります。
しかし、Pythonタグは、タイムライン上のタイムスライダが移動した時に実行されるようです。

タグのプリセット

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    pass  #put in your code here
main(doc,op)
{


}

Pythonタグの初期値です。
Cinema4DをPythonで制御するために、「import」で「c4d」モジュールを読み込みます。
この段階では、「import c4d」は無くてもエラーにならないようです。

コメントは、「#」で行末までです。
関数は、「def 関数名(引数…):」
処理があるべきところに無いとエラーになりますので、処理が無い場合は、「pass」を使います。
main()の処理が無いので、「pass」が使われています。

Pythonのブロックはインデントなので、ブロック毎に揃えないとエラーになります。

ここで、「op」を使って見ます。

op

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    print op[900]
main(doc,op)
{
  println(op#ID_BASELIST_NAME);

}
Python Tag ヌルオブジェクト

main()関数の引数がありませんが、opが使用可能です。
グローバル変数のようですが…

C.O.F.F.E.E.エクスプレッションタグのopは、このタグが取り付けられているオブジェクトを指しています。が…
Pythonタグのopは、Pythonタグを指しています。

ID_BASELIST_NAME = 900です。

この段階でも「import c4d」が無くてもエラーが起こりません。

次は、Pythonタグが取り付けられているオブジェクトを取得してみます。

タグが取り付けられているオブジェクトの取得

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()
    print obj[900]
main(doc,op)
{
  println(op#ID_BASELIST_NAME);

}
ヌルオブジェクト ヌルオブジェクト

BaseTagクラスの中のメソッドの一つにget_object()があります。
このget_object()は、取り付けられているオブジェクトを取得する事ができます。

Pythonの変数は、他のプログラミング言語(C.O.F.F.E.E.も含む)の様な変数宣言はしません。
変数を使うときは、まず初期値を代入します。
他の言語では変数の型の指定がありますが、PythonはC.O.F.F.E.E.と同じく、ありません。

変数の使用は初期値を代入するところから始まるわけですが、配列の場合はどうするのでしょう。

import c4d
#Welcome to the world of Py4D


def main():
    a = [4, 3, 5, 12.6, "DD"]
    print a[0],
    print a[1],
    print a[2],
    print a[3],
    print a[4]
4 3 5 12.6 DD

配列変数の初期値の入力は、この様に角カッコに要素の数だけコンマで区切ります。
アクセスの方法は、C.O.F.F.E.E.と同じく

配列変数[インデックス番号]

配列に格納する数値はC.O.F.F.E.E.と同じく、型が一致していなくても問題ありません。

既に、「c4d」モジュール内のクラスを使用していると思いますが…
不思議な事に、「import c4d」が無くてもエラーが起こりません。

Pythonタグには、「import c4d」でc4dモジュールの読み込みを行わなくても良いのだろうか…?

では、タグの取り付けられているオブジェクトの子オブジェクトを取得してみます。

タグが取り付けられているオブジェクトの子オブジェクトの取得

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()
    obj = obj.get_down()
    while obj:
      print obj[900]
      obj = obj.get_next()
main(doc,op)
{
  var obj = op->GetDown();
  while(obj)
  {
    println(obj#ID_BASELIST_NAME);
    obj = obj->GetNext();
  }
}
立方体
球体
円錐
立方体
球体
円錐

この様なレベルでは、C.O.F.F.E.E.との劇的な違いがありません。

BaseList2Dクラスのget_down()/get_next()等のメソッドを使って、オブジェクトのツリー構造のリスト内のオブジェクトを取得しながら移動します。

Pythontag_02

Pythonのwhileループには、条件外の時に実行するブロックがあります。

while 式:
  処理1
else:
  処理2

処理2のブロックが、式がFALSEの時に実行されます。

Pythontag_03

このelseブロックは省略できます。

では、elseブロックを使ってみましょう。

whileのelseブロックの使用

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()
    obj = obj.get_down()
    while obj:
      print obj[900]
      obj = obj.get_next()
    else:
      print "The child object doesn't exist."
main(doc,op)
{
  var obj = op->GetDown();
  while(obj)
  {
    println(obj#ID_BASELIST_NAME);
    obj = obj->GetNext();
  }
  if(!obj)println("The child object doesn't exist.");
}
立方体
球体
円錐
The child object doesn't exist.
立方体
球体
円錐
The child object doesn't exist.

問題ありませんね。

次はオブジェクトのパラメータを取得し変更てみましょう。

オブジェクトのパラメータの取得

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()
    obj = obj.get_down()

    print obj[900]
    size = obj[1100]
    size.y = size.x * 2.0
    obj[1100] = size

    print size
main(doc,op)
{
  var obj = op->GetDown();

  println (obj#ID_BASELIST_NAME);
  var size = obj#PRIM_CUBE_LEN;
  size.y = size.x * 2.0;
  obj#PRIM_CUBE_LEN = size;

  println(size);
}
立方体
(200, 400, 200)
立方体
[200.000000,400.000000,200.000000]

子オブジェクトの立方体のサイズを取得。
サイズXの値を2倍にした数値をサイズYに代入。
変更したサイズを立方体に再度適用します。

C.O.F.F.E.E.Vector型同様、変数.x、変数.y、変数.zと言う具合にアクセスします。

サイズを取得する前に、既にオブジェクトの名前の取得で、オブジェクトのパラメータにアクセスしていました。

オブジェクト[ID]

これで、オブジェクトのパラメータにアクセスできます。
PRIM_CUBE_LEN = 1100

これで、オブジェクトのパラメータ操作ができます。

次にオブジェクトのユーザデータにアクセスしてみよう。

ユーザデータへのアクセス

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()

    print obj[900]
    print obj[c4d.ID_USERDATA,1]
main(doc,op)
{
  println(op#ID_BASELIST_NAME);
  println(op#ID_USERDATA:1);
}
ヌルオブジェクト
10
ヌルオブジェクト
10

Pythonタグが取り付けられているヌルオブジェクトには、次のようにユーザデータを設定してあります。

Pythontag_04

Pythonからのオブジェクトのユーザデータのアクセスは…

オブジェクト[c4d.ID_USERDATA, ユーザデータ番号]

ここで、コードの先頭の「import c4d」を削除するとエラーが起こります。
ようやく、「c4d」モジュールが使われました。

c4d.ID_USERDATA = 700

C.O.F.F.E.E.での定数:ID_USERDATA = 700は、Pythonではc4dモジュール定数:ID_USERDATA = 700という事です。

import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()

    print obj[900]
    print obj[700, 1]

これでもエラーが起こらず実行されます。

と、言う事は…

import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()

    print obj[c4d.ID_BASELIST_NAME]
    print obj[c4d.ID_USERDATA, 1]

淡い期待も虚しく消え…
エラーが表示されました。

いきなりですが、while以外のループの for を試してみます。

一般的なループ for

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()

    pts = obj.get_points()
    tg = obj.get_down()
    for c in range(len(pts)):
      if tg:
        tg.set_pos(pts[c])
        tg = tg.get_next()
main(doc,op)
{
  var pts = op->GetPoints();
  var tg = op->GetDown();
  var c;
  for(c = 0 ; c < sizeof(pts) ; c++)
  {
    if(tg)
    {
      tg->SetPosition(pts[c]);
      tg = tg->GetNext();
    }
  }
}

これは、スプラインオブジェクトの幾つかの球体の子オブジェクトをポイントの位置に配置します。

Pythontag_05

オブジェクトの型のチェックはしていません。

コードの構成はPythonもC.O.F.F.E.E.も同じです。

スプラインのポイント配列を取得
子オブジェクトを取得
ポイント配列のインデックスの数だけループ
カウンタ変数cに繰り返した回数を保持
子オブジェクトがあれば、ポイント配列のインデックスにカウンタ変数を使用し、子オブジェクトにポイントの座標を適用。
次の子オブジェクトを取得

C.O.F.F.E.E.では、配列変数のインデックス数はsizeof(配列変数)で求められますが、Pythonでは、len(配列変数)のようです。
range(n)関数は、0~n-1の数値を出力するそうで…具体的な事はまだ理解できていません。

C.O.F.F.E.E./C/C++等の for の条件式を評価してTRUEの時だけ繰り返すスープとは違うという事です。

もう少し、具体的にみてみます。

一般的なループ for(10回ループ)

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    for c in range(10):
      print c,
main(doc,op)
{
  var c;
  for(c = 0 ; c < 10 ; c++)print(c, " ");
  println();
}
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

C.O.F.F.E.E.のコードと同じ動作をしています。

0~9までの10回ループです。
この状態では、range(n)という関数の実態がわかりません。

import c4d
#Welcome to the world of Py4D


def main():
    print range(10)
    for c in range(10):
      print c,
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9

range(n)は連番を格納した配列を返えします。

ならば、直接配列を使用する事も可能と言う事です。

import c4d
#Welcome to the world of Py4D


def main():
    for c in [0, 5, 3, 2, 4]:
      print c,
0 5 3 2 4

これは、とても便利な機能です。

これを踏まえると、最初に使用したスプラインのポイントに球体を配置するPythonタグも、次のようにスプラインのポイント配列を使う事も可能だということです。

import c4d
#Welcome to the world of Py4D


def main():
    obj = op.get_object()

    pts = obj.get_points()
    tg = obj.get_down()
    for pos in pts:
      if tg:
        tg.set_pos(pos)
        tg = tg.get_next()

Pythontag_05

ポイント配列変数より、順番に座標データが変数posに代入されます。
後は、そのままオブジェクトの座標に適用していきます。

要するに、配列のインデックス数だけ繰り返し、配列に格納している数値を順に指定した変数に代入するのです。

もう少しだけrange()関数を見てみましょう。

import c4d
#Welcome to the world of Py4D


def main():
    print range(2, 5)
[2, 3, 4]

range(start , end)

このrange()関数で取得できる配列は、インデックス数 : end - start、格納される値 : start~end - 1と言う事です。

import c4d
#Welcome to the world of Py4D


def main():
    print range(2, 25, 3)
[2, 5, 8, 11, 14, 17, 20, 23]

range(start, end, step)

3番目の引数がステップ値です。もちろんステップ値は負の値でも問題はありません。
ステップ値が負の値の場合は、startはendより大きくなくてはいけません。

import c4d
#Welcome to the world of Py4D


def main():
    print range(25, 5, -3)
[25, 22, 19, 16, 13, 10, 7]

これで、range()関数が理解できたと思います。

では、「一般的なループ for」に戻ります。

Pythonの for には、while同様にelse:ブロックを使用することができます。

for 変数 in 配列:
  処理1
else:
  処理2
Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    for c in range(10):
      print c,
    else:
      print "end"
main(doc,op)
{
  var c;
  for(c = 0 ; c < 10 ; c++)
  {
    print(c, " ");
  }
  if(!(c < 10))println("end");
}
0 1 2 3 4 5 6 7 8 9 end 0 1 2 3 4 5 6 7 8 9 end

このelse:ブロックはループの最後に実行されます。
Pythonのforは多言語と違い、繰り返し条件式の評価ではないのでelseの意味合いが違うのでは?と思われるユーザもいるとは思います。
ループが完了するとelseブロックが実行されます。ループの途中でbreakが実行されると、elseブロックは実行されません。

import c4d
#Welcome to the world of Py4D


def main():
    for c in range(10):
      print c,
      if c == 7:break
    else:
      print "end"
0 1 2 3 4 5 6 7

while同様、elseブロックは省略が可能です。

さて、ここで「一般的なループ for」は一旦終了します。
次は、上のコードでも使いました、条件分岐の if を見てみましょう。

一般的な条件分岐 if

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    for c in range(10):

      print c,

      if c is 3:
        print "A",
      else:
        print "*",
main(doc,op)
{
  var c;
  for(c = 0 ; c < 10 ; c++)
  {
    print(c, " ");

    if(c == 3)
      print("A ");
    else
      print("* ");
  }
  println();
}
0 * 1 * 2 * 3 A 4 * 5 * 6 * 7 * 8 * 9 * 0 * 1 * 2 * 3 A 4 * 5 * 6 * 7 * 8 * 9 *

PythonもC.O.F.F.E.E.も基本的に大差はありません。
C.O.F.F.E.E.での比較式は、c == 3ですがPythonでは c is 3 になっています。
もちろん、Pythonでも c == 3 と記述しても比較され不具合はありません。

他の言語では、if()の条件式がFALSEの時に、更にif()を重ねて使う場合に else if があります。
Pythonにも同様にelse if があります。記述は elif です。

Python C.O.F.F.E.E.
import c4d
#Welcome to the world of Py4D


def main():
    for c in range(10):

      print c,

      if c is 3:
        print "A",
      elif c is 7:
        print "B",
      else:
        print "*",
main(doc,op)
{
  var c;
  for(c = 0 ; c < 10 ; c++)
  {
    print(c, " ");

    if(c == 3)
      print("A ");
    else if(c == 7)
      print("B ");
    else
      print("* ");
  }
  println();
}
0 * 1 * 2 * 3 A 4 * 5 * 6 * 7 B 8 * 9 * 0 * 1 * 2 * 3 A 4 * 5 * 6 * 7 B 8 * 9 *

Pythonも、他言語とあまり変わりがありません。

今回の記事の最後に条件分岐 if 等の比較式に使う演算子等を…

Python C.O.F.F.E.E.
a is b , a == b a == b
a is not b , a != b a != b
a and b a && b
a or b a || b
a < b , a <= b a < b , a <= b
a > b , a >= b a > b , a >= b
not a !a

まだまだPythonを習得まで学習する事が沢山あります。

関数等、まだ試していないですね…
でも、main関数は使っていますが…

所詮Pythonもプログラミング言語のひとつであり、他の言語との共通点が沢山あります。
全くの未知の言語ではありません。
何かひとつでもプログラミング言語を習得しているのであれば、習得にはさほど時間がかからないと思います…
さぁ、ご一緒に習得に励みましょう…

|

« たまには、スペインのC4Dはどうだろう… | トップページ | C4D Maxon Twitterで紹介していた、星型プリミティブのプラグインは、もうダウンロードしました? »