2018年6月3日日曜日

選択したエッジを延長した先の交点を求める

選択したエッジを延長し、その交点で頂点をマージしたいという要望が会社でありました。
ベクトルを使えば簡単に解決できそうな感じがしましたが、気になったので調査してみました。
以下ソース
import maya.cmds as mc
import maya.api.OpenMaya as om2
def getVectorValue(pointA=[0.0,0.0,0.0],pointB=[0.0,0.0,0.0]):
tmpVecA = om2.MVector(pointA)
tmpVecB = om2.MVector(pointB)
return tmpVecB-tmpVecA
def getCrossPoint2Edge(vtxNamePist=[[]]):
result=[]
edgeVecAB = om2.MVector()
edgeVecCD = om2.MVector()
edgeVecAC = om2.MVector()
vtxList=[]
vtxList.append([mc.pointPosition(vtx,w=True) for vtx in vtxNamePist[0]])
vtxList.append([mc.pointPosition(vtx,w=True) for vtx in vtxNamePist[1]])
edgeVecAB = getVectorValue(vtxList[0][0],vtxList[0][1])
edgeVecCD = getVectorValue(vtxList[1][0],vtxList[1][1])
edgeVecAC = getVectorValue(vtxList[0][0],vtxList[1][0])
nAB = edgeVecAB.normal()
nCD = edgeVecCD.normal()
work1 = nAB*nCD;
work2 = 1 - work1*work1;
if work2==0.0:
mc.warning('2 edge is Concurrent')
return 0
d1 = ((edgeVecAC*nAB)-work1*(edgeVecAC*nCD))/ work2
d2 = (work1*(edgeVecAC*nAB)-(edgeVecAC*nCD))/ work2
result.append([vtxList[0][0][0]+d1*nAB.x,
vtxList[0][0][1]+d1*nAB.y,
vtxList[0][0][2]+d1*nAB.z])
result.append([vtxList[1][0][0]+d2*nCD.x,
vtxList[1][0][1]+d2*nCD.y,
vtxList[1][0][2]+d2*nCD.z])
return result
def connect2Edge(Threshold=0.001):
nodeList = mc.ls(sl=True,fl=True)
edgeList = mc.polyListComponentConversion(nodeList,te=True)
edgeList = mc.ls(edgeList,fl=True)
vtxList = []
vtxList.extend([mc.ls(mc.polyListComponentConversion(edgeList[0],tv=True),fl=True)])
vtxList.extend([mc.ls(mc.polyListComponentConversion(edgeList[1],tv=True),fl=True)])
print vtxList
crossPoints = getCrossPoint2Edge(vtxList)
crossPointA = om2.MVector(crossPoints[0])
crossPointB = om2.MVector(crossPoints[1])
rezPoint = crossPointA - crossPointB
if rezPoint.length()>Threshold:
mc.warning('Cannot Cross.')
return -1
editPoints = []
for points in vtxList:
vec1 = om2.MVector(mc.pointPosition(points[0],w=True))
vec2 = om2.MVector(mc.pointPosition(points[1],w=True))
chk1 = crossPointA-vec1
chk2 = crossPointA-vec2
if chk1.length()<chk2.length():
editPoints.append(points[0])
else:
editPoints.append(points[1])
editPoints=list(set(editPoints))
print editPoints
if len(editPoints)<2:
mc.warning('Already connect edges.')
return 0
for vtx in editPoints:
mc.move(crossPoints[0][0],crossPoints[0][1],crossPoints[0][2],vtx,ws=True,wd=True)
return 1
connect2Edge()
view raw connectEdge hosted with ❤ by GitHub
コードと考え方は以下を参考にしました。 http://www.sousakuba.com/Programming/gs_two_lines_intersect.html 
大変わかりやすく解説されています。 

このソースでは、選択したエッジの交点を求め、近いほうの頂点をその座標へ移動するまでとなっていますが、処理の根幹としては十分かと。

うん、やっぱベクトルってべんりだなーと…。

2018年5月26日土曜日

namespaceを指定してFBXインポート

手動で行う分には問題なく行える操作ですが、スクリプトで実行しようとしたとき、若干はまりポイントだと思うので、メモを。
以下ソース
# -*- coding: utf-8 -*-
import maya.cmds as mc
import maya.mel as mel
def FBXImportToTargetNamespace(ns='targetNamespace'):
#set namespace
currentNs = mc.namespaceInfo(cur=True)
if not mc.namespace(ex=':%s'%ns):
mc.namespace(add=':%s'%ns)
mc.namespace(set=':%s'%ns)
#import FBX
pathList = mc.fileDialog2(fm=1,ds=2,ff=('FBX(*.fbx)'))
if not pathList:
return
mel.eval('FBXImport -f "%s"'%pathList[0])
#return current ns
mc.namespace(set=currentNs)
FBXImportToTargetNamespace(ns='testNs')

fileコマンドからインポートした時、namespaceを指定しても無反応。
カレントネームスペースを設定したうえでインポートするところがポイント。

2018年5月17日木曜日

Maya2017 systemからフォルダを開くと無限ループで落ちるMayaバグ

無印Maya2017では起こらなかったのですが、Maya2017 update4で以下ソースを実行すると、落ちます。
proc testProc(){
string $userYN = `confirmDialog -b "OK"`;
if ($userYN == "OK"){
system("load C:\Autodesk");
}
}

systemからエクスプローラーでダイアログを開こうとすると、なぜか処理がconfirmDialogのところへ戻って、以下無限ループ。
キャンセルなどして、systemの処理をスキップしようとすると、Mayaが固まって落ちました。

処理をpythonに逃がして対応できないかと模索したところ、
os.startfileの処理では、同様の結果となり、Mayaが落ちました。
しかし、subprocess.popenから処理を行ったところ、無事にクラッシュを回避できました。(以下ソース)
proc testProc(){
string $userYN = `confirmDialog -b "YES"`;
if ($userYN == "YES"){
string $path = "C:\Autodesk";
python("import subprocess");
python("subprocess.Popen('explorer \""+$path+"\"')");
//system("load C:\Autodesk");
}
}
testProc();

subprocessとos、melのsystemの大きな違いは、既定値でshellへ処理を飛ばすかどうか。
subprocessは既定ではshellで処理をしなかったはずなので、そのあたりに原因があるかも。

なお、最新のMaya2017 update5で発生するかどうかは未検証。 後日もう少し探ってみることにする。

2018年5月6日日曜日

OpenMaya:頂点処理の速度比較

以前海外の記述で見つけた記述を参考に、選択頂点で、設定値より近接している頂点の検索処理を、OpenMayaとmayaPythonで比較してみました。

処理内容はどちらも
①選択頂点の座標を取得
②openMayaのMVectorクラスを使って閾値以上近接している頂点を検索
③エラーがあればリストに格納して返す

以下ソース
mayaPython
import maya.cmds as mc
import maya.api.OpenMaya as om2
def checkNearVtx():
errorList=[]
vtxList = mc.ls(sl=True,fl=True)
vtxList2 = vtxList[:]
for vtx1 in vtxList:
pos1 = mc.pointPosition(vtx1)
vec1 = om2.MVector(pos1)
for vtx2 in vtxList2:
if vtx1 == vtx2:
continue
pos2 = mc.pointPosition(vtx2)
vec2 = om2.MVector(pos2)
vec3 = vec1-vec2
if vec3.length()<0.001:
errorList.extend([vtx1,vtx2])
vtxList2.remove(vtx1)
return errorList
start = time.time()
print checkNearVtx()
elapsed_time = time.time() - start
print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")
view raw checkNearVtx hosted with ❤ by GitHub
openMaya
#_ Import required modules
import maya.cmds as mc
import maya.api.OpenMaya as om2
import time
def retunrnSelectVtxPos():
orgSelection = mc.ls(sl=True)
#getVtx IndxList
tmp = mc.polyListComponentConversion(orgSelection,tv=True)
selVtxList = mc.ls(tmp,fl=True)
selVtxList = sorted(selVtxList)
selDict = {}
for vtx in selVtxList:
shape = vtx.split('.')[0]
if not shape in selDict.keys():
selDict[shape] = []
indx = int(vtx.split('[')[-1].split(']')[0])
selDict[shape].append(indx)
returnDict={}
for shape in selDict.keys():
mc.select(shape)
selection = om2.MGlobal.getActiveSelectionList()
selObj = selection.getDagPath(0)
mfnObject = om2.MFnMesh(selObj)
posList = mfnObject.getPoints(om2.MSpace.kWorld)
returnDict[shape]=[]
for vtx in selDict[shape]:
returnDict[shape].append([vtx,posList[vtx]])
mc.select(orgSelection)
return returnDict
def checkNearVtxList(vtxDict):
errorList=[]
for key in vtxDict.keys():
MposList = vtxDict[key]
MposList2 = MposList[:]
for vtxInfo1 in MposList:
indx1 = vtxInfo1[0]
vec1 = om2.MVector(vtxInfo1[1])
for vtxInfo2 in MposList2:
indx2 = vtxInfo2[0]
if vtxInfo1==vtxInfo2:
continue
vec2 = om2.MVector(vtxInfo2[1])
vec3 = vec1-vec2
if vec3.length()<0.001:
vtx1 = '%s.vtx[%s]'%(key,indx1)
vtx2 = '%s.vtx[%s]'%(key,indx2)
errorList.extend([vtx1,vtx2])
MposList2.remove(vtxInfo1)
errorList = list(set(errorList))
return errorList
start = time.time()
dict = retunrnSelectVtxPos()
print checkNearVtxList(dict)
elapsed_time = time.time() - start
print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")

で、結果。
mayaPythonの結果: elapsed_time:1.26999998093[sec]
openMayaの結果: elapsed_time:0.103000164032[sec]

うーん! これだけで10倍以上の処理速度の差が。
 ソースはもっと洗練できると思う。 もっと早くなるんじゃないだろか。
参考;
http://jensvhansen.com/fastest-way-to-query-vertex-position-in-maya/
https://boomrigs.com/blog/2016/1/12/how-to-get-mesh-vertex-position-through-maya-api

2018年4月30日月曜日

OpenMaya:現在のビューポートからフェースを選択する

大分前にopenMayaを使って、現在のビューポートからフェースを選択するコードを書いたのですが、 どこかに行ってしまい、参考にした海外の書き込みも見当たらず、どーしたもんかと思っていたところ、 ようやく見つけました。
def faceListFromView():
mc.select( all=True )
mc.selectMode(component=True )
mc.selectType( facet=True )
mc.hilite()
view = OMU.M3dView.active3dView()
OM.MGlobal.selectFromScreen(0, 0, view.portWidth(),
view.portHeight(), OM.MGlobal.kReplaceList)
FACE_LIST = cmds.ls(sl=True,fl=True)
return FACE_LIST
こんどこそ忘れないように。 ※後になって参考にした書き込みを発見…はやくいってよぉ…。
参考:http://forums.cgsociety.org/archive/index.php?t-1045968.html

なお、元ソースを探してさまよっていた際、porySelectConstraintを使った方法を紹介している記述を見つけたので、試してみました。
def selectFromcamera(cam=None):
if not cam:
return
pos = mc.xform(cam,q=True,ws=True,wd=True,t=True)
#pos = mc.getAttr('%s.translate'%cam)[0]
mc.polySelectConstraint(m=3,t=0x0008,v=True,va=90,vp=pos)
mc.polySelectConstraint(m=0,v=False)
参考:https://forum.highend3d.com/t/select-polygons-facing-camera/2782/3
しかし、使ってみると、こちらはポリゴンメッシュ内部にカメラがめり込むと、そのポリゴンメッシュが選択不能になってしまったので、openMaya経由のほうが無難に使えました。

2018年3月27日火曜日

現在のアクティブなシェルフを取得する

作ったToolのボタンをシェルフに登録したい。
ShelfLayoutをそもそも使っていれば何の問題もないけど、
さまざまな理由から、遠回りをしたいとき。

例えば右クリック⇒現在のMayaシェルフに登録などさせる場合、
現在アクティブなシェルフレイアウトの名前を取得したい。

そんな時はこちら。

proc string getActiveShelfLayout(){
string $uiList[] = `lsUI -type "shelfLayout"`;
string $tabList[] = `lsUI -type "tabLayout"`;
if (!(stringArrayFind("ShelfLayout",0,$tabList))) return "";
string $tl=`tabLayout -q -st "ShelfLayout"`;
if (!(stringArrayFind($tl,0,$uiList))) return "";
return $tl;
}
print getActiveShelfLayout;