アニメーションをリージョンでスケールをかけるとキーフレームが非整数型になってしまいますよね。
それじゃいじりにくいから全キーフレームを選んで「Move Keys Frames to Nearest Frame」実行すれば一番近いフレームに移動されます。
大した手間ではないけど、ワンクリックで全オブジェクトでやりたいなーと思いました。
スクリプトを書くより手動でやった方が早いんだろうけど、これからも同じ作業もあるし、なんか書きたくなりました。
手動でもそんなに手間ではないから、あんまり便利ではないかもしれないけど、もう書いちゃったんだから公開しちゃいます。
スクリプトを書く人には多少役に立つかもしれないし。
DOWNLOAD
/*-----------------------
Get Fractional Key Frames
-------------------------
2012 myara
Select Animated objects and run
It selects objects with fractional keys
If the FIX option is checked, it move their keys to the nearest frame
-------------------------*/
var oPSet = XSIFactory.CreateObject("CustomProperty");
oPSet.name = "Fractional Key Frames ";
oPSet.AddParameter2( "Fix", siBool,0);
oPSet.AddParameter2( "Sel", siBool,1);
var oLayout = oPSet.PPGLayout;
oLayout.AddGroup("",0);
var oItem = oLayout.AddItem( "Fix", "[ Fix ] Move Key to Nearest Frame" );
var oItem = oLayout.AddButton ("Run","R U N");
oItem.SetAttribute( siUICX, 315);
oItem.SetAttribute( siUICY, 50);
oLayout.EndGroup();
oLayout.Logic = Run_OnClicked.toString();
oLayout.Language = "JScript" ;
InspectObj( oPSet,null,null,3 ) ;
function Run_OnClicked()
{
//Turn off log
var prefs = Application.Preferences;
prefs.SetPreferenceValue( "scripting.cmdlog", false );
var oSel = FilterX3D(selection); oSelCount = oSel.Count
if (oSelCount > 0){
var oFracSel = XSIFactory.CreateObject( "XSI.Collection" );
if (!PPG.Fix.value){
for (var i=0; i < oSelCount ; i++){
var GetFrac = GetFractionalKeyFrame(oSel(i))
if( GetFrac != "no"){
logmessage ("["+ GetFrac +"] Fractional Key Frames Found" )
oFracSel.Add ( GetFractionalKeyFrame(oSel(i)) )
}
}
}
else {
for (var i=0; i < oSelCount ; i++){
var GetFrac = GetFractionalKeyFrame(oSel(i),"fix");
if( GetFrac != "no"){
oFracSel.Add ( GetFrac )
}
}
}
if (oFracSel.count>0){
SelectObj(oFracSel)
}
else {
Selection.clear();
logmessage ("No Fractional Key frames found")
}
}
else {
logmessage ("ERROR : Nothing Selected", siWarning)
}
function GetFractionalKeyFrame(oObj, opt)
{
var flag
var oAnimParam = XSIFactory.CreateObject( "XSI.Collection" );
oAnimParam.AddItems ( oObj.NodeAnimatedParameters( siFCurveSource ));
for (var i=0; i < oAnimParam.Count; i++){
var oFc = oAnimParam(i).Source;
for (var j=0, b = oFc.GetNumKeys(); j < b; j++){
if (mRound(oFc.GetKeyFrame(j),10)!= Math.round(oFc.GetKeyFrame(j))){
flag = "yes"
if(opt=="fix"){
oFc.SnapToNearestFrame();
flag = "fixed"
}
}
}
}
if(flag=="yes"){
return(oObj)
}
else if(flag=="fixed"){
LogMessage ("["+oObj + "] Key Frames fixed")
return(oObj)
}
else if (!flag){
return("no")
}
}
function mRound(num,digits){
dig = Math.pow(10,digits)
return Math.round(num * dig)/ dig
}
function FilterX3D(in_Objs){
//----- Get only 3D Objects
var oCol = XSIFactory.CreateObject('XSI.Collection');
oCol.unique = true;
for (var i=0, a=in_Objs.count; i < a; i++) {
if (in_Objs(i).IsClassOf(siX3DObjectID)) {
oCol.Add(in_Objs(i));
}
}
var oExp = oCol.expand();
for (var i=0, a = oExp.count; i < a; i++) {
if (oExp(i).IsClassOf(siX3DObjectID)) {
oCol.Add(oExp(i))
}
}
return oCol;
}
}
ちょっとしたスクリプト解説
「取得したフレーム数」を「そのフレーム数を丸めた数値」と比較して、
同じだったら、取得したフレームに小数点が入ってないと思いますよね。
普通はそう思うんですよね。
ところで、前にもJunkiさんのブログで読んだことがある気がするけど、フレーム数を取得する時になぜか小数点が入ってしまうこともあります。例えば50フレームではなく、49.999999... と出てしまいます。
なので、スクリプトで「取得したフレーム数」を「そのフレームを丸めた数字」と比較すると、同じのはずなのに同じじゃないという結果になってしまいます。
こんな時に取得したフレームを少し丸めれば上手く行きます。そのために Jscriptの Math.Round を使って、「mRound」っというfunctionを作っておきました:
function mRound(num,digits)
{
dig = Math.pow(10,digits)
return Math.round(num * dig)/ dig
}
digits = 小数点
これで mRound (取得したフレーム , 小数点) で 取得したフレーム数を直します。
フレームだけじゃなくて、色んなところで変な小数点が入ってしまうからこのFunctionは便利です。
追記
キーフレームやmRoundについては説明不足だったのでもう少し細かく書きます:
例えば、ヌルを作って、キーフレームをいっぱい打ってみましょう。
手動でやっても良いけど、面倒だからスクリプトでやっちゃおう。
この方がヒューマンエラーがないはずですね。
これでヌルが作られ、posxにフレーム0から150までにキーが打たれました。var test = GetPrim("Null", null, null, null);
for (var i=0; i<150; i++){
SaveKey(test + ".kine.local.posx", i, null, null, null, null, null);
}
次に、キーフレーム を そのキーフレームの丸めた数値と比較してみましょう。
よし、これでvar oObj = selection(0);
var anim = oObj.NodeAnimatedParameters( siFCurveSource );
for (var i=0; i<anim.Count; i++){
var oFc = anim(i).Source;
for (var j=0; j<oFc.GetNumKeys(); j++){
if (oFc.GetKeyFrame(j) != Math.round(oFc.GetKeyFrame(j))){
logmessage(oFc.GetKeyFrame(j))
}
}
}
「キーフレーム」 を 「整数化されたそのキーフレームの数値」 と比べ、
同じ数値じゃなかったら、そのキーフレームをログに残します。
結果は、以下の通り:
// INFO : 31
// INFO : 62
// INFO : 111
// INFO : 123
// INFO : 124
// INFO : 125
でも、ログには小数点が入っていないですね。可笑しいよね。
31 = 31 なので、出るはずがないんでしょう?
試しに、フレームの数値と、丸めた数値を両方をログに残すようにしましょう。
var oObj = selection(0);
var anim = oObj.NodeAnimatedParameters( siFCurveSource );
for (var i=0; i<anim.Count; i++){
var oFc = anim(i).Source;
for (var j=0; j<oFc.GetNumKeys(); j++){
if (oFc.GetKeyFrame(j) != Math.round(oFc.GetKeyFrame(j))){
logmessage(oFc.GetKeyFrame(j) +" = "+ Math.round(oFc.GetKeyFrame(j))
}
}
}
結果はこんなかんじ:
// INFO : 30.999999999999996 = 31
// INFO : 61.99999999999999 = 62
// INFO : 110.99999999999998 = 111
// INFO : 122.99999999999998 = 123
// INFO : 123.99999999999998 = 124
// INFO : 125.00000000000001 = 125
なんで!!
分かりません。知りません。わけわかりません。
分かったのは一つだけ。
このフレームを直しても直らないんです。(直し方が分からないだけかな?)
だから上記のスクリプトに小数点を10桁で丸めて見ました。なんで10桁?単純にヒューマンミスで10桁以降に微妙な数字が入る可能性がほぼ0だと思いますから。
上記のスクリプトは直すスクリプトだけじゃなく、チェックするためのスクリプトです。小数点が入っているキーフレームがあったら、オブジェクトを選択して、ログを残します。
なので、このmRound Functionを使わなかったら、31フレームや62フレームに小数点が入ってるというメッセージが出てしまいます。直しても出てしまいます。