これで OBJ A のウェイトを OBJ B にコピーすることが出来ます。
しかし、OBJ B のウェイトは必ず OBJ A の骨(デフォーマー)を使ってしまいます。
これはこれで便利な時もありますが、同じ骨構造の違うキャラクターにウェイトコピーしたい場合は不便です。
OBJ B に Gatorでウェイトコピーして、OBJ Bのウェイトを保存して、
OBJ の エンベロープを削除して、もう一度自分の骨にエンベロープしなおします。
そして、エンベロープを掛けた後に保存したウェイトを読み込みます。
これで完了。
これは何体のプロジェクトがある時には言うまでもなく、面倒くせぇ・・・。
他に便利なやり方がありますでしょうか?
あったら教えて下さい ! 是非 ! お願いします !
Mayaのコピーウェイトは確かに、ウェイトが入ったままでウェイト情報をコピーすることが出来ますね。
Gatorほどパワフルではないけど、この場合にはGatorより便利です。
最近SIのプロジェクトが多くてMayaは全く触っていないな・・・。
なんでしたっけ、
あっ、はい、Gatorだな
Gatorのこのやり方しか分からないから、スクリプトですることにしました。
メインコードはGatorのログを使うので初心者でも出来るレベルのスクリプトだと思いますが、
ちょっと参考になるから書いておきます。
それに、エンベロープオペレーターからウェイトプロパティーの取得方法を見つけたからメモっておきます。
実はイマイチよく分からないんですけど、こんな感じです:
var oObj = selection(0)
var oEnv = oObj.envelopes(0)
var EnvCls = oEnv.PortAt( 3, 0, 0).Target2
var EnvProp = oEnv.PortAt( 4, 0, 0).Target2
そう。それだけです。
これで EnvCls = エンベロープクラスター
と EnvProp = ウェイトプロパティー
は取得が出来ました。
この書き込みから覚えたやり方です
http://www.the-area.com/forum/autodesk-softimage/xsi-sdk/trouble-with-saving-out-weights/page-last/
良く分からないからまた今度ゆっくりマニュアルを読んでみます。
では、Copy Weights のスクリプトです。
このスクリプトは2つの大きなファンクションに分かれています。
① CopyWeights : コピーウェイト(Gatorと全く同じ)
② ReEnvelope : エンベロープし直して、ウェイトを読み込み。
① CopyWeights だけが必要な場合「ReEnvelope」の前に // を入れるだけで済むからこの書き方にしてみました。
/*
mCopyWeights2
--------------
Copy Weights through Gator
Bones have to have the same name to work
*/
// ポリメッシュだけをとっておきましょう。
var oSel = SIFilter(selection, siPolyMeshFilter);
// 条件:「ソースにエンベロープがある・ポリゴンメッシュオブジェクトの数は2個」
if (oSel != null && oSel.Count ==2 && oSel(1).envelopes.Count == 1){
// ウェイトをコピーするファンクションを実行
CopyWeights(oSel);
// ここまではウェイトコピーされたけど、コピー元の骨のエンベロープになっています。
// 必要であれば好きな骨にエンベロープをし直して、さっきのウェイトを使います。
// 骨は同名という前提で動くファンクションです:
ReEnvelope(oSel(0));
}
else{
logmessage ("コピー先のポリゴンメッシュオブジェクト と コピー元ポリゴンメッシュオブジェクト を選択して下さい", siError)
}
//============================================
// ウェイトをコピーするファンクション
//--------------------------------------------
function CopyWeights(oSel){
// まずは変数を設定します。
// oObj = 最初に選択されたオブジェクト(コピー先)
// oSource = 最後に選択されたオブジェクト(コピー元)
var oObj = oSel(0)
var oSource = oSel(1)
// コピー先にエンベロープがあると、コピーが出来ないので、
// エンベロープが見つかったら削除しておこう
if (oObj.envelopes.count !=0) deleteobj(oObj.envelopes)
// Gatorでエンベロープをコピーして、Gatorのオペレーターをフリーズ
var GatOp = ApplyGenOp("Gator", "", oObj +";"+ oSource, 3, siPersistentOperation, siKeepGenOpInputs, null);
CopyAnimationAcrossGenerator(oObj + ".polymsh.TransferAttributes", 0, null);
FreezeObj(GatOp);
logmessage ("Envelope Copied : [" + oSource + "] --> [" + oObj +"]")
}
//============================================
// エンベロープをし直すファンクション
//--------------------------------------------
function ReEnvelope(oObj){
// oObj = コピー先。最初に選択されたオブジェクト 。
// プロジェクトフォルダを弄りたくないから、XSIのテンポラルフォルダを取得
var TempPath = XSIUtils.Environment("TEMP");
// ファイルの名前とパスを設定しておこう。
var TempPathPreset = TempPath + "\\" + oObj.name + ".Preset"
// ウェイト情報をプリセットファイルに保存する(テンポラルフォルダ)
SavePreset (oObj.envelopes(0).PortAt( 4, 0, 0 ).Target2, TempPath + "\\" + oObj.name + ".Preset");
// エンベロープを削除
deleteobj(oObj.envelopes)
// エンベロープを削除してもポイントクラスタが残ってしまうので、消しておこう。
var pntcls = selection(0).activeprimitive.geometry.clusters.filter("pnt")
if (pntcls.count > 0){
// エンベロープと関係ないポイントクラスタがあるかもしれないので、
// 消したい奴だけを探る必要があります。ポイントクラスタをループしましょう。
for ( var i=0, a = pntcls.Count; i < a; i++ ) {
// エンベロープクラスタは今タダのポイントクラスタなので見分ける方法がありません。
// 普通は「EnvelopWeightCls」という名前になっているはずなので、
// 「EnvelopWeight」から始まったら削除しよう。
if(pntcls(i).name.substring(0,13) == "EnvelopWeight") DeleteObj(pntcls(i))
// もし違う名前だったら・・・諦めるしか無い。
}
}
// 新しくエンベロープし直す。
// でもどの骨にエンベロープするのか判断できないので、ユーザーに決めてもらうように
// ピックカソル選択にしましょう:
logmessage ("エンベロープ のデフォーマー を選択して下さい", siWarning)
var rtn = PickElement( null, "Pick Bone", "Pick Bones Branch to Envelope", null, button, 0 )
var element = rtn.Value( "PickedElement" ); // これで選択された骨を取得する
var button = rtn.Value( "ButtonPressed" ); // これはただキャンセルされたかどうかが分かる為
// ピックはキャンセルされていないければ button は 0 じゃない なので、
// キャンセルしてないければ次に進もう:
if (button !=0){
// Expand() でブランチ選択された全オブジェクトをとっておこう
var oCol = XSIFactory.CreateObject('XSI.Collection');
oCol.unique = true; oCol.items = element;
var oBones = oCol.Expand();
// oObj を さっきのブランチ選択に エンベロープ を掛けましょう。
ApplyFlexEnv(oObj +";"+ oBones, null, 2)
// 最後に保存していたウェイトを読み込んで
// ここは保存した「プリセット」を「ウェイトクラスタ」にぶち込む
// デフォルトの名前になっているはずなので、クラスタ名だけで上手く行きます:
SILoadPreset( TempPath + "\\" + oObj.name + ".Preset" , oObj.envelopes(0).PortAt( 4, 0, 0 ).Target2 );
}
// FSOメソッドでウェイトのファイルを削除。一応ね。
var FSO = new ActiveXObject( "Scripting.FileSystemObject" );
FSO.DeleteFile (TempPathPreset)
}
因みにですね、ブログの解析ツールを見てたらどうやら2ちゃんから来てくださった方もいたので、2ちゃんスレッドを除いてみました。なんと、俺に対しての批判的な書き込みもありましたw
名乗らずに悪口書くのは簡単だからこの程度のクズは相手にするつもりないけどちょっと驚きましたね、さすがに。
暇でしょうけど、知らない人の悪口を書くより他にやることないのかな?
多分同じ人だと思うけど、Mayaに非破壊は要らない。皆優秀で形状を完璧に出来てからウェイトを入れるみたいなことを言ってたけど、これはちょっと笑っちゃいました。この人は本当にCGの仕事をしてるのかな?
まぁ、どうでも良いけど。
明日は多分Diablo3のサーバーはきっとまたメンテナンスになるので、今日やるしかないけど、もう飽きちゃいました。
Skyrimをやる気も出ないけど、頑張ってクリアしようかな~。
とりあず、今日は寝る。
おやすみなさい!