日本でハリウッドVFXを制作! 「経産省アイディアボックス」 結果:  
●まとめエントリはこちら ●FAQ ●お問い合わせは左のメールフォームから

2012年3月19日月曜日

「スカラー」の語源

Melやプログラム言語を勉強していて「スカラー値」という言葉がよく出てくる。

これは最初とまどったがようはベクター(複数の数字が一組になって表現されるもの)などに対して、ひとつの数字 で表される物を指していると理解してからはほぼつじつまが合うので、そのまますすめてきた。
参照1:スカラー,ベクトル,行列

ところでこの「スカラー」という言葉。
英語の発音を聞くとどちらかというと「スケーラー」(音声参照:goo辞書) と聞こえる。

そうメモリとか物差しを意味するスケールとほぼ同じである。

英語表記、発音記号は以下のように「Scal」まではほぼ同じである。
スカラー:Scalar (skéilər
スケール:Scale (skéil

これって同じ所から来ているのかも知れないので語源を調べてみた。

英語版Wikiで見るとラテン語の「Scalaris」から来ており、ラテン語で「はしご(Ladder)」を意味するScalaの形容詞句である。
英語の「Scale(スケール)」も「Scala」から派生している。
記録にある限り数学で最初に「Scalar(スカラー)」の意味として使われたのはフランソワ・ビエトによる、「Analytic Art」(1591年)の中である。

    Magnitudes that ascend or descend proportionally in keeping with their nature from one kind to another are called scalar terms.
(一つの状態から他の状態へ同比率で上昇または降下するその大きさ(等級)をスカラーという用語で呼ぶ)



参照:Online Etymology Dictionary「Scalar」
"resembling a ladder," 1650s, from L. scalaris "of or pertaining to a ladder," from scalae (pl.) "ladder, steps" (see scale (n.2)). Mathematical sense first recorded 1846.




そしてほぼこれと同じ意味で推測されている方が居てWeb上にうまくまとめられていたのでそれを引用しておきたい。
参照:Meta2mathematician's HP 
スカラー scalar

この 「スカラー」 という言葉は大学で線型代数学でも学ばないとなかなか目にしなくなったが, これは scale (スケール) という言葉から発生したものだと思われる。 音楽家が scale といえばそれは 「音階」 のことであるが (こっちはフランス語では gamme, ドイツ語では Tonleiter, Skala, イタリア語では scala, gamma という), (英語では) 同語源の単語 scale, 即ち 「目盛り」 とか 「物差」 とかを意味する言葉である。 つまり, vector が 「大きさと方向を持つ量」 であるのに対し, 「物の大きさ」 を示す量が (物差しで測れる量) scalar なのであろう。

補足だがここでは最初に使ったのは、「William Rowan Hamilton(1805-1865) 」とあるが、上記Wikiによると1846年に英語の用語「scalar」を最初に使ったのが彼である。
(上記、フランソワ・ビエトは同様の意味で使ったが使用したのはラテン語「Scalaris」)

2012年3月4日日曜日

パーティクル101 その4:saveInitialState無しで追加したパーティクルを保存する(2)

今回の内容は、実は「その2:アスキーファイルの分析」よりも前に書いてました。
でも、ファイルの基本的内容を知っていると、今回の内容が理解しやすいので
後回しにさせてもらいました。


<はじめに>
前回、説明しましたとおり、今回の結果は結局は勘違いを元に動いており、
実用的ではないですが、
●アスキーファイルの分析例
●setAttrを使ったパーティクルアトリビュートの設定法

は参考になると思います。
ただし長いです。




<動機>
Expressionによる方法では、開始フレームにおいて追加したいパーティクルを表示することが出来ません。

もういちど「particle」コマンドを使うとどうなるのかおさらいしてみます。
最初からパーティクルをいくつかもたせてparticleShapeを作れば、
開始フレームから最終フレームまでそのままです。
そのファイルを保存して開いても、そのパーティクルが消えることはありません。


適切な表現かどうかはわかりませんがパーティクルの数がしっかりそのノードに記憶されているのです。


なぜそのノードに記憶されているんでしょう?
その記憶をちょこっと修正すれば、そのノード(particleShape)にちゃんと追加したパーティクルの情報を埋め込んでおくことができるんじゃないでしょうか?

なぜそんな簡単というか重要なことができる機能がないのか?(← ここが勘違い。InitialStateがその働きをします。

まぁMayaだから仕方がない。どうやったらできるか考えてみることにしました。

これについても@spx808さんからヒントをもらい、アドバイス通りMayaアスキーファイルを分析してみることにした。
「パーティクルの初期状態はposition0のようにPPアトリビュートの前に0をつけたもので記録されています。
初期状態で存在するパーティクルはid0とnextId0で記録されています。
.maファイルを読むと仕組みが理解できるので解析してmel化することができると思います。」
「m0,id0,nid0,pos0あたりのアトリビュートをセットしてやればなんとかなると思いますがけっこうめんどいです。」

なにぶん、アスキーファイル、パット見て「あっここだ!」とさらさらっと修正するほどなれてませんので、
ステップを明確にして、少しづつ解析していきました。




<分析手順>
1)4つの異なるシーンを作成。)
パーティクル個数が
(a)ゼロ
(b)1個(原点)
(c)1個(座標1,1,1)
(d)二個(原点と座標1,1,1の位置)
2)それぞれアスキー形式(.ma)で保存
3)アスキーファイルを開きParitcleShapeに関連する部分を切り出し比較。
※この切り出したものは最後に画像ファイルとしてまとめて掲載してあります。


それによりわかったのはファイル内では
●particleShape はcreateNodeコマンドで作られている
●各アトリビュートがsetAttrで設定されている
●異なっている部分は以下のアトリビュート


pos0
vel0
acc0
nid (パーティクルが存在する時のみ)
nid0 (パーティクルが存在する時のみ)
bt0
ag0
lifespanPP0




ヘルプ「particle」ノードの項目で各アトリビュートを調べどんな内容が設定されているのか調べてみます。
まずは「pos0」からです。


<pos0>
pos0: 「各パーティクルにおける初期状態のposition(位置)」
注意すべきは「pos」というアトリビュートもあるという点、違いはpos0は初期位置であるという点
(@spx808さんのアドバイスにもありますが、アトリビュート名の後ろに「0」がついているのは
初期状態を記録しているアトリビュートの意味です。)


作例の4つのファイルを比較すると以下のようになる。
(a)個数ゼロ:       setAttr ".pos0" -type "vectorArray" 0 ;
(b)原点に1個:     setAttr ".pos0" -type "vectorArray" 1 0 0 0 ;
(c)座標1,1,1に1個:     setAttr ".pos0" -type "vectorArray" 1 1 1 1 ;
(d)原点と座標1,1,1に計2個:  setAttr ".pos0" -type "vectorArray" 2 0 0 0 1 1 1 ;


なるほど、「1 0 0 0」「2 0 0 0」というところで、どうやら個数と座標値がセットされているらしい。
では具体的にはどのようにしてセットされているのかを見ていきたい。


<setAttrの使われ方>
setAttrはアトリビュートに値を設定するコマンド。
まずはCGWorldの「Mel for Designers」のサポートページがわかりやすいのでそちらを参考にしてSetAttrの全体像をつかむ事にする。

「ノードのプロパティを指定した値に設定します。
構文: setAttr ノード名.プロパティ名 設定値
例:pCube1のスケールYを6.0に設定します。
setAttr pCube1.scaleY 6.0 ; 」



今回、アスキーファイルに書き込まれているsetAttrの行には、
●ノード名が無く
●プロパティー名が「" "」でくくられて".pos0"となっている。

この理由はヘルプから見つけることは出来なかった。

そこで勝手に推測してみることにする。
●ノード名が無い理由 --> 「すでに対象ノードが選択されているから」
この一連のsetAttrの直前には「createNode」 コマンドが実行されている。
コマンドが実行されて最後に作られたノードは選択状態になる。
この場合は、「particleShape」が選択状態になっている。
それに関係するコマンドを続けて実行するので、わざわざノード名を指定する必要がない。
それで、プロパティー名のみを指定しているということだと思われる。

●「" "」でくくられている理由 --> 「文字列であることを明記するため」
これも推測。これは文字列を示すためのMel内の基本的な決まり事である。
実際には使わなくても良いが、明確にするために使っているのだろう。


これらを実証するために「Mel for Designers」の例を元に試してみます。

pCube1を作成して以下の5つの条件でsetAttrコマンドを実行してみました。

実験1)ノード名.プロパティー名を「" "」でくくる。
setAttr "pCube1.scaleY" 6.0 ; をpCube1を選択しないで実行
--> 正常動作

実験2)ノード名.プロパティー名を「" "」でくくらない。
setAttr pCube1.scaleY 6.0 ; をpCube1を選択しないで実行
--> 正常動作

実験3)ノード名なし、.プロパティー名だけを「" "」でくくる。。
setAttr ".scaleY" 6.0 ; をpCube1を選択しないで実行
--> エラー // Error: setAttr: No object matches name: .scaleY //

実験4)同条件
setAttr ".scaleY" 6.0 ; をpCube1を選択してから実行
--> 正常動作

実験5)同条件
setAttr .scaleY 6.0 ; をpCube1を選択してから実行
--> 正常動作

以上の実験から、以下のことがわかります
● プロパティー名がなければ対象が選択されていないと動作しない。

● プロパティー名だけの表記でも動作する。
● プロパティー名は文字列であるが「" "」で囲んでも囲まなくてもよい。




<-type "vectorArray">
さて、元のアスキーファイルにあるsetAttrに戻ります。

最後の数字は設定値である事はわかるが、
数字の前に「-type "vectorArray"」というフラグが使われている、これは何でしょうか?

ヘルプファイルで調べてみます。
オンラインヘルプ:setAttr

「-type フラグは、非数値型のアトリビュートを設定するときのみに必要となります
    {TYPE} はスペースで区切られた任意の数のタイプ(TYPE)の値を意味します。
    [TYPE] はタイプ(TYPE)の値がオプションであることを意味します。」


「1 0 0 0」は数値ではないか?という思ってしまうかもしれないが、
アトリビュートの「型」としては違う。
ここではアトリビュートとしては「配列」という形式になるのだが、
「配列」自体は数値を入れる入れ物ではあっても、「数値」そのものではなく「入れ物」である。
それで非数値型アトリビュートということになっているらしい。
こういうのは言葉の遊びのように思えてきて初心者には、どうでもいいことのように感じる事があるが、コンピュータでは明確に処理の仕方が異なってくるので、あきらかに違うのである。


この非数値型の他の種類も含めてオンラインヘルプに表で示してある。

-type vectorArray」の所を見てみると
「ベクトルの可変長配列」ということなので
1)ベクトルの配列
2)配列の数は固定ではない。

ことがわかる。
パーティクルの数が増えればそのベクター値を格納するところ(配列)を、それに応じて増やせるということになる。

値についての箇所は以下のようになっている
値の構文 :    int {double double double}
値の意味 :    numberOfArrayValues {xValue yValue zValue}

とある。
Integer(整数)により配列の数を指定し、xyzの値を次に指定するという形式を取ることがわかる。
実際にはこの「{ }」の括弧は使われるわけではないので、この文章の中でデータの違いを示すためのものであろう。



今回の各テストシーンにおける「pos」アトリビュートに設定される配列数と値は以下のようになっている。

(a)個数ゼロ:       setAttr ".pos0" -type "vectorArray" 0 ;
配列数:ゼロ

(b)原点に1個:     setAttr ".pos0" -type "vectorArray" 1 0 0 0 ;
配列数:1、値 0 0 0

(c)座標1,1,1に1個:     setAttr ".pos0" -type "vectorArray" 1 1 1 1 ;
配列数:1、値 1 1 1

(d)原点と座標1,1,1に計2個:  setAttr ".pos0" -type "vectorArray" 2 0 0 0 1 1 1 ;
配列数:2、値 0 0 0 と 1 1 1


ここから考えると
●配列数はパーティクルの数と同じ
●パーティクルの各座標値が、その後にスペースをはさんで続く、カンマなどの区切りはない


パーティクル数(スペース)x1(スペース)y1(スペース)z1(スペース)x2(スペース)y2(スペース)z2 ・・・
という具合になる。


<-type "doubleArray">
さてsetAttr ".mas0" -type "doubleArray" 0 ; の部分をみると
「-type "doubleArray"」というフラグが使われている。

先ほどとは違うので、これも後のために調べておくことにす
オンラインヘルプ:setAttr

ヘルプを見ると「倍精度浮動小数点数の可変長配列
1)倍精度浮動小数点数の配列
2)配列の数は固定ではない。

ということになる。

.mas」(mass)は質量を示しているアトリビュートだが、各パーティクルの初期質量を倍精度小数点の数値で指定いると言うことになる。

値の構文     int {double}
値の意味     numberOfArrayValues {arrayValue}

Integer(整数)により配列の数を指定し、値を次に指定するという形式を取ることがわかる。
先ほどのvectorArrayと比べると値は一つなのでわかりやすい。

●配列数はパーティクルの数と同じになる。
●パーティクルの各初期質量が、その後にスペースをはさんで続く、カンマの区切りはない。


パーティクル数(スペース)a(スペース)b(スペース)c(スペース)d(スペース)e・・・
という具合になる。


さてここまででパーティクルにおけるsetAttrの使われ方がわかったので、
今度は各アトリビュート名ごとに調べていく。
「pos0」についてはすでに見たので、それ以降について調べてみる。



<vel0>
vel0:これも「vel」プロパティーと混同しないように要注意。
パーティクル毎のVelocity(方向性を持った速度)の初期値
デフォルト値:空
オンラインヘルプ:パーティクル

(a)個数ゼロ:       setAttr ".vel0" -type "vectorArray" 0 ;
配列数:ゼロ、値:なし

(b)原点に1個:     setAttr ".vel0" -type "vectorArray" 1 0 0 0 ;
配列数:1、値: 0 0 0

(c)座標1,1,1に1個:     setAttr ".vel0" -type "vectorArray" 1 0 0 0 ;
配列数:1、値: 0 0 0

(d)原点と座標1,1,1に計2個:  setAttr ".vel0" -type "vectorArray" 2 0 0 0 0 0 0 ;
配列数:2、値: 0 0 0 と 0 0 0

デフォルトで作成されたものはVelocityはゼロであることがわかる。



<acc0>
acc0:これも「acc」プロパティーと混同しないように要注意。
パーティクル毎のAcceleration(加速度)の初期値
デフォルト値:空

(a)個数ゼロ:       setAttr ".acc0" -type "vectorArray" 0 ;
配列数:ゼロ、値:なし

(b)原点に1個:     setAttr ".acc0" -type "vectorArray" 1 0 0 0 ;
配列数:1、値: 0 0 0

(c)座標1,1,1に1個:     setAttr ".acc0" -type "vectorArray" 1 0 0 0 ;
配列数:1、値: 0 0 0

(d)原点と座標1,1,1に計2個:  setAttr ".acc0" -type "vectorArray" 2 0 0 0 0 0 0 ;
配列数:2、値: 0 0 0 と 0 0 0


デフォルトで作成されたものはAccelerationもゼロ



<mas0>
mas0:これも「mas」プロパティーと混同しないように要注意。
パーティクル毎のmass(重さ)の初期値
デフォルト値:空


(a)個数ゼロ:       setAttr ".mas0" -type "doubleArray" 0 ;
配列数:ゼロ、値:なし
(b)原点に1個:     setAttr ".mas0" -type "doubleArray" 1 1 ;
配列数:1、値: 1

(c)座標1,1,1に1個:     setAttr ".mas0" -type "doubleArray" 1 1 ;
配列数:1、値: 1

(d)原点と座標1,1,1に計2個:  setAttr ".mas0" -type "doubleArray" 2 1 1 ;
配列数:2、値: 1 と 1





<id0>
id0:これも「id」プロパティーと混同しないように要注意。
パーティクル毎のAcceleration(加速度)の初期値
id:各パーティクルのユニークなID
id0:パーティクル毎の初期ID値
(正直言うと違いがよくわからないが、ここではid0ということで)
デフォルト値:空


(a)個数ゼロ:       setAttr ".id0" -type "doubleArray" 0 ;
配列数:ゼロ、値:なし

(b)原点に1個:     setAttr ".id0" -type "doubleArray" 1 0 ;
配列数:1、値:0
(c)座標1,1,1に1個:     setAttr ".id0" -type "doubleArray" 1 0 ;
配列数:1、値:0

(d)原点と座標1,1,1に計2個:  setAttr ".id0" -type "doubleArray" 2 0 1 ;
配列数:2、値:0 と 1



<nid>
nid:「nextID」 次に利用可能なID
デフォルト値:0(ゼロ)
これは配列ではないので値だけ。

(a)個数ゼロ:       該当しない
値:    該当しない

(b)原点に1個:     setAttr ".nid" 1;
値:1

(c)座標1,1,1に1個:     setAttr ".nid" 1;
値:1

(d)原点と座標1,1,1に計2個:  setAttr ".nid" 2;
値:2




<nid0>
NextID(nid)の初期値
デフォルト値:0(ゼロ)
これも配列ではないので値のみ

(a)個数ゼロ:       該当しない
値:    該当しない

(b)原点に1個:     setAttr ".nid" 1;
値:1

(c)座標1,1,1に1個:     setAttr ".nid" 1;
値:1

(d)原点と座標1,1,1に計2個:  setAttr ".nid" 2;
値:2


最初のフレームでパーティクルの数がすでに決定している場合、
当然ながら<nid>と<nid0>は同じ値をとると思われる。



<bt0>
bt0:「birthTime0」
パーティクル毎のバースタイム(発生時間)の初期値。
デフォルト値:空

(a)個数ゼロ:       setAttr ".bt0" -type "doubleArray" 0 ;
配列数:ゼロ、値:なし

(b)原点に1個:     setAttr ".bt0" -type "doubleArray" 1 0.041666666666666664 ;
配列数:1、値:0.041666666666666664

(c)座標1,1,1に1個:     setAttr ".bt0" -type "doubleArray" 1 0.041666666666666664 ;
配列数:1、値:0.041666666666666664

(d)原点と座標1,1,1に計2個: setAttr ".bt0" -type "doubleArray" 2 0.041666666666666664 0.041666666666666664 ;
配列数:2、値:0.041666666666666664 と 0.041666666666666664

そのパーティクルの発生時間の初期値
この長い小数点数はどこから来たかというと、フレームを秒数表示した物。
今回は24fpsで作成したシーンなので、
1(秒)÷24(フレーム)=0.041666666666666664
すなわち1フレーム目で発生していることを示している。



<ag0>
ag0:「age0」
パーティクル毎の年齢、初期値

デフォルト値:空

(a)個数ゼロ:       setAttr ".ag0" -type "doubleArray" 0 ;
配列数:ゼロ、値:なし

(b)原点に1個:     setAttr ".ag0" -type "doubleArray" 1 0 ;
配列数:1、値:0

(c)座標1,1,1に1個:     setAttr ".ag0" -type "doubleArray" 1 0 ;
配列数:1、値:0
(d)原点と座標1,1,1に計2個: setAttr ".ag0" -type "doubleArray" 2 0 0 ;
配列数:2、値:0 と 0

このケースの値は、いずれもパーティクル発生時「0歳」に設定されている。

setAttr ".lifespanPP0" -type "doubleArray" 2 3.4028234663852886e+038




<lifespanPP0>
なぜかヘルプにはのってない。
これは「0」部分を除きカスタムアトリビュートと同じ名前であるが...別にカスタムアトリビュートになにか設定するわけではないし、アトリビュートエディター内のlifespanPPの所に何も表示されていない。

ヘルプの「パーティクル アトリビュートのリスト」によると以下のような説明である。
「lifespanPP:パーティクルが消滅するときをパーティクル単位で設定します。」


アトリビュート名の後ろに0があるケースはそれが初期値であることを示す。
よって「lifespanPP0」は寿命の初期値であるというのは想像がつく。


ブログ「memlog」さんによると、
「lifespanPP [寿命]
各パーティクルの寿命。
例えばlifespanPP = 1とすると、1秒後に消滅する。
おそらく、age > lifespanPPとなった瞬間に、消滅するのだと思われる。
この値をゼロにすることで、パーティクルを任意のタイミングで消滅させることが可能」



シーンファイルの設定はデフォルトのままなのでMayaのGUIからアトリビュートエディターの設定を見るとLifeSpanの設定は以下の通りである。
LifeSpan:Live Forever
この状態での各シーンの設定は以下のようになっている。

(a)個数ゼロ:       setAttr ".lifespanPP0" -type "doubleArray" 0 ;
配列数:ゼロ、値:なし

(b)原点に1個:     setAttr ".lifespanPP0" -type "doubleArray" 1 3.4028234663852886e+038 ;
配列数:1、値:3.4028234663852886e+038

(c)座標1,1,1に1個:     setAttr ".lifespanPP0" -type "doubleArray" 1 3.4028234663852886e+038 ;
配列数:1、値:3.4028234663852886e+038

(d)原点と座標1,1,1に計2個: setAttr ".lifespanPP0" -type "doubleArray" 2 3.4028234663852886e+038 3.4028234663852886e+038 ;
配列数:2、値:3.4028234663852886e+038 と 3.4028234663852886e+038


ためしに
LifeSpan Mode: Constant
LifeSpan:1

で設定したがこれら値は変化無し。

アトリビュートエディターのLifespanPPに以下のエクスプレッションを設定してみた
CreateExpression:particleShape1.lifespanPP = 0.1;
しかし、上記のsetAttrの値に変化は無かった。


名前からするとパーティクル毎の寿命の初期値であることは間違いないのだが。

これは@honeking さんとのTwitterでのやりとりで解明した。

まず、ヘルプの「finalLifespanPP(flp)」には以下のように書かれている。
「finalLifespanPP(flp)はlifespanPPの値をコピーして利用する。
LifeSpanモードが「None」の時は、フロート最大値が使われる」




上記のアスキーファイル内にある「3.4028234663852886e+038」という数字は、実はフロート値の最大値なのである。
参照サイト:「変数の扱える最大値の周辺」
「3.40282347e38 が float の最大値である。」

ヘルプを見ても「finalLifespanPP0(注意:初期値を示す「0」が後尾にあり)」というのは存在しない
LifeSpanモードが「None」の時の値をどこからか持ってくる必要がある。
そしておそらくその為の値「floatの最大値」を格納する場所が「lifespanPP0」なのだと思われる。
ようするにデフォルトの「Live Forever」の値は、ここからとってきていると考えることが出来る。

これは実際の数としてはかなり巨大な数なので、実質、永久に存在していると考えて間違いないだろう。そもそもMayaのタイムレンジをそこまで設定できるのかどうかもわからないし、そこまでの長尺のショットなどあり得ないだろう。
ようするにこれはこれで有効なのだ。


スクリプトエディターで「Echo AllCommand」にして観察しながら、アトリビュートエディターでLife Foreverモードにすると
setAttr "particleShape1.lifespanMode" 0;
が実行されていることがわかる。
ヘルプでは「None」と書いているが「0(ゼロ)」の事だと思われる。



------------------
<イニシャルステートを使わない、パーティクルの追加方法>
以上の分析からパーティクルを追加してかつそれを初期値として保存するためには以下のような
Melでアトリビュート値を設定する事になる。

以下はパーティクルを追加する場合に変更する必要がある場所:
(参考スクリプトは今回作成したアスキーファイルより引用)

setAttr ".pos0" -type "vectorArray" 1 0 0 0 ;

ポジション: 配列数、値(座標値xyz = 任意)
setAttr ".vel0" -type "vectorArray" 1 0 0 0 ;
速度: 配列数、値(速度値xyz = 0 0 0)

setAttr ".acc0" -type "vectorArray" 1 0 0 0 ;
加速度: 配列数、値(加速度値xyz = 0 0 0)

setAttr ".mas0" -type "doubleArray" 1 1 ;
質量: 配列数、値(質量=1)

setAttr ".id0" -type "doubleArray" 1 0 ;
ID: 配列数、値(ID、ゼロから始まり配列数が2以上だと 1 2 3 ・・・と増加する)

setAttr ".nid" 1;
NextID: 値(id0の最後の値の次の数、基本的に他の配列「数」と同じになるはず)

setAttr ".nid0" 1;
NextID: 値(nidと同じ)

setAttr ".bt0" -type "doubleArray" 1 0.041666666666666664 ;
バースタイム: 配列数、値(フレーム1からの場合 0.041666666666666664 )

setAttr ".ag0" -type "doubleArray" 1 0 ;
Age(年齢): 配列数、値(発生時の年齢:0)

setAttr ".lifespanPP0" -type "doubleArray" 1 3.4028234663852886e+038 ;
寿命初期値: 配列数、値(最大値 3.4028234663852886e+038)




これを参考に実際に行うためのスクリプトを作ってみる。
1)空のパーティクルShapeを作成
particle; 

2)setAttrを使い1,1,1の場所に一つのパーティクルを作成。

setAttr ".pos0" -type "vectorArray" 1 1 1 1 ;
setAttr ".vel0" -type "vectorArray" 1 0 0 0 ;
setAttr ".acc0" -type "vectorArray" 1 0 0 0 ;
setAttr ".mas0" -type "doubleArray" 1 1 ;
setAttr ".id0" -type "doubleArray" 1 0 ;
setAttr ".nid" 1;
setAttr ".nid0" 1;
setAttr ".bt0" -type "doubleArray" 1 0.041666666666666664 ;
setAttr ".ag0" -type "doubleArray" 1 0 ;
setAttr ".lifespanPP0" -type "doubleArray" 1 3.4028234663852886e+038 ;



これでパーティクルが一つ追加される。
(パーティクルが表示されない場合は、タイムスライダーを動かし、初期フレームに戻る必要がある。)


ではさらに2,2,2の位置にもう一つ追加してみる。
追加と書くと新しいパーティクル1つの情報だけをスクリプトで実行するようなイメージを持ってしまうが、 実際には既存のパーティクル、今回追加するパーティクルの両方をsetAttrで設定する必要がある。
簡単に言えば、二つのパーティクルを設定するためのsetAttrで各アトリビュートを上書きする事になる。


3)setAttrを使い1,1,1 2,2,2の場所に2つのパーティクルを作成。

setAttr ".pos0" -type "vectorArray" 2 1 1 1 2 2 2 ;
setAttr ".vel0" -type "vectorArray" 2 0 0 0 0 0 0;
setAttr ".acc0" -type "vectorArray" 2 0 0 0 0 0 0 ;
setAttr ".mas0" -type "doubleArray" 2 1 1 ;
setAttr ".id0" -type "doubleArray" 2 0 1 ;
setAttr ".nid" 2;
setAttr ".nid0" 2;
setAttr ".bt0" -type "doubleArray" 2 0.041666666666666664 0.041666666666666664;
setAttr ".ag0" -type "doubleArray" 2 0 0 ;
setAttr ".lifespanPP0" -type "doubleArray" 2 3.4028234663852886e+038 3.4028234663852886e+038;



これで二つパーティクルが追加された。

ーーーーーーーーーー

<勘違いに気がついた>
アスキーファイルでパーティクルがどのように記述されているのかがわかったので、
Emitでパーティクルを一つ追加しInitalStateで保存した場合のアスキーファイルも比較してみることにした。

createNode particle -n "particleShape1" -p "particle1";
    addAttr -ci true -sn "lifespanPP" -ln "lifespanPP" -dt "doubleArray";
    addAttr -ci true -h true -sn "lifespanPP0" -ln "lifespanPP0" -dt "doubleArray";
    addAttr -ci true -sn "lifespan" -ln "lifespan" -at "double";
    setAttr -k off ".v";
    setAttr ".gf" -type "Int32Array" 0 ;
    setAttr ".pos0" -type "vectorArray" 1 0 0 0 ;
    setAttr ".vel0" -type "vectorArray" 1 0 0 0 ;
    setAttr ".acc0" -type "vectorArray" 1 0 0 0 ;
    setAttr ".usc" yes;
    setAttr ".scp" -type "string" "particleEmit_startup";
    setAttr ".mas0" -type "doubleArray" 1 1 ;
    setAttr ".id0" -type "doubleArray" 1 0 ;
    setAttr ".nid" 1;
    setAttr ".nid0" 1;
    setAttr ".bt0" -type "doubleArray" 1 0.041666666666666664 ;
    setAttr ".ag0" -type "doubleArray" 1 0 ;
    setAttr ".irbx" -type "string" "";
    setAttr ".irax" -type "string" "";
    setAttr ".icx" -type "string" "";
    setAttr ".cts" 1;
    setAttr ".lifespanPP0" -type "doubleArray" 1 3.4028234663852886e+038 ;
    setAttr -k on ".lifespan" 1;



これを見ると、自分がsetAttrのスクリプトを使って設定したのと同じ結果になっているということがわかる。

ようするにInitalStateを使うということはsetAttrでちゃんと初期値を設定しているということであった。
各アトリビュートを設定する必要は無かったと言うことだ。
InitialStateを使うとキャッシュのように別ファイルとして保存されるというのは全くの思い違いで幻想であった。


メニューからInitalStateをクリックすると「saveInitialState」コマンドが実行され、
SaveInitialStateはアトリビュートの設定きちんと上書き保存している。
そしてファイルにはきちんと記述として残る。


------------
これで一度、パーティクルをシーンに作成、追加する方法の基本は終わりとします。
パーティクルを増やすにはEmitterで行うのが一般的ですが、それはまたいろいろなテクがあるし、そればっかりやってもつまらないので、それらは適宜必要なときにやってみることにします。

あと以下にこれまでの「パーティクル101」へのリンクと
今回使用したアスキーファイルの画像ファイルを添付しておきます。
 この「パーティクル101」シリーズは、自分が充分に知っていることを初心者にわかりやすく書いた物ではありません。
自分が知らないことが多すぎるので初心者に立ち戻り、知っていること知らないことを明確にしながら知らないところがわかるように、調べ、それで「わかったこと」、「調査過程」を他の人にも(できるだけ)わかりやすいようにまとめただけです。

---------------
これまでの「パーティクル101」シリーズ 
その1:パーティクルの作成
その2:アスキーファイルの分析
その3:saveInitialState無しで追加したパーティクルを保存する(1)


 今回使用したアスキーファイルからの抜粋。
  (a)ゼロ




(b)1個(原点)
 



(c)1個(座標1,1,1)
 


(d)二個(原点と座標1,1,1の位置)