ラベル softimage の投稿を表示しています。 すべての投稿を表示
ラベル softimage の投稿を表示しています。 すべての投稿を表示

2012/12/21

インスタンスモデルを普通のモデルに戻す

すげー久しぶりの更新。。。

標準機能にあると思って探したけどどうやらないみたいなので書きました。
インスタンスモデルを普通のモデルに戻すスクリプトです。

マスターモデルを選択して実行。

とりあえず動くけど直したいところは結構あります。
とりあえずメモってことで。
from siutils import si, disp

def GetInstances(oMdl):
    gInsts = oMdl.Groups('InstanceGroup')
    return gInsts.Members
    
def ResotreInstance(oInst, oMstr=None, bDel=True):
    if not oMstr:
        oMstr = oInst.InstanceMaster
    sInstName = oInst.Name
    oParent   = oInst.Parent
    oTmp = si.Duplicate("B:"+oMstr.Name, "", 2, 1, 1, 0, 2, 1, 0, 1, "", "", "", "", "", "", "", "", "", "", 0)(0)
    oTmp.Kinematics.Global.Transform = oInst.Kinematics.Global.Transform
    oTmp = disp(oTmp)
    if bDel:
        si.DeleteObj(oInst)
    oTmp.Name = sInstName
    oParent.AddChild(oTmp)
    return oTmp
 

oMdl = si.Selection(0)
if not oMdl.Type == '#model':
    oMdl = oMdl.Model

oInsts = GetInstances(oMdl)
for oInst in oInsts:
    ResotreInstance(oInst, oMdl, False)
si.DeleteObj(oInsts)

マスターモデルをデュプリケイトして位置と名前と親を合わせただけですね。
毎回DeleteObjすると効率が悪いので外に出していっぺんにやりましたが、Duplicateも同様なので修正したいです。

ま、時間があるときにまた直すかも。

2012/05/04

Softimageの開発陣が移動???

http://goo.gl/L0UIY
なんかAutodeskの人事異動でSoftimageの開発チームがMayaチームに移動、って感じのことが書いてある気がする。。。
コメント見ても「この世の終わりだ」的なものが多いし。

大丈夫なのか???

2011/12/26

シーン中のすべての~を取得

ずっと昔にどっかで見て使ったけどすっかり忘れちゃってた方法を、必要にかられて思い出しました。
次はもうちょっとすばやく思い出せるようにメモ。
シーン中のすべてのエクスプレッション、とかすべてのコンストレイン、とか探したくならないですか?
そんなときには「Application.FindObjects」らしいです。

シーン中のすべてのエクスプレッションを取得するには以下のようにするそうです。過去の自分によれば。
from siutils import *
oExps = si.FindObjects('', '{12723EB2-7DDB-11D0-A57F-00A0C91412DE}')
for i in oExps:
    print i.Definition.Value
すべてのPoseコンストレインはこう。
from siutils import *
oPoseCnss = si.FindObjects('', '{D42BBF71-3C47-11D2-8B42-00A024EE586F}')
for i in oPoseCnss:
    print i
この意味不明な文字はsiObjectCLSIDというものらしいです。
以下で選択オブジェクトのsiObjectCLSIDが取得できます。
from siutils import *
repo = siut.DataRepository
print repo.GetIdentifier(si.Selection(0), 3)

と、ここまで書いておそらくjunkiさんのページで見たのだと思い出しました。
ほんとにいつもお世話になりっぱなしです。

2011/09/28

SoftimageのオブジェクトをPythonクラスで拡張する

タイトルどおりSoftimageのオブジェクトをPythonクラスで拡張する方法。
これのミソは元々のSoftimageのオブジェクトの機能はちゃんと受け継いでるところです。
たとえばこんな感じ。
from win32com.client import *
si = Application

class MyObject(object):
    '''Softimageオブジェクトを拡張するクラス'''
    def __init__(self, input):
        '''初期化処理'''
        self.input = input  #元オブジェクトを格納


    def __getattr__(self, attr):
        '''このクラスにないアトリビュートが呼び出されたときに通る処理'''
        return getattr(self.input, attr)  #元オブジェクトのアトリビュートを取得して戻す


oNull = si.ActiveSceneRoot.AddNull() #ヌルを作成
MyNull= MyObject(oNull)                 #ヌルを引数に自前クラスのインスタンスを作成
LogMessage(MyNull.Name)
LogMessage(MyNull.posx.Value)
MyNull.AddNull('child')

これをSoftimageのスクリプトエディタに貼って実行するとどこにも定義してないけど.Nameも.posx.ValueもメソッドのAddNull()も使えます。

種は__getattr__とgetattrで、
__getattr__はクラスにないアトリビュートが呼ばれた時に実行されるメソッドで、呼び出そうとしたアトリビュートの代わりに戻り値を実行してくれるようです。
getattrは
getattr(オブジェクト, アトリビュート名)
でオブジェクトが持ってるアトリビュートを返してくれます。
なので
    def __getattr__(self, attr):
        return getattr(self.input, attr)
とすることで__getattr__を通る(存在しないアトリビュートが呼ばれた)時にインスタンスを作った時self.inputに格納しておいた元オブジェクトを使ってgetattr(self.input, attr)で元オブジェクトのアトリビュートを取得して実行するようになります。

これで好きな機能をバリバリ追加したカスタムオブジェクトが作れます。
たとえばこんな感じ。
アイコンを簡単に変更する機能をつけたヌルクラス

from win32com.client import *
si = Application

#ヌルアイコンの定数
NullIcon = {
   'None'       : 0,
   'Null'       : 1,
   'Rings'      : 2,
   'Arrow Rings': 4,
   'Box'        : 5,
   'Circle'     : 6,
   'Square'     : 7,
   'Diamond'    : 8,
   'Pyramid'    : 9,
   'Arrow'      : 10
   }


class MyNull(object):
 '''Nullを拡張するクラス'''
 def __init__(self, input):
  '''初期化処理'''
  self.input = input  #元オブジェクトを格納


 def __getattr__(self, attr):
  '''このクラスにないアトリビュートが呼び出されたときに通る処理'''
  return getattr(self.input, attr)  #元オブジェクトのアトリビュートを取得して戻す
  
  
 def SetIcon(self, sIconType='Null', nSize=1):
  '''アイコンを変更'''
  self.Parameters('primary_icon').Value = NullIcon[sIconType]
  self.Parameters('size').Value         = nSize
  
  
 def SetShadowIcon(self, sIconType='Null', nSize=1, lColor=[0,0,0]):
  '''
  シャドウアイコンを変更
  シャドウアイコンを変更するときはきっと通常のアイコンを使わないことが多いので非表示にする
  '''
  self.SetIcon('None', nSize) #通常のアイコンを非表示に
  self.Parameters('shadow_colour_custom').Value = True
  self.Parameters('shadow_icon').Value = NullIcon[sIconType]
  self.Parameters('R').Value = lColor[0]
  self.Parameters('G').Value = lColor[1]
  self.Parameters('B').Value = lColor[2]
  
  
oNull = si.ActiveSceneRoot.AddNull()     #ヌルを作成
Null = MyNull(oNull)                     #ヌルを引数に自前クラスのインスタンスを作成
Null.SetShadowIcon('Rings', 1, [1,1,0])  #シャドウアイコンを変更

2011/05/23

.xsipref でワークグループ管理2

前の投稿の続き。

.xsiprefを書き換えてSoftimageを起動するバッチファイルを作りました。
myXSI.bat
@echo off
set prefname=data_management.workgroup_appl_path
set path1=D:\xsi_workgroups\test;
set path2=D:\xsi_workgroups\test1;
set path3=D:\xsi_workgroups\test2;
echo %prefname% = %path1%%path2%%path3%>[ユーザののPreferenceディレクトリ]\workgroups.xsipref

call [Softimageの起動バッチ]
*[ユーザのPreferenceディレクトリ]にはC:\Users内のPreferenceディレクトリを指定します
*[Softimageの起動バッチ]には普段使っているXSI.batのフルパスを書きます。

このバッチを叩くと3つのワークグループが登録されたSoftimageが起動します。

このバッチファイルを複数用意しておけばいろんなワークグループ設定のSoftimageを簡単に起動できます。
もっといいやり方あるのかもしれないけどとりあえずやりたかったことはできました。
めでたしめでたし。

2011/05/22

.xsipref でワークグループ管理

みなさんSoftimageのワークグループ管理どうしてます?
自分は一応ワークグループ内のプラグインを管理してるので自分のローカルでプラグイン書いてちゃんと動けばサーバにsvnでコミットする、というやり方をしてます。
このやり方、編集中のローカルにあるプラグインがどんなにバグバグでも他の人が実際に登録してるワークグループに影響が出ないのですごくいいんですがサーバ側のチェックがめんどくさい。。。
ローカルとサーバは基本同じものなのでプラグイン名かぶりまくりで同居でず、置き換えなきゃいけません。
なので
1.ローカル側のワークグループを解除
2.サーバ側のワークグループを登録
3.再起動
という手順を踏むことになります。
これはめんどくさい。
ワークグループの登録重いし。(特にサーバ側のやつ)

ずっとなんとかしたいなぁと思ってたんですが、いい方法を見つけました!

Alternative Preference File
XSI will load any .xsipref file it finds in the \Data\Preferences directory of the user or factory location. So, for convenience, you could generate and store the workgroup path in a preference file of its own. This would work best in scenarios where you don't expect the users to connect and disconnect from workgroups themselves and want to establish the correct workgroups through configuration scripts.
(softimage wikiより)

.xsiprefというファイルをインストールディレクトリかユーザディレクトリの/Data/Preferences/に入れとくとプリファレンスをいじれるよ。
なので自分で.xsipref作っといて入れ替えるスクリプト書けばいいじゃん。
みたいな感じ?
実際はよくわかりませんがそうに違いない。

早速試してみました。
workgroups.xsipref
data_management.workgroup_appl_path = D:\xsi_workgroups\test

たった一行のテキストファイルですがこれを上記のディレクトリに置いておくとちゃんと起動時にワークグループが設定されてます!
これを複数作っておいて起動時に入れ替えてやればそのバッチを叩くだけで希望のワークグループを登録したSoftimageが立ち上がるぞ!
まだ作ってないけどw

2011/05/06

Momentum 2.0.1 - Instancer Operator


パーティ来るをそのばでメッシュに変換してさらにシミュレーションかけてる模様。
もうすごすぎてなにがなにやら。。。

2011/01/25

非平面を平面に2

前回の続き。
以前のものは選択したポリゴン面の法泉を基準(これは少し怪しい)に平面化してましたが
今回はスクリプトを実行するとポイントをピックさせられます。
3点ピックするとそれを元に平面化します。
相変わらず4つ以上の面に接したポイントがあるとダメです。
いやぁ使えない使えない。。。

from win32com.client import *
xsi = Application

def GetReferencePoints():
    ''' リファレンスポイントを取得(最低3点) '''
    xsi.ActivateVertexSelTool()
    lPnts = []
    while len(lPnts) < 3:
        rtn = xsi.PickElement(constants.siPointFilter)
        oPick = rtn[2]
        if not oPick:  #ピックが足りない場合処理中止
            return
        for oCmp in oPick.SubComponent.ComponentCollection:
            lPnts.append(oCmp)
    return lPnts

def GetReferenceTransform(lPnts):
    ''' リファレンストランスフォームを取得 '''
    #外積を取得
    v1 = XSIMath.CreateVector3()
    v2 = XSIMath.CreateVector3()
    vCrs = XSIMath.CreateVector3()
    v1.Sub(lPnts[1].Position, lPnts[0].Position)
    v2.Sub(lPnts[2].Position, lPnts[0].Position)
    vCrs.Cross(v1, v2)
    #トランスフォームに変換(後でレイキャストさせるために位置をどのポイントとも違う位置(ポイントの中点)に)
    vPos = XSIMath.CreateVector3()
    for i in range(3):
        vPos.AddInPlace(lPnts[i].Position)
    vPos.ScaleInPlace(1.0/len(lPnts))
    vYAxis = XSIMath.CreateVector3(0,1,0)
    oTrans = XSIMath.CreateTransform()
    oTrans.Translation = vPos
    nAgl   = vYAxis.Angle(vCrs)
    vCrs.Cross(vCrs, vYAxis)
    vCrs.NegateInPlace()
    oTrans.SetRotationFromAxisAngle(vCrs, nAgl)
    return oTrans

def MovePointToReferenceTransform(oFace, oItemTrans, oRefTrans, oAllPnts):
    ''' ポイントをリファレンストランスフォーム上のY=0に移動 '''
    lPosArr = [list(t) for t in oAllPnts.PositionArray]
    for oPnt in oFace.Points:
        vPosOnRef = XSIMath.MapObjectPositionToObjectSpace(oItemTrans, oRefTrans, oPnt.Position)
        vPosOnRef.Y = 0
        vPosOnRef.ScaleInPlace(10)
        vPos = XSIMath.MapObjectPositionToObjectSpace(oRefTrans, oItemTrans, vPosOnRef)
        lPosArr[0][oPnt.Index] = vPos.X
        lPosArr[1][oPnt.Index] = vPos.Y
        lPosArr[2][oPnt.Index] = vPos.Z
    oAllPnts.PositionArray = lPosArr
        
def GetEdgeInfo(oFace):
    ''' エッジ情報を取得 '''
    
    def GetInfo(oEdge, lPntIndxsOnFace):
        oPnts = oEdge.Points
        if oPnts[0].Index in lPntIndxsOnFace:
            oStartPnt = oPnts[1]
            oEndPnt   = oPnts[0]
        else:
            oStartPnt = oPnts[0]
            oEndPnt   = oPnts[1]
        vStart = oStartPnt.Position
        vEnd   = oEndPnt.Position
        vEnd.SubInPlace(vStart)
        vStart.SubInPlace(vEnd)
        return vStart, vEnd, oEndPnt.Index
        
    oNgbrEdges = oFace.Edges.NeighborEdges()
    lPntIndxsOnFace = [oPnt.Index for oPnt in oFace.Points]
    lPos    = [] #開始位置リスト
    lAxis   = [] #方向リスト
    lPntIdx = [] #対象ポイントインデックスリスト
    for oEdge in oNgbrEdges:
        lInfo = GetInfo(oEdge, lPntIndxsOnFace)
        lPos.extend(lInfo[0].Get2())
        lAxis.extend(lInfo[1].Get2())
        lPntIdx.append(lInfo[2])
    return lPos, lAxis, lPntIdx
    
def MovePointToRaycastPosition(oGeom, oFace, lEdgeInfo):
    ''' ポイントをレイキャストした先に移動 '''
    oGeom.SetupPointLocatorQueries(3, None, [oFace.Index], -1)
    oPntLocations = oGeom.GetRaycastIntersections(lEdgeInfo[0], lEdgeInfo[1], 0)
    lPos = oGeom.EvaluatePositions(oPntLocations)
    oPnts = oGeom.Points
    lPosArr = [list(t) for t in oPnts.PositionArray]
    for idx, allidx in enumerate(lEdgeInfo[2]):
        lPosArr[0][allidx] = lPos[0][idx]
        lPosArr[1][allidx] = lPos[1][idx]
        lPosArr[2][allidx] = lPos[2][idx]
    oPnts.PositionArray = lPosArr
    
def main():
    oSel = xsi.Selection(0)
    if oSel.Type != 'polySubComponent': #ポリゴンが選択されてない場合処理中止
        return
    #選択ポリゴンのサブコンポーネントからいろいろ取得
    oSubCmp    = oSel.SubComponent
    oFace      = oSubCmp.ComponentCollection[0]
    oPoly      = oFace.Nodes[0]
    oItem      = oSubCmp.Parent3DObject
    xsi.FreezeModeling(oItem)                              #フリーズしとかないとポイントの移動ができない
    oItemTrans = oItem.Kinematics.Global.Transform
    oGeom      = oItem.ActivePrimitive.Geometry
    oAllPnts   = oGeom.Points
    lPosArr    = [list(t) for t in oAllPnts.PositionArray]
    oAllPnts.PositionArray = lPosArr                       #一旦ポイントをいじっとくことで初回実行からちゃんと動く(なぞ)
    lEdgeInfo  = GetEdgeInfo(oFace)                        #エッジ情報を保存
    lPnts      = GetReferencePoints()                      #参照トランスフォーム作成用ポイントをピックさせる(最低3点)
    if not lPnts:
        return
    oRefTrans  = GetReferenceTransform(lPnts)              #参照トランスフォームを作成
    MovePointToReferenceTransform(oFace, oItemTrans, oRefTrans, oAllPnts) #とりあえず平面化
    MovePointToRaycastPosition(oGeom, oFace, lEdgeInfo)                   #できた面と保存しておいてエッジをレイキャストして補正
    xsi.ActivateRaycastPolySelTool()
    
main()

2011/01/20

非平面を平面に

ツイッター上で話題になっていた非平面ポリゴンを平面化する、というスクリプトです。
Softimage2011で確認。
単純に平面化するとほかのポリゴン面の形を変えてしまってせっかく平面だったものも非平面にしてしまうので
いろいろこねくり回して回避してます。
汚いコードですがとりあえずそれっぽく動くようにはなってます。
いくつか問題はありますが。。。

使い方は、平面化したいポリゴンを選択後実行。です。
使用前


使用後



おおまかな処理内容としては
・平面化したいポリゴン面に隣接するエッジ情報をとっておく
・平面化
・平面化したポリゴンととっておいたエッジの交差点にポイントを移動
てな感じです。

上にも書きましたが問題がありまして、
・ポリゴンの法泉がうまく取得できなくて失敗することがある。
PolygonNode.Normalから取得してるんですが値の意味を勘違いしてるのか使い方が悪いのか
けっこうな頻度でうまくいかない。
再現性があるのでなんかしらの理由があるのだろうけどわかりません。
情報求む。

ここに関しては横着せずに他の人がツイッターに書いていたように各ポイント法線から算出すれば解決するかもしれません。

・対象ポリゴンを構成するポイントが4つ以上のポリゴンに属しているとうまくいかない
最初にとっておいてるエッジ情報のインデックスと最後に移動させるポイントのインデックスが合わないのが一つ。
これはもうちょい手を入れればなんとかなりそう。
もうひとつがオレの陳腐な脳みそでは可決不能。
4つ以上の面に接したポイントをどう動かせばすべての面を平面に保てるかわからない。
誰か頭のいい人教えてください。

・なぜか1回目の実行は処理がされない
なんで???

とまぁこんな感じです。
そのうち直せたら直したい。

以下コード。

from win32com.client import *

xsi = Application

#サブコンポーネントからいろいろ取得
oSubCmp = xsi.Selection(0).SubComponent
oFace   = oSubCmp.ComponentCollection[0]
oPoly   = oFace.Nodes[0]
oParent = oSubCmp.Parent3DObject
oGeom   = oParent.ActivePrimitive.Geometry
xsi.FreezeModeling(oParent)

#隣接エッジのベクトルを保存しておく
#(レイキャスト時にちゃんとヒットするように拡大)
lPntIdxs = [oPnt.Index for oPnt in oFace.Points]
lEdgePos  = []
lEdgeAxis = []
lEdgePntIdx  = []
for oEdge in oFace.Edges.NeighborEdges():
    oEdgePnts = oEdge.Points
    if oEdgePnts[0].Index in lPntIdxs:
        oStartPnt = oEdgePnts[1]
        oEndPnt   = oEdgePnts[0]
    else:
        oStartPnt = oEdgePnts[0]
        oEndPnt   = oEdgePnts[1]
    vEdgeAxis = XSIMath.CreateVector3()
    vEdgeAxis.Sub(oEndPnt.Position, oStartPnt.Position)
    vEdgeAxis.ScaleInPlace(100)        #拡大
    lEdgeAxis.extend(vEdgeAxis.Get2())
    vPos = oStartPnt.Position
    vEdgeAxis.ScaleInPlace(0.5)        #逆側もレイキャストできるように後ろにずらす
    vPos.Sub(vPos, vEdgeAxis)
    lEdgePos.extend(vPos.Get2())
    lEdgePntIdx.append(oEndPnt.Index)
  

#ポリゴン面にそったトランスフォームを作成
vFacePos = XSIMath.CreateVector3()
oPnts = oFace.Points
for oPnt in oPnts:
    vFacePos.Add(vFacePos, oPnt.Position)
vFacePos.Scale(1.0/oPnts.Count, vFacePos)
 
oTrans = XSIMath.CreateTransform()
oTrans.Translation = vFacePos
vYAxis = XSIMath.CreateVector3(0, 1, 0)
vNrml = XSIMath.CreateVector3()
nAngle = vYAxis.Angle(oPoly.Normal) #radians
vCross = XSIMath.CreateVector3()
vCross.Cross(vYAxis, oPoly.Normal)
oTrans.SetRotationFromAxisAngle(vCross, nAngle)

#平面化
#(さっき作ったのトランスフォーム上でのY=0に移動)
#(レイキャスト時にちゃんとヒットするように拡大)
dPos    = {}
for oPnt in oPnts:
    vPntOnFace = XSIMath.MapWorldPositionToObjectSpace(oTrans, oPnt.Position)
    vPntOnFace.ScaleInPlace(5)
    vPntOnFace.Y = 0
    vPntOnFace = XSIMath.MapObjectPositionToWorldSpace(oTrans, vPntOnFace)
    dPos[oPnt.Index] = vPntOnFace
oPnts = oGeom.Points
lPosArr = [list(l) for l in oPnts.PositionArray]
for idx, v in dPos.iteritems():
    lPosArr[0][idx] = v.X
    lPosArr[1][idx] = v.Y
    lPosArr[2][idx] = v.Z
oPnts.PositionArray = lPosArr

#エッジベクトルから平面にレイキャスト
oGeom.SetupPointLocatorQueries(3, None, [oFace.Index], -1)
oPntLocations = oGeom.GetRaycastIntersections(lEdgePos, lEdgeAxis, 1)
lPos = oGeom.EvaluatePositions(oPntLocations)
for idx, allidx in enumerate(lEdgePntIdx):
    lPosArr[0][allidx] = lPos[0][idx]
    lPosArr[1][allidx] = lPos[1][idx]
    lPosArr[2][allidx] = lPos[2][idx]
oPnts.PositionArray = lPosArr