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/09/16

メソッドからクラス名を取得2

またまた自分用メモ。
こういうやり方もあるらしい。
これだとsys._getframe()の引数を変えることでクラスに限らずどんどんframeオブジェクトとやらを上がっていけるみたい。
import sys

def test():
	print sys._getframe(1).f_code.co_name

class TestClass:
    test()
 
T = TestClass()

2011/09/14

メソッドからクラス名を取得

自分メモ。
自分を呼び出したインスタンスのクラス名を表示。
class TestClass:
	def test(self):
		print locals()['self'].__class__.__name__

class TestClass2(TestClass):
	pass
		
T = TestClass()
T.test()

T = TestClass2()
T.test()

9/25 追記:
べつにこれでいいじゃん。。。
class TestClass:
	def test(self):
		print self.__class__.__name__

class TestClass2(TestClass):
	pass
		
T = TestClass()
T.test()

T = TestClass2()
T.test()
ま、なんかに使えるかな。きっと。

2011/06/30

Game Tools & Middleware Forum 2011

Game Tools & Middleware Forum 2011とその後の非公式飲みに行ってきました。
http://www.info-event.jp/gtmf2011/

フォーラム本編ではやはりUnityの存在感が強い印象を受けました。
今回もUnreal、国内エンジンOROCHIなどのゲームエンジンがセッションを持っていましたが、Unity含めゲームエンジン全般がどれも迅速なトライ&エラー、迅速なデバッグを追求していて、各機能の優劣はあれど基本的な考え方はほぼ同じように思えました。
Unreal、OROCHIが新たに組み込んだすばらしい機能のプレゼンをしていたのに対しUnityのほうは現在の日本のゲーム開発環境とゲームエンジンを使ったパイプラインの差をプレゼンしてくれていました。その上でUnityを使えばこんなにいいよ、と。
実際Unrealのほうがハイエンドで美しい絵が出せていますが、AssetStoreというアップルのAppStoreのようなものを開いて世界中の人が素材やカスタム環境をどんどん開発していけるコミュニティの力は大きいとです。

ということで自分もUnity使い始めてますがまだまだわからないことだらけ。
でもいろいろと参考になる動画やチュートリアルがあるみたいなんでコツコツやっていきます。

非公式飲みではいろんな人と話をすることができました。
こういう場には割と顔を出すほうなんですが今回は今まで知らなかった国内ゲーム開発のコミュニティや活動のことを知りました。
またこういう場に来ている人同士の人脈の広さや業界へのアンテナの張り方の広さを思い知りました。

うーん、みんなすごい!
来年もまた期待しちゃうなー



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/15

いいカメラがほしい!

娘が生まれれて早4ヶ月。
今まで撮ったこと無いような枚数の写真を撮りまくってます。
ただ撮った写真を見るとやっぱりもっときれいにかわいく写したい願望が出てきました。
そこでカメラを買い換えることに。

正直今までカメラに興味がわなかくて小さければ小さいほどいいと思ってました。
それがいざいいものを探し始めると基準がわからないので決められない!

コンパクトデジカメからのグレードアップということを重視して先輩が進めてくれたのは
sonyのα NEX-5

とりあえず触りに行こうということでヨドバシに行って事情を話すと
同じくsonyのα55薦められました。


聞くとより性能がいいのはわかったけどやっぱり自分には気軽に使えるコンパクトのほうがいいと思ってみたり。。。
運動会とかで撮ることになることを考えると望遠が強いほうがいいと思ってみたり。。。

うーむ。。。
悩ましい。
早く買わないと娘の時間は刻々と過ぎていく!

2011/05/12

「センス・オブ・ワンダー ナイト 2011」の作品公募がスタート

何年か前のやつをTGSで見た。
シンプルだけどおもしろいものが多くて感動して帰ってきたのを覚えてる。
今回はどうかな?
http://indyzone.jp/blog/archives/2011/05/mari_challenge_1.html

MARIチャレンジ

3DペイントソフトMARIを使ったコンペみたい。
最近こういうのよく見かけるなぁ。
自分が見つけてなかっただけ?
http://indyzone.jp/blog/archives/2011/05/mari_challenge_1.html

2011/05/06

Momentum 2.0.1 - Instancer Operator


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

2011/04/30

X-MEN First Class


プロフェッサー世代の話なのかな?
こりゃ観たい。

2011/03/09

シンタックスハイライト

今までいれてたものよりいいのがあったので入れてみた。
http://fazibear.prv.pl/



が、うまく表示されず。。。
以下テストコード
------------------------
def test():
    print 'test'

test()
------------------------
インデントはうまくいってるけどハイライトができない。
なんでだろ?
もうちょい調べてダメだったら元にもどそう。

参考にしたのは以下のページ
http://giichirosasaki.blogspot.com/2010/11/bloggersyntaxhighlighter.html
http://kuinazi.blogspot.com/2010/03/blogger-syntax-highlighter.html

2011/03/01

yahoo pipes

yahoo pipesでつくったfeed(?)がうまくgoogleリーダーに読み込めない。
なぜだ?
ネットは難しい。。。

追記:
おとなしくgoogleリーダーのみで構成したらうまくいきそう。
はやく終わらせたいな。

2011/02/28

rss

はじめたばかりのこのブログですがさっそく更新が止まってます。。。
(誰も読んでないと思いますが)
もともとマメなほうではないので予想でしたんですがこの放置っぷりはひどい。
たぶん書くときに身構えてしまうからダメなんだな。
もっと気楽に。twitterにつぶやくように書こう。

ということで、今日はどうでもいいことを書きます。

cg系のblogをブックマークしまくってるんですが毎日チェックするのが厳しいです。
ブックマークぜんぜん整理できてないし、うまく使えてないです。
なのでrssリーダーに登録してブックマークからは消すことにしました。
いまいちやり方がわかりませんが。
blogに行ってrss的な文字がないところはできないんでしょうか?
そうするとあまり効果を発揮しないかもしれないなぁ。

どうでもいい日記でした。

2011/02/01

アウトレット

やっとこさiPhoneアプリに手を出しはじめました。
とはいってもただの興味本位で何かつくりたいものがあるわけでも金をもうけようと思ってる訳でもありません。
いろいろ調べたら自分の不満を解消するすべが身に付くかもなぁ、程度。

で、
http://gihyo.jp/dev/serial/01/iphone
を見てはじめてのアプリをつくってるんですが、いきなり「アウトレット」とやらが作れません。
この記事は少し古いバージョンのものらしく、指定された操作ができない。

この記事ではこうですが、


自分の手元ではこう。なんかいろいろ足りない。


うーむこまった。
ちゃんと本買ってじっくりやるかぁ。

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