maya2024からブーリアンが改修されたようなのですが、
まだ2022をメインでやってるもので
ブーリアンが難しい
コツというか、未だその辺をつかめていないので
ブーリアン実行!ってやると大体虚無が生まれるんですよね。
時間がない時だと、えーあーもういいやブーリアンあきらめよう!
ってなってしまいがち。
今回もそうなってしまいましたが、処理する数が多かったので
メッシュがスフィアの中に収まるようにスフィアの外側にはみ出た部分を何とかする
というパワー な処理を作ってなんとかしました。
設計
スフィア(切り取りオブジェクト)から
外にはみ出てるメッシュを削除したい。
または
外にはみ出てるメッシュを内側に押し込めたい
パッと思いついたのはshrinkWrapですが、
はみ出てる部分を判別できない事にはなぁ・・・・
vtxが切り取りオブジェクトの外にいるかうちにいるか
を判別出来ればあとは煮るなり焼くなりにのみやかz
凄く雑に考えると
- vtxの位置から全軸の方向にレイを飛ばす
- レイが1か所でも切り取りオブジェクトにヒットしない場合は外
- レイが全て切り取りオブジェクトにヒットした場合は内
でいいかなぁ。
まぁ切り取りオブジェクトが複雑な形状だと法線とかもみないと駄目かなと思いますが、今回はシンプルな形状なので。
雑に実装
import maya.cmds as cmds
import maya.api.OpenMaya as om
def getDagNode(target):
try:
sellist = om.MGlobal.getSelectionListByName(target)
return sellist.getDagPath(0)
except:
return None
def stringToVector(axis):
if axis == "x":
return om.MVector.kXaxisVector
elif axis == "y":
return om.MVector.kYaxisVector
elif axis == "z":
return om.MVector.kZaxisVector
elif axis == "-x":
return om.MVector.kXnegAxisVector
elif axis == "-y":
return om.MVector.kYnegAxisVector
elif axis == "-z":
return om.MVector.kZnegAxisVector
def checkVtxInside(vtx,mesh):
meshDagPath = getDagNode(mesh)
shapeFn = om.MFnMesh(meshDagPath)
position = cmds.xform(vtx , q =True , ws = True, t =True)
raySource = om.MFloatPoint(*position)
space = om.MSpace.kWorld
id_list = []
point_list = []
isInside = True
for axis in ["x","y","z","-x","-y","-z"]:
#vtxの位置から全軸方向へrayをとばす
axisVector = stringToVector(axis)
maxParam = 9999
testBothDirections = False
accelParams=om.MMeshIsectAccelParams()
result = shapeFn.closestIntersection(
raySource,
om.MFloatVector(axisVector),
space,
maxParam,
testBothDirections, idsSorted=False, accelParams=accelParams, tolerance=0.0001)
if result == None:
isInside = False
break
return isInside
def getOutsideVtx(checkTarget,clipGuide):
meshDagPath = getDagNode(checkTarget)
shapeFn = om.MFnMesh(meshDagPath)
outsideVtx = []
for i in range(0,shapeFn.numVertices):
#ターゲットのvtxを順番に処理
isInside = checkVtxInside(checkTarget +".vtx["+str(i)+"]",clipGuide)
if isInside == False:
outsideVtx.append(checkTarget +".vtx["+str(i)+"]")
return outsideVtx
checkTarget = "pCube1"
clipGuide = "pSphere1"
outsideVtx = getOutsideVtx(checkTarget,clipGuide)
cmds.select(outsideVtx,r =True)
あとはこのvtxを元にポリゴンを削除するなり、shrinkWrapでスフィアにくっつけるなりすれば
虚無は回避できそうですわね
実際の運用時には
- 外のvtxをfaceに変換
- 変換したfaceを削除
- 削除後にも外側に残ってるvtxを再取得
- そのvtxを切り取りオブジェクトの最近接点にスナップ
までを処理させて対応しました。