mayaのブーリアンで虚無が生まれるので雑な奴を自作

maya2024からブーリアンが改修されたようなのですが、
まだ2022をメインでやってるもので

ブーリアンが難しい
-
コツというか、未だその辺をつかめていないので
ブーリアン実行！ってやると大体虚無が生まれるんですよね。

時間がない時だと、えーあーもういいやブーリアンあきらめよう！
ってなってしまいがち。

今回もそうなってしまいましたが、処理する数が多かったので
**メッシュがスフィアの中に収まるようにスフィアの外側にはみ出た部分を何とかする**

というパワー　な処理を作ってなんとかしました。

設計
-

ターゲットはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/363da47b-e5f4-e84d-6449-a0b420a82b05.png)

スフィア（切り取りオブジェクト）から

**外にはみ出てるメッシュを削除したい。**

または

**外にはみ出てるメッシュを内側に押し込めたい**

パッと思いついたのはshrinkWrapですが、
はみ出てる部分を判別できない事にはなぁ・・・・

**vtxが切り取りオブジェクトの外にいるかうちにいるか**
を判別出来ればあとは煮るなり焼くなりにのみやかｚ

凄く雑に考えると
- vtxの位置から全軸の方向にレイを飛ばす
- レイが1か所でも切り取りオブジェクトにヒットしない場合は外
- レイが全て切り取りオブジェクトにヒットした場合は内

でいいかなぁ。
まぁ切り取りオブジェクトが複雑な形状だと法線とかもみないと駄目かなと思いますが、今回はシンプルな形状なので。

雑に実装
-

```python
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)
```
ぱっと見は・・・・・大丈夫そうかな？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/c33cebb1-72c7-b82b-3da1-98053da05880.png)

あとはこのvtxを元にポリゴンを削除するなり、shrinkWrapでスフィアにくっつけるなりすれば
虚無は回避できそうですわね

shrikWrapするとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/9649d003-c6f3-0ea2-9d18-577967995b88.png)


実際の運用時には
- 外のvtxをfaceに変換
- 変換したfaceを削除
- 削除後にも外側に残ってるvtxを再取得
- そのvtxを切り取りオブジェクトの最近接点にスナップ

までを処理させて対応しました。