悲しみのローカルシンメトリ弐。
大きなあの人が書いてくれたコードをパクって改造してみますた。
var rtn = GetKeyboardState( );
ModKey = rtn(1);
var oObjects = FilterX3D( Selection );
if ( oObjects.count != 0 )
{
var oSymRingpulls = Ringpull285cm( oObjects, ModKey );
SelectObj( oSymRingpulls );
}
function Ringpull285cm( oObjects, ModKey )
{
// If no modkey pressed = hardcoded options
if ( ModKey == 0 )
{
PivotObj = "Maman";
xx = 1.0;
yy = 0.0;
zz = 0.0;
DuplicateConstraint = true;
ShareParent = true;
FreezeNegativeScaling = true;
IsRingpullTall = true; // Cancel flag = NOT cancelled
}
// If any modkey pressed = PPG
else
{
var oP = XSIFactory.CreateObject( "CustomProperty" );
oP.name = "身長285cm";
var oParam;
oParam = oP.AddParameter2( "sPlane", siString, "X" );
oParam = oP.AddParameter2( "sPivot", siString, "Parent" );
oParam = oP.AddParameter2( "bDupConst", siBool, true );
oParam = oP.AddParameter2( "bShareParent", siBool, true );
oParam = oP.AddParameter2( "bFreezeNegScl", siBool, true );
var oLayout, oItem;
oL = oP.PPGLayout;
var aItems1 = Array( "YZ (X)","X", "XZ (Y)","Y", "XY (Z)", "Z" );
var aItems2 = Array( "Parent", "Parent", "Self", "Ringpull" );
oL.AddGroup();
oL.AddRow( );
oItem = oL.AddEnumControl( "sPlane", aItems1, "Plane", siControlCombo );
oItem = oL.AddEnumControl( "sPivot", aItems2, "Pivot", siControlCombo );
oL.EndRow( );
oL.EndGroup( );
oL.AddGroup();
oL.AddRow( );
oL.AddGroup( "", false, 40 );
oItem = oL.AddItem( "bDupConst", "Duplicate Constraints" );
oL.EndGroup( );
oL.AddGroup( "", false, 60 );
oL.EndGroup( );
oL.EndRow( );
oL.AddRow( );
oL.AddGroup( "", false, 30 );
oL.EndGroup( );
oL.AddGroup( "", false, 40);
oItem = oL.AddItem( "bShareParent", "Share Parent" );
oL.EndGroup( );
oL.AddGroup( "", false, 30 );
oL.EndGroup( );
oL.EndRow( );
oL.AddRow( );
oL.AddGroup( "", false, 60 );
oL.EndGroup( );
oL.AddGroup( "", false, 40 );
oItem = oL.AddItem( "bFreezeNegScl", "Freeze Negative Scaling" );
oL.EndGroup( );
oL.EndRow( );
oL.EndGroup( );
Inspect = InspectObj( oP,null, null, siModal, false );
if ( !Inspect )
{
switch( oP.sPlane.value)
{
case "X" : xx = 1.0; yy = 0.0; zz = 0.0; break;
case "Y" : xx = 0.0; yy = 1.0; zz = 0.0; break;
case "Z" : xx = 0.0; yy = 0.0; zz = 1.0; break;
}
switch ( oP.sPivot.value )
{
case "Parent" : PivotObj = "Maman"; break;
case "Ringpull" : PivotObj = "Ringpull"; break;
}
DuplicateConstraint = oP.bDupConst.value;
ShareParent = oP.bShareParent.value;
FreezeNegativeScaling = oP.bFreezeNegScl.value;
IsRingpullTall = true; // Cancel flag = NOT cancelled
}
else
{
IsRingpullTall = false; // Cancel flag = Cancelled
}
}
// Do Duplicate Symmetry (Mainly stolen from Ringpull's code )
if ( IsRingpullTall )
{
var oRingpulls = XSIFactory.CreateObject( "XSI.Collection" );
for ( var i=0; i<oObjects.count; i++ )
{
var oObj = oObjects(i);
if ( PivotObj == "Maman" )
{
var oPivotObject = oObj.Parent;
}
else if ( PivotObj == "Ringpull" )
{
var oPivotObject = oObj;
}
var oTrans = oPivotObject.Kinematics.Global.Transform;//軸になるオブジェクトのトランフォームげっと(=親 or りんぷる)
var vT = XSIMath.CreateVector3();
var vR = XSIMath.CreateVector3();
var vN = XSIMath.CreateVector3( xx, yy, zz );
var rA = XSIMath.CreateRotation();
oTrans.GetTranslation(vT);//選択オブジェクトの位置げっと
oTrans.GetRotationXYZAngles(vR);//選択オブジェクトの回転げっと
rA.SetFromXYZAngles( vR);
vN.MulByRotationInPlace( rA);//プレーンをげっとした回転で回す
vN.NormalizeInPlace();
d = vT.Dot(vN);
var oRingpull = DuplicateSymmetry( oObj, DuplicateConstraint, ShareParent, vN.x, vN.y, vN.z, d, FreezeNegativeScaling )(0);
oRingpulls.Add( oRingpull );
}
return oRingpulls;
}
}
function FilterX3D( in_Objs )
{
var oCol = XSIFactory.CreateObject( "XSI.Collection" );
for ( var i=0; i<in_Objs.count; i++ )
{
if ( in_Objs(i).IsClassOf( siX3DObjectID ) )
{
oCol.Add( in_Objs(i) );
}
}
return oCol;
}
オブジェクト(複数可)を選んで実行します。
何も押さないで実行すると、速攻で親を軸としたXローカルなシンメトリ複製が実行されます。
Shift とか何か押して実行すると PPG が降臨してオプション指定が可能です。
一応、標準の Duplicate Symmetry のオプションは再現したつもりですが。
こちらにも Python で書かれたバージョンがあります。
http://d.hatena.ne.jp/fmt0808/20110220/1298220836
うーむ、なんか美しい感じがしますよね。わかっている/慣れている人は違う。 丁寧なコメントが付いているので Python そのものの勉強にもなります。
あとはクローンできるようにした方がいいのかな。
日々使いながら改造します。
しばらくは毎日使います。
.
| 固定リンク
« そしてまたビール。 | トップページ | ○。 »
コメント
りんぷる先生! 本文中のスクリプトで、
ブツが何かの子供になっていた場合で、
かつ Freeze Negative Scaling がオフになっている場合、
期待した結果になりません! ローカル対称の位置に行ってくれません!
逆に、
ブツが何かの子供になっていなければ(グローバルの子供なら)、Freeze Negative Scaling がオフでも大丈夫です。 あるいは、ブツが何かの子供だったとしても、Freeze Negative Scaling がオンなら、当然大丈夫です。
Freeze Negative Scaling によって計算を変えないといけない気がするんですが、どうでしょう。 俺さっぱりなので、俺のかわりにあなたが考えて下さい。
よろしく御査収お願い申し上げます。
投稿: junki | 2011年2月23日 (水) 01時57分
どもです、ちょっとわからないですね。すいません
正しくならない条件ですが
ブツが何かの子供になっていた場合で、
かつ Freeze Negative Scaling がオフになっている場合、
ではなくて
親のy,zの回転が0でない場合(X反転時)で、
かつ Freeze Negative Scaling がオフになっている場合
正しくならない様です
Freeze Negative Scaling がオフになっている場合
DuplicateSymmetryの引数の
d(SymmetryPlaneD)の値に何が入っていても結果が変わらないんですが
なんで変わらないのかよくわからないですw
(そもそもax,by,czが入るところにa,b,cを入れたらうまくいったという理屈もわからないんですがw)
なんか微妙な感じです
以下正しくならなかった場合、移動して回転させて位置を合わせるスクリプトですw
var oObj = selection(0);
var oTransSelf = oObj.kinematics.Local.Transform;//選択オブジェクトのローカルトランスフォームげっと
var oTransParent = oObj.Parent.kinematics.Global.Transform;//選択オブジェクトの親グローバルトランスフォームげっと
var vT = XSIMath.CreateVector3();
var vR = XSIMath.CreateVector3();
var vN = XSIMath.CreateVector3( 1.0, 0.0, 0.0);
var rA = XSIMath.CreateRotation();
oTransParent.GetTranslation(vT);//選択オブジェクトの位置げっと
oTransParent.GetRotationXYZAngles(vR);//選択オブジェクトの回転げっと
rA.SetFromXYZAngles( vR);
vN.MulByRotationInPlace( rA);//プレーンをげっとした回転で回す
vN.NormalizeInPlace();
d = vT.dot(vN) ;
var oDup = DuplicateSymmetry(oObj, true, false, vN.x, vN.y, vN.z, d, true)(0);
//以下Freeze Negative Scaling オフで正しくならなかったときの場合
var oDupB = DuplicateSymmetry(oObj, true, false, vN.x, vN.y, vN.z, 1, false)(0);//Freeze Negative Scaling オフ
//oDupBを親基準で-xの位置に移動
oTransSelf.GetTranslation( vT); // 選択オブジェクトの位置げっと
vT.x = vT.x * -1;
var vGlobalT = XSIMath.MapObjectPositionToWorldSpace( oTransParent, vT);
var oTransDup = oDupB.kinematics.Global.Transform; //複製オブジェクトのグローバルトランスフォームげっと
oTransDup.SetTranslation( vGlobalT);
oDupB.kinematics.Global.Transform = oTransDup;
//oDupBをx軸180度回転
//コマンド的にはRotate oDupB, -180, 0, 0, siRelative, siLocal, siObj, siXYZ, , , , , , , , 0
var oTransDup = oDupB.kinematics.Local.Transform;
oTransDup.GetRotationXYZAngles( vR);
rA.SetFromXYZAngles( vR);
var vX = XSIMath.CreateVector3( 1.0, 0.0, 0.0);
var vY = XSIMath.CreateVector3( 0.0, 1.0, 0.0);
var vZ = XSIMath.CreateVector3( 0.0, 0.0, 1.0);
vX.MulByRotationInPlace( rA);
vY.MulByRotationInPlace( rA);
vZ.MulByRotationInPlace( rA);
//vX.NegateInPlace();
vY.NegateInPlace();
vZ.NegateInPlace();
oTransDup.SetRotationFromXYZAxes( vX, vY, vZ);
oDupB.kinematics.Local.Transform = oTransDup;
投稿: ringpull(りんぷる | 2011年2月24日 (木) 03時38分
すいません一箇所間違えました
var oObj = selection(0);
var oTransSelf = oObj.kinematics.Local.Transform;//選択オブジェクトのローカルトランスフォームげっと
var oTransParent = oObj.Parent.kinematics.Global.Transform;//選択オブジェクトの親グローバルトランスフォームげっと
var vT = XSIMath.CreateVector3();
var vR = XSIMath.CreateVector3();
var vN = XSIMath.CreateVector3( 1.0, 0.0, 0.0);
var rA = XSIMath.CreateRotation();
oTransParent.GetTranslation(vT);//選択オブジェクトの位置げっと
oTransParent.GetRotationXYZAngles(vR);//選択オブジェクトの回転げっと
rA.SetFromXYZAngles( vR);
vN.MulByRotationInPlace( rA);//プレーンをげっとした回転で回す
vN.NormalizeInPlace();
d = vT.dot(vN) ;
var oDup = DuplicateSymmetry(oObj, true, false, vN.x, vN.y, vN.z, d, true)(0);
//以下Freeze Negative Scaling オフで正しくならなかったときの場合
var oDupB = DuplicateSymmetry(oObj, true, false, vN.x, vN.y, vN.z, d, false)(0);//Freeze Negative Scaling オフ
//oDupBを親基準で-xの位置に移動
oTransSelf.GetTranslation( vT); // 選択オブジェクトの位置げっと
vT.x = vT.x * -1;
var vGlobalT = XSIMath.MapObjectPositionToWorldSpace( oTransParent, vT);
var oTransDup = oDupB.kinematics.Global.Transform; //複製オブジェクトのグローバルトランスフォームげっと
oTransDup.SetTranslation( vGlobalT);
oDupB.kinematics.Global.Transform = oTransDup;
//oDupBをx軸180度回転
//コマンド的にはRotate oDupB, -180, 0, 0, siRelative, siLocal, siObj, siXYZ, , , , , , , , 0
var oTransDup = oDupB.kinematics.Local.Transform;
oTransDup.GetRotationXYZAngles( vR);
rA.SetFromXYZAngles( vR);
var vX = XSIMath.CreateVector3( 1.0, 0.0, 0.0);
var vY = XSIMath.CreateVector3( 0.0, 1.0, 0.0);
var vZ = XSIMath.CreateVector3( 0.0, 0.0, 1.0);
vX.MulByRotationInPlace( rA);
vY.MulByRotationInPlace( rA);
vZ.MulByRotationInPlace( rA);
//vX.NegateInPlace();
vY.NegateInPlace();
vZ.NegateInPlace();
oTransDup.SetRotationFromXYZAxes( vX, vY, vZ);
oDupB.kinematics.Local.Transform = oTransDup;
投稿: ringpull(りんぷる | 2011年2月24日 (木) 03時41分
いやあ、りんぷるさんお世話になります。
りんぷるさんにわからないことが、俺にわかるワケがありません。あきらめましょうw
っていうか、ユーザが Freeze Negative Scaling をオフで実行した場合は、後半の「正しくならなかった場合、移動して回転させて位置を合わせるスクリプト」 の部分のコードが走るようにすればいいかな?
あるいは、しくみの理解は棚に上げて結果だけを求めるなら、俺が最初に書いたもっとも原始的なバージョンを使うのもひとつの手かなあ。これは、一度グローバル原点に持っていって rot 0 の状態にし、標準の Duplicate Symmetry コマンドに全ておまかせして原点基準で対称複製し、その結果をまた元の位置と回転に戻すということをやっているので、Freeze Negative Scaling だろうがなんだろうが XSI の UI からの操作で想定されている状態は 100% 再現できるはずなんですよね。そうしちゃおうかなあ。
一昨日あたりから、ひとまずこの記事の本文中にあるバージョンをプラグイン化してガンガン使っています。現在のタスクが一段落するまで毎日使うはずです。
そして普段は Freeze Negative Scaling は常にオンの状態で使っているので、なんにも問題になりませんw 標準機能で使えるオプションを全部再現することにこだわらなければ、俺様的実用上、Freeze Negative Scaling のオプションは抹殺してしまう(=常にオンにしかできない)のが一番良いですw
投稿: junki | 2011年2月24日 (木) 13時46分