« 対象複製同時名前健作痴漢。 | トップページ | 俺を縛り付けているのはいったい誰だ。 »

2011年8月26日 (金)

女~るFcurve。

とりあえずバージョン1なんですが。





var oP = XSIFactory.CreateObject( "CustomProperty" );
oP.name = "女~るFcurve";
oP.AddParameter2( "iTimeScalePivotMode", siInt4, 1 );
oP.AddParameter2( "dTimeScalePivot", siDouble, 1 );
oP.AddParameter2( "dTimeScaleFactor", siDouble, 1 );
oP.AddParameter2( "iValueScalePivotMode", siInt4, 2 );
oP.AddParameter2( "dValueScalePivot", siDouble, 0 );
oP.AddParameter2( "dValueScaleFactor", siDouble, 1 );

var oL, oItem;
oL = oP.PPGLayout;
oItem = oL.AddButton( "Reset", "R   e   s   e   t" );
oItem.SetAttribute( siUICX, 310 );
oItem.SetAttribute( siUICY, 16 );

oL.AddRow();
    oL.AddGroup( "Time Scale" );
        var aArray = Array( "First key", 1, "Mid key", 2, "Last key", 3, "Specify pivot frame", 4 );
        oItem = oL.AddEnumControl( "iTimeScalePivotMode", aArray, "Time Pivot", siControlCombo );
        oItem = oL.AddItem( "dTimeScalePivot", "Pivot Frame" );
        oItem = oL.AddItem( "dTimeScaleFactor", "Time Scale" );
        oItem = oL.AddButton( "DoTimeScale", "時間女~る" );
        oItem.SetAttribute( siUICX, 0 );
    oL.EndGroup();
    oL.AddGroup( "Value Scale" );
        var aArray = Array( "Max value", 1, "Mid value", 2, "Min value", 3, "Specify pivot value", 4 );
        oItem = oL.AddEnumControl( "iValueScalePivotMode", aArray, "Value Pivot", siControlCombo );
        oItem = oL.AddItem( "dValueScalePivot", "Pivot Value" );
        oItem = oL.AddItem( "dValueScaleFactor", "Value Scale" );
        oItem = oL.AddButton( "DoValueScale", "値女~る" );
        oItem.SetAttribute( siUICX, 0 );
    oL.EndGroup();
oL.EndRow();

oL.Language = "JScript";
oL.Logic =    OnInit.toString()+
            iTimeScalePivotMode_OnChanged.toString()+
            iValueScalePivotMode_OnChanged.toString()+
            DoTimeScale_OnClicked.toString()+
            DoValueScale_OnClicked.toString()+
            Reset_OnClicked.toString();

function OnInit()
{
    iTimeScalePivotMode_OnChanged();
    iValueScalePivotMode_OnChanged();

}
function iTimeScalePivotMode_OnChanged()
{
    if ( PPG.iTimeScalePivotMode.value == 4 )
    {
        PPG.dTimeScalePivot.Readonly = false;
    }
    else
    {
        PPG.dTimeScalePivot.Readonly = true;
    }
}
function iValueScalePivotMode_OnChanged()
{
    if ( PPG.iValueScalePivotMode.value == 4 )
    {
        PPG.dValueScalePivot.Readonly = false;
    }
    else
    {
        PPG.dValueScalePivot.Readonly = true;
    }
}

function DoTimeScale_OnClicked()
{
    var oFcurves = FcurveSelection;   
//    現在選ばれているFカーブを取得
    if ( oFcurves.count != 0 )
    {   
        for ( var i=0; i<oFcurves.count; i++ )
        {
            var oFcurve = oFcurves(i);

            if ( PPG.iTimeScalePivotMode == 1 )
            {
                ScalePivotFrame = oFcurve.GetMinKeyFrame();
//最初のキーがピボット
            }
            else if ( PPG.iTimeScalePivotMode == 2 )
            {
                ScalePivotFrame = oFcurve.GetMidKeyFrame();
//真ん中のキーがピボット
            }
            else if ( PPG.iTimeScalePivotMode == 3 )
            {
                ScalePivotFrame = oFcurve.GetMaxKeyFrame();
//最後のキーがピボット
            }
            else if ( PPG.iTimeScalePivotMode == 4 )
            {
                ScalePivotFrame = PPG.dTimeScalePivot.value;
//指定したフレームがピボット
            }

    //    Fカーブスケールを実行
            oFcurve.BeginEdit();
            oFcurve.Scale( PPG.dTimeScaleFactor.value, 1, ScalePivotFrame, null );
            oFcurve.EndEdit();
        }
    }
    else
    {
        Logmessage( "No fuckin Fcurves selected.", siError );
    }
}

function DoValueScale_OnClicked()
{
    var oFcurves = FcurveSelection;
    if ( oFcurves.count != 0 )
    {   
        for ( var i=0; i<oFcurves.count; i++ )
        {
            var oFcurve = oFcurves(i);

            if ( PPG.iValueScalePivotMode == 1 )
            {
                ScalePivotValue = oFcurve.GetMaxKeyValue();
//最大値キーがピボット
            }
            else if ( PPG.iValueScalePivotMode == 2 )
            {
                ScalePivotValue = oFcurve.GetMidKeyValue();/
/真ん中キーがピボット
            }
            else if ( PPG.iValueScalePivotMode == 3 )
            {
                ScalePivotValue = oFcurve.GetMinKeyValue();
//最小値キーがピボット
            }
            else if ( PPG.iValueScalePivotMode == 4 )
            {
                ScalePivotValue = PPG.dValueScalePivot.value;
//指定した値がピボット
            }

            oFcurve.BeginEdit();
            oFcurve.Scale( 1, PPG.dValueScaleFactor.value, null, ScalePivotValue );   
            oFcurve.EndEdit();
        }
    }
    else
    {
        Logmessage( "No fuckin Fcurves selected.", siError );
    }
}

function Reset_OnClicked()
{
    PPG.dTimeScaleFactor.value = 1;
    PPG.dValueScaleFactor.value = 1;
}

InspectObj( oP, null, null, siLock );





Fカーブをスケールするツールです。

Scalefcurve

数値を入力してスケールしたいとか、ひとつの基点ではなくFカーブそれぞれの中間値を基点にスケールしたいとか、そういうことをするために書いてみたんですがね。


実行すると PPG が現れます。
いくつでもいいのでFカーブを選択します。
時間スケール、値スケールの基点やスケール値を決めて、ボタンを押します。
するとFカーブにスケールがかかります。

基点にグローバルな値、つまり全てのFカーブに共通のひとつの基点を与えたい時は、ドロップダウンメニューで Specify を選ぶと、グレー表示だった部分が入力できるようになって、任意の値を決められます。

これ以外のモードでは、各Fカーブから値をゲットします。 サイクル周期や、値変動のレンジが全然違う複数のFカーブに対して、それぞれのFカーブの基点でスケールすることがそもそものこのツールの目的でした。





問題はですね、
自動でアップデートされないのですよ。
つまり、実行後、画面は何も変化がないように見えるのです。
ビューポート上のオブジェクトはそのまんま。
Fカーブエディタ上のFカーブもそのまんま。


次のフレームに移動するなど、刺激を与えてやればビューポートはリフレッシュされます。 Fカーブは、Fカーブエディタのアップデートボタンを押せば、ちゃんと実行後の状態が反映されて表示されます。


自動じゃないのが気に食わないですね。
どうやったらいいのかわかりません。
Fカーブに変更を与えた後に、Refresh や SceneRefresh を実行するようなスクリプトにしてみても、アップデートされせんでした。 現状、上記のように、手で刺激を与えてやるしかない。


ということで、どなたか教えて下さい。スクリプトからFカーブをいじった後、ビューポートやFカーブエディタが自動で変更後の状態にリフレッシュされる方法をご存知のお方、教えて下さい。




.ではごきげんよう。




.

|

« 対象複製同時名前健作痴漢。 | トップページ | 俺を縛り付けているのはいったい誰だ。 »

コメント

手動で可能ならスクリプトにすればおk
ので、OnClickedの最後に

var current_frame = GetValue("PlayControl.Current");
SetValue("PlayControl.Current", GetValue("PlayControl.Out"));
SetValue("PlayControl.Current", current_frame);

とすればアップデートされますね。
なにか釈然としませんが…

投稿: anamorph | 2011年8月26日 (金) 23時13分

どうもどうも、いつもお世話になります。

あれ? それでアップデートできましたか?
NextFrame();
PrevFrame();
ってのは試したんですよ。手動で1フレ進めて戻す、というのでアップデートできていたのでそれをスクリプトで書いたという。そしたらアップデートされないんですよ。手動ではできたのに、同じことをスクリプトからやると、シカトされてしまう。

最後のフレームに飛んで戻す、なら大丈夫ということですかね?
ううむ、釈然としませんねえ。。。。

投稿: junki | 2011年8月27日 (土) 00時01分

女をスケと読ますなんて流石ですね。昭和の男って感じです。
自分ゆとりなんで、最初何て読むのかわからなかったです。

投稿: ika336 | 2011年8月27日 (土) 00時51分

こちらこそたくさんお世話になってます。ありがとうございます

おそらくSetValueで現フレームを飛ばしてるというのが重要なんだと思います。

SetValue("PlayControl.Current", current_frame + 1.0);
SetValue("PlayControl.Current", current_frame - 1.0);

みたいなのでも反映されるようなので。以前ぼくも悩んでぐちゃぐちゃ書いた覚えがあります。
こういうのは util.ForceUpdate() とかなまえつけておくと後でバージョン変わって挙動変わった時とかに対応しやすいですね

投稿: anamorph | 2011年8月27日 (土) 01時01分

こんばんは。
お久しぶりです。
モチオです。

今回の件、自分もFカーブをいじくりまわすプラグインとか作ってて
そんな現象に遭遇したことがなかったので気になって調べてみました。
結論から言うと、どうやら oFcurve.Scale()のバグのようです。

var desktop = Application.Desktop;
desktop.RedrawUI();

とかでSI自体描画しなおせばなるかと思いきや、やっぱなおりませんでした。
相変わらずのSIのアホっぷりにイラっとしたので、
oFcurve.Scale()とほぼ同じ挙動をする関数を作ってみました。

********************************************************************************

//オリジナルFカーブスケール関数
//引数の最初がFカーブオブジェクトなだけでFCurve.Scale()と使い方はほぼ一緒
function OriginalFcurveScale(in_FcSource, in_FrameFactor, in_ValueFactor, in_FrameAnchor, in_ValueAnchor){

//引数が省略された場合
if(in_FrameFactor == null)in_FrameFactor = 1;
if(in_ValueFactor == null)in_ValueFactor = 1;
if(in_FrameAnchor == null)in_FrameAnchor = 1;
if(in_ValueAnchor == null)in_ValueAnchor = 1;

var EditFr_Array = new Array();

//各ピボット・スケール値でキーフレームを再計算
for(var h = 0; h < in_FcSource.keys.count; h++){
EditFr_Array.push((in_FcSource.keys(h).time - in_FrameAnchor) * in_FrameFactor + in_FrameAnchor);
EditFr_Array.push((in_FcSource.keys(h).value - in_ValueAnchor) * in_ValueFactor + in_ValueAnchor);
}

//作った配列を使って一斉にキー追加
in_FcSource.BeginEdit();
in_FcSource.SetKeys(EditFr_Array);
in_FcSource.EndEdit();

return;
}

********************************************************************************

で、これをjunkiさんのに組み込んでみたのが↓です。
(必要ないかもしれませんが…)

********************************************************************************

var oP = XSIFactory.CreateObject( "CustomProperty" );
oP.name = "女~るFcurve";
oP.AddParameter2( "iTimeScalePivotMode", siInt4, 1 );
oP.AddParameter2( "dTimeScalePivot", siDouble, 1 );
oP.AddParameter2( "dTimeScaleFactor", siDouble, 1 );
oP.AddParameter2( "iValueScalePivotMode", siInt4, 2 );
oP.AddParameter2( "dValueScalePivot", siDouble, 0 );
oP.AddParameter2( "dValueScaleFactor", siDouble, 1 );

var oL, oItem;
oL = oP.PPGLayout;
oItem = oL.AddButton( "Reset", "R e s e t" );
oItem.SetAttribute( siUICX, 310 );
oItem.SetAttribute( siUICY, 16 );

oL.AddRow();
oL.AddGroup( "Time Scale" );
var aArray = Array( "First key", 1, "Mid key", 2, "Last key", 3, "Specify pivot frame", 4 );
oItem = oL.AddEnumControl( "iTimeScalePivotMode", aArray, "Time Pivot", siControlCombo );
oItem = oL.AddItem( "dTimeScalePivot", "Pivot Frame" );
oItem = oL.AddItem( "dTimeScaleFactor", "Time Scale" );
oItem = oL.AddButton( "DoTimeScale", "時間女~る" );
oItem.SetAttribute( siUICX, 0 );
oL.EndGroup();
oL.AddGroup( "Value Scale" );
var aArray = Array( "Max value", 1, "Mid value", 2, "Min value", 3, "Specify pivot value", 4 );
oItem = oL.AddEnumControl( "iValueScalePivotMode", aArray, "Value Pivot", siControlCombo );
oItem = oL.AddItem( "dValueScalePivot", "Pivot Value" );
oItem = oL.AddItem( "dValueScaleFactor", "Value Scale" );
oItem = oL.AddButton( "DoValueScale", "値女~る" );
oItem.SetAttribute( siUICX, 0 );
oL.EndGroup();
oL.EndRow();

oL.Language = "JScript";
oL.Logic = OnInit.toString()+
iTimeScalePivotMode_OnChanged.toString()+
iValueScalePivotMode_OnChanged.toString()+
DoTimeScale_OnClicked.toString()+
DoValueScale_OnClicked.toString()+
OriginalFcurveScale.toString()+
Reset_OnClicked.toString();

function OnInit()
{
iTimeScalePivotMode_OnChanged();
iValueScalePivotMode_OnChanged();

}
function iTimeScalePivotMode_OnChanged()
{
if ( PPG.iTimeScalePivotMode.value == 4 )
{
PPG.dTimeScalePivot.Readonly = false;
}
else
{
PPG.dTimeScalePivot.Readonly = true;
}
}
function iValueScalePivotMode_OnChanged()
{
if ( PPG.iValueScalePivotMode.value == 4 )
{
PPG.dValueScalePivot.Readonly = false;
}
else
{
PPG.dValueScalePivot.Readonly = true;
}
}

function DoTimeScale_OnClicked()
{
var oFcurves = FcurveSelection; // 現在選ばれているFカーブを取得
if ( oFcurves.count != 0 )
{

for ( var i=0; i {
var oFcurve = oFcurves(i);

if ( PPG.iTimeScalePivotMode == 1 )
{
ScalePivotFrame = oFcurve.GetMinKeyFrame();//最初のキーがピボット
}
else if ( PPG.iTimeScalePivotMode == 2 )
{
ScalePivotFrame = oFcurve.GetMidKeyFrame();//真ん中のキーがピボット
}
else if ( PPG.iTimeScalePivotMode == 3 )
{
ScalePivotFrame = oFcurve.GetMaxKeyFrame();//最後のキーがピボット
}
else if ( PPG.iTimeScalePivotMode == 4 )
{
ScalePivotFrame = PPG.dTimeScalePivot.value;//指定したフレームがピボット
}

//Fカーブスケールを実行
OriginalFcurveScale(oFcurve, PPG.dTimeScaleFactor.value, 1, ScalePivotFrame, null)
}
}
else
{
Logmessage( "No fuckin Fcurves selected.", siError );
}
}

function DoValueScale_OnClicked()
{
var oFcurves = FcurveSelection;
if ( oFcurves.count != 0 )
{
for ( var i=0; i {
var oFcurve = oFcurves(i);

if ( PPG.iValueScalePivotMode == 1 )
{
ScalePivotValue = oFcurve.GetMaxKeyValue();//最大値キーがピボット
}
else if ( PPG.iValueScalePivotMode == 2 )
{
ScalePivotValue = oFcurve.GetMidKeyValue();//真ん中キーがピボット
}
else if ( PPG.iValueScalePivotMode == 3 )
{
ScalePivotValue = oFcurve.GetMinKeyValue();//最小値キーがピボット
}
else if ( PPG.iValueScalePivotMode == 4 )
{
ScalePivotValue = PPG.dValueScalePivot.value;//指定した値がピボット
}

//oFcurve.BeginEdit();
//oFcurve.Scale( 1, PPG.dValueScaleFactor.value, null, ScalePivotValue );
//oFcurve.EndEdit();

OriginalFcurveScale(oFcurve, 1, PPG.dValueScaleFactor.value, null, ScalePivotValue)
}
}
else
{
Logmessage( "No fuckin Fcurves selected.", siError );
}
}

function Reset_OnClicked()
{
PPG.dTimeScaleFactor.value = 1;
PPG.dValueScaleFactor.value = 1;
}

InspectObj( oP, null, null, siLock );


//オリジナルFカーブスケール関数
//引数の最初がFカーブオブジェクトなだけでFCurve.Scale()と使い方はほぼ一緒
function OriginalFcurveScale(in_FcSource, in_FrameFactor, in_ValueFactor, in_FrameAnchor, in_ValueAnchor){

//引数が省略された場合
if(in_FrameFactor == null)in_FrameFactor = 1;
if(in_ValueFactor == null)in_ValueFactor = 1;
if(in_FrameAnchor == null)in_FrameAnchor = 1;
if(in_ValueAnchor == null)in_ValueAnchor = 1;

var EditFr_Array = new Array();

//各ピボット・スケール値でキーフレームを再計算
for(var h = 0; h < in_FcSource.keys.count; h++){
EditFr_Array.push((in_FcSource.keys(h).time - in_FrameAnchor) * in_FrameFactor + in_FrameAnchor);
EditFr_Array.push((in_FcSource.keys(h).value - in_ValueAnchor) * in_ValueFactor + in_ValueAnchor);
}

//作った配列を使って一斉にキー追加
in_FcSource.BeginEdit();
in_FcSource.SetKeys(EditFr_Array);
in_FcSource.EndEdit();

return;
}

********************************************************************************


これでFカーブに任意のスケールがかかって、
Fカーブエディタやビューポートが更新されるのを確認しました。

自作スケール関数ですが、多分計算間違ってないとは思うんですが…。
間違っていたらすいません。

あと、コメントでは行冒頭の空白が無くなっちゃうみたいなので見づらくてすいません。

以上、長文失礼しました。

投稿: モチオ | 2011年8月27日 (土) 02時58分

ikaさんがコメント付けているからどんなスクリプトへのツッコミかと思ってgkbrしてたらそっちかいw

でも、そうだよなあ、平成というかゆとりな連中、スケなんて言い方知らないよなあ

投稿: junki | 2011年8月27日 (土) 10時21分

anamorphさん、こにゃにゃちは。 こにゃにゃちはも昭和の男しか知らない挨拶か。

はい、なるほど、SetValue であることがポイントなんでしょうな。確かに SetValue は、その薬効の中に強制更新も常に含まれている気がします。一連の処理をバッチ化するスクリプトなどで、わざわざオブジェクトモデルで目的のパラメータを取得して oParam.value = false などとやると、更新されないことがたまにあったように思うのです。例えばビューポートをある状態にして、キャプチャし、元に戻すとか、そういう処理をする時に SetValue を使わないと、スクリプト上はある状態にしているのに実際はアップデートされないままキャプチャが始まってしまい、目的の状態になる前の状態でキャプチャされてしまっているなどという現象がありました。oParam.value = xxx の代わりに SetValue を使ったら直ったんだったと思います。

なるべくコマンドを排除してオブジェクトモデルだけで書きたいんですがねえ。 まあ、そこにこだわる意味も実は薄いんですが。

投稿: junki | 2011年8月27日 (土) 10時29分

モチオさん久しぶりっスね。元気ですか。

わざわざありがとうございます! さすがモチオさんですわ。スクリプティングで問題が出ても刹那的な対策しか採らない俺とは大違いだ。

で、バグなんですか。何をどうやったらそういうバグになるのか俺はようわからんですわ。ま、驚きもしませんがね。XSIだもの。

ひとつ思っていたのが、今回は Fcurveオブジェクトの Scale メソッドを使ったわけですけど、SDKガイドを見ると、ScaleKeys っていうメソッドもあるんですね。で、違いはよくわからん。同じものに見える。 で、もし ScaleKeys の方にそのバグが無いのであればそっちを使おうかな、などと思ってみましたが、どうなんでしょう。後でやってみます。


独自関数でスケールするのはもちろんスヴァらしいのですが、おそらく後からコード読み返した時にわかり易いのは anamorph さんの解決方法で、また、「アップデートされない問題をはらんでいるから無理やりこうしているんだな」 という、バグのリマインダにもなります。なのでフレーム移動させてアップデートする方式にすると思います。そっちの方が俺らしいしw


あとは、現在 OnClicked のファンクション内でやっている処理をコマンドとして独立させることかなあ。その方が、フレーム移動の強制更新も含めた全てを1まとめにしてアンドゥリドゥができて良い気がする。 あ、今どきの XSI はアンドゥブロックとか指定できるんでしたっけ? 2012 からかな?  だとすると、アンドゥのためだけにファンクションをコマンドとして独立させる意味は薄いかな?  どうなのでしょう。

投稿: junki | 2011年8月27日 (土) 10時48分

ScaleKeysあったんですね・・・。
一応探したんですが…恥ずかしい。

前回あんだけ長文書いておいてなんですが、解決方法はanamorph さんのが良いと思います。
にわか関数化すると正確性に欠けますし(すでにタンジェントとか考慮してませんし)、
最終目的は綺麗なスクリプトを書くことや処理速度を確保することではないですしね。(必要なことですけど)
自分も最終的にはその方法取ります。 ^^;

oFcurve.Scale()のバグですが、Fカーブエディタを更新せずに変更を加えたFカーブを再度選択すると
セーブキーはそのままの位置なのに、カーブだけ更新されて、キーとカーブが分離するってすごい状態になりますね!!!
さすがSI。
実はこういうアホなところが好きなわけですがw

投稿: モチオ | 2011年8月27日 (土) 17時22分

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/217974/52573196

この記事へのトラックバック一覧です: 女~るFcurve。:

« 対象複製同時名前健作痴漢。 | トップページ | 俺を縛り付けているのはいったい誰だ。 »