2016年1月5日火曜日

【Maya】 【python】ポリゴンの凹面を判別する。

少し前からですが、アーティストの方から割と要望をいただく件として、
「ポリゴンメッシュの凹面を自動判別する機能」があります。

早めに開発着手したかったのですが、なかなか手が空かず、
時間ばかりいただいてしまいました。。
で、ちょうど年末年始、数学に強い従兄の助言もいただき、
時間のあるこの時期に大体形にしてみたので、こちらでも紹介します。

■どうやって凹凸を判別するか?
 チェックするポリゴンは4頂点の4角形であることが前提です。
 そもそも3角形だったら平面だし。5角形だったらそもそもポリゴン割れし。
 
 で、仕組みはこうです。
 ずばり内積と外積を使います。

 ベクトルの内積と外積を使って、4頂点のうち、
 3頂点の平面から見た残りの1点の位置を判別します。












 








~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
かんたんに外積:
2つのベクトルに垂直なベクトルを算出します。

 

















 
かんたんに内積:
ベクトルAをベクトルBに成分分解したときの、そのベクトルの長さを求めます。



















~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 その手順は…、

 ①3頂点で作る、1点から伸びる2本のベクトルの外積を出して、
 この3角形に垂直なベクトルを算出します。





















 ②残り1頂点で作るベクトルと、①の三角形に垂直なベクトルの内積を求めます。





















 この内積の値が正か負かで、残りの1点の位置が算出できるはずです。

■しかし、ポリゴンのみかたで凹か凸かが変わってしまう。
 この4頂点ですが…

こうみるか




















こうみるかで、凹か凸かが変わってしまいます。




















 要は、どの頂点を判別するのか、準点を定める必要があるわけです。
 ここは、判別の基準をアーティストさんに確認する必要がありますが、、、
 とりあえず、一度Triangulateをかけた時の形状が、凹か凸かを判別するように
 考えることにしました。

 要は、このポリゴンを…





















 Triangulateをかけて…


 この3角形に含まれない頂点…


 つまり、この頂点を判別することにします。


■melに便利なコマンドが
 melにズバリ、内積・外積を算出するコマンドがあるので、これを使うっきゃない。
 
 外積:cross  http://download.autodesk.com/global/docs/maya2014/ja_jp/Commands/cross.html
 内積:dot    http://download.autodesk.com/global/docs/maya2014/ja_jp/Commands/dot.html 

 しかし、頂点計算など、数が多い処理は全てmelで処理するには重たすぎるので、
 基本はすべてpythonで書くことにし、pythonからmelプロシージャを呼び出すようにします。

そんな感じで、ぱっと作ってみました。
※使用方法は、mel文を先に実行しておくか、sourceコマンドで読んでおいた上で
ポリゴンを選択し、python文を実行します。
すると、凹んだ角形のみが選択された状態で終了します。

実際にまだ使っていないので、信頼性は低いですが。
いろいろテストなどして、ブラッシュアップしていこうと思います。
 
以下ソース
//------------------------
//mel部分
//------------------------
global proc float[] ReturnCrosProductList(vector $vec1,vector $vec2){
vector $crossProc = cross($vec1,$vec2);
float $ReturnList[];
$ReturnList[0]=$crossProc.x;
$ReturnList[1]=$crossProc.y;
$ReturnList[2]=$crossProc.z;
return $ReturnList;
}
global proc float ReturnDotProductList(vector $vec1,vector $vec2){
float $ReturnFloat = dot($vec1,$vec2);
return $ReturnFloat;
}
//------------------------
#python部分
#-------------------------
# -*- coding: utf-8 -*-
import maya.cmds as mc
import maya.mel as mel
import math as math
def change_e_to_zero(List=[0,0,0]):
i=0
for num in List:
numstr='%s'%num
if len(numstr.split('e'))>1:
List[i]=0.0
i=i+1
return List
def getRecessedFace():
errorFaceList=[]
faceList=[]
trifaceList=[]
vtxList=[]
triVtxList=[]
chkVtxList=[]
P_org=[]
P_A=[]
P_B=[]
P_C=[]
vec1=[1,1,1]
vec2=[1,1,1]
vec3=[1,1,1]
vecNormal=[1,1,1]
vecCrossProc=[1,1,1]
moreFiveVtxFaceList=[]
faceList=mc.ls(mc.polyListComponentConversion(mc.ls(sl=True),tf=True),fl=True)
#mc.scriptEditorInfo(sr=False)
for face in faceList:
trifaceList[:]=[]
vtxList[:]=[]
chkVtxList[:]=[]
P_org[:]=[]
P_A[:]=[]
P_B[:]=[]
P_C[:]=[]
vtxList = mc.ls(mc.polyListComponentConversion(face,tv=True),fl=True)
try:
if len(vtxList)>4:
print 'This is more 5Vtx Face.'
elif len(vtxList)<4:
print 'This is Triangle Face.'
else:
#get target vtx
mc.select(face)
mc.polyTriangulate(face,ch=False)
trifaceList=mc.ls(sl=True,fl=True)
triVtxList=mc.ls(mc.polyListComponentConversion('%s'%trifaceList[0],tv=True),fl=True)
mc.undo()
mc.select(vtxList)
mc.select(triVtxList,d=True)
chkVtxList=mc.ls(sl=True,fl=True)
mc.select(cl=True)
#get vtx point
P_org=mc.pointPosition('%s'%triVtxList[0])
P_A=mc.pointPosition('%s'%triVtxList[1])
P_B=mc.pointPosition('%s'%triVtxList[2])
P_C=mc.pointPosition('%s'%chkVtxList[0])
#change e to 0
P_org=change_e_to_zero(P_org)
P_A=change_e_to_zero(P_A)
P_B=change_e_to_zero(P_B)
P_C=change_e_to_zero(P_C)
#getVec
vec1 = [P_A[0]-P_org[0],P_A[1]-P_org[1],P_A[2]-P_org[2]]
vec2 = [P_B[0]-P_org[0],P_B[1]-P_org[1],P_B[2]-P_org[2]]
vec3 = [P_C[0]-P_org[0],P_C[1]-P_org[1],P_C[2]-P_org[2]]
vecStr1='<<'+str(vec1[0])+','+str(vec1[1])+','+str(vec1[2])+'>>'
vecStr2='<<'+str(vec2[0])+','+str(vec2[1])+','+str(vec2[2])+'>>'
vecStr3='<<'+str(vec3[0])+','+str(vec3[1])+','+str(vec3[2])+'>>'
vecCrossProc=mel.eval('ReturnCrosProductList('+vecStr1+','+vecStr2+');')
#get crossProduct Vec
vecCrossVecStr='<<'+str(vecCrossProc[0])+','+str(vecCrossProc[1])+','+str(vecCrossProc[2])+'>>'
#get dotProduct length
vecDotProc=mel.eval('ReturnDotProductList('+vecStr3+','+vecCrossVecStr+');')
if len(str(vecDotProc).split('e'))>1:
vecDotProc=0
if vecDotProc>0:
errorFaceList.append(face)
except:
print ('skip ' + face)
#print errorFaceList
mc.select(errorFaceList)
getRecessedFace()

2016年1月4日月曜日

centos7 rc.localからだと起動スクリプトがうごかない。。。

以前svnserveを導入した際、rc.localにsvnserveの起動スクリプトを記述して、
サーバーの起動時にsvnserveが自動的に立ち上がるように設定したのですが、
単にこれだけだと、自動起動してくれないことが分かりました。

実は、centos7から従来のrc.localにとる起動スクリプト管理ではなく、systemedにて
起動スクリプトの管理を行うようになったようです。

…てか、本にもそう書いてあった。全然読んでないじゃん。orz


起動スクリプトの管理方法は、他サイト様にていろいろ紹介されてありますが、
方法は2つ。
①rc.localを従来通り使うか
②systemedに乗り換えるか

です。

①に関しては、単にrc.localに実行権限を与えてあげるだけでOK。
実際やってみて、OKでした。

chmod u+x /etc/rc.d/rc.local

参考サイト:http://kantaro-cgi.com/blog/etc-server/cant_run_rclocal_centos7.html

②に関しては、
 ・専用シェルスクリプトを用意し、
 ・「/etc/systemd/systemの下に、拡張子が .serviceのテキストファイルを作る。」
   →参考サイト:tire.retire ガジェット好きおじさんの日記 より引用
 ・systemedに登録してあげる。

参考サイト:http://tire-retire.blogspot.jp/2014/12/centos7rclocal.html
参考サイト:http://motw.mods.jp/shellscript/tutorial.html

僕は①を試したのち、今後のことも考えて、systemedの対応を進めてみました。
シェルスクリプトは書いたことがありませんでしたが、初心者の自分にも難しくはなかったです。

ただ、現状まだうまく自動起動設定ができていない状態です。
systemedはサービスの起動順序をいろいろ指定できるのですが、依存関係にあるサービスが立ち上がる前にsvnserveの自動起動スクリプトが実行されているのではないか、と考えています。

今のところ、現状サーバー再起動時に再度立ち上げないといけないものは少ないので、
しばらく手動で対応しますが、頃合いをみて再挑戦したいところです。