LoginSignup
3
2

More than 1 year has passed since last update.

draggerContext を使ってみた

Last updated at Posted at 2021-12-01

カーソルの軌跡に沿ってナーブスカーブを編集してみたかったので、
draggerContextを使ってやってみた。

まずはdraggerContextを下調べ

projection

  • viewPlane (ビュー プレーンに投影)
  • objectViewPlane ((ビュー プレーンと平行な)オブジェクト プレーンに投影)
  • objectPlane (オブジェクトの位置と法線(既定)0,1,0 で定義した指定プレーンに投影)
  • plane (原点と法線(既定)0,1,0 で定義した指定プレーンに投影)
  • sketchPlane (スケッチ プレーンに投影)
  • xAxis (X 軸上の最近接ポイントに投影)
  • yAxis (Y 軸上の最近接ポイントに投影)
  • zAxis (Z 軸上の最近接ポイントに投影)
  • boundingSphere (オブジェクト球の境界上の最近接ポイントに投影)
  • boundingBox (オブジェクト バウンディング ボックス上の最近接ポイントに投影)

この辺がよく判らないので、細々検証したい。
ざっくりと検証用のツールを作成

import maya.cmds as cmds
def pressCommand_test():
    pressPosition = cmds.draggerContext(toolName, query=True, anchorPoint=True)    
    print("start position" + str(pressPosition))

def dragCommand_test():
    dragPosition = cmds.draggerContext( toolName, query=True, dragPoint=True)
    print(str(dragPosition))
    node = cmds.spaceLocator()[0]
    cmds.setAttr(node + ".t", *dragPosition)

def releaseCommand_test():
    pass

toolName = "hogeTool"

if cmds.draggerContext(toolName,q =True, exists=True):
    cmds.deleteUI(toolName)

cmds.draggerContext(toolName,
                    projection = "plane",
                    pressCommand = "pressCommand_test()",
                    dragCommand = "dragCommand_test()",
                    releaseCommand = "releaseCommand_test()",
                    space = "world"
)

cmds.setToolTo(toolName)

perspカメラ越しに実行してみて、結果を確認

viewPlane
現在のカメラのviewPlane上に投影し、3次元上の位置情報を取得
image.png

objectViewPlane
image.png

objectPlane / plane
image.png

オプションを変えてみて判ったことは

  • space を wolrdにしているので3次元上の座標になるが、screenにするとこでビューポートの左下を0,0としたX,Y座標を取得できる

  • オブジェクトの指定方法がよく変わらない

その上でnurbsCurveをどうこうしたい

どうこうしたいので、どうしよう。
ざっくりと考えるとこんな感じかしら?

image.png

カメラ = A CV 元位置 = B ストローク上 = C CV 移動先 = P と置きなおすと
image.png

ベクトルAC を ABと同じ長さになるように延長した点をPとする

必要になってくるのは

  • A:カメラ位置
    これで現在のカメラを取得できそう。
    OpenMayaUI.M3dView.active3dView().getCamera()

    cam_MFnTransIns = om2.MFnTransform(om2.MFnDagNode(omui.M3dView.active3dView().getCamera().transform()).getPath())
    cam_position = cam_MFnTransIns.translation(om2.MSpace.kWorld)
    
  • C:viewPlane上のストローク座標
    draggerContext で projecction = viewPlane かつ space = world で取得可能

  • B:CVの元位置
    xfromあたりで取得

点Cの定義

ストローク上の点は沢山取得できるけれども、どれを点Cとして定義しようか?

  • ストロークの各ポイントからパラメーター位置を割り出す

  • CVのworld位置をビューポート上の2次元位置に変換して、ストロークの最近接点を割り出す

  • ストローク上の点を採用してnurbsCurveを生成、rebuildで元Curveと諸々合わせてCV位置を取得

軌跡の描画も兼ねさせてしまいたいので、3つ目を採用
pressCommand
- ストロークのカーブがあったら削除
- クリックした点を取得

draggCommand
- ストロークのカーブが無ければ作成
- ある場合はポイントをappendしていく

releaseCommand
- 最初に選択していたカーブに合わせて degree / spans を取得し、rebuild

pressPosition = []
tmpCurveName = "tempCurve"
selectCurve = ""
toolName = "hogeTool"

def draggerEditCurve_pressCommand():
    global pressPosition
    pressPosition = cmds.draggerContext(toolName, query=True, anchorPoint=True)    
    if cmds.objExists(tmpCurveName):
        cmds.delete(tmpCurveName)

def draggerEditCurve_dragCommand():
    dragPosition = cmds.draggerContext( toolName, query=True, dragPoint=True)

    if cmds.objExists(tmpCurveName):
        cmds.curve(tmpCurveName , p = [dragPosition], append =True)
    else:
        cmds.curve(name = tmpCurveName , p = [pressPosition,dragPosition], d = 1, bezier = False, periodic = False)

    cmds.refresh()

def draggerEditCurve_releaseCommand(selectCurve):    
    degree = cmds.getAttr(selectCurve + ".degree")
    spans = cmds.getAttr(selectCurve + ".spans")    
    cmds.rebuildCurve(tmpCurveName,ch =False, degree = degree,rebuildType = 0,spans = spans,replaceOriginal = True,keepRange =0)

def draggerEditCurveTool():
    selectCurve = cmds.ls(sl =True)[0]

    if cmds.draggerContext(toolName,q =True, exists=True):
        cmds.deleteUI(toolName)

        cmds.draggerContext(toolName,
                        projection = "viewPlane",
                        pressCommand = "draggerEditCurve_pressCommand()",
                        dragCommand = "draggerEditCurve_dragCommand()",
                        releaseCommand = "draggerEditCurve_releaseCommand(\""+selectCurve+"\")",
                        space = "world"
    )

    cmds.setToolTo(toolName)

draggerEditCurveTool()

点Pの定義

2種類のカーブとカメラの位置から、最終的な移動地点を定義する。

def getDistPoint(sourceCurve,targetCurve):
    cam_MFnTransIns = om2.MFnTransform(om2.MFnDagNode(omui.M3dView.active3dView().getCamera().transform()).getPath())
    cam_position = om2.MVector(cam_MFnTransIns.translation(om2.MSpace.kWorld))    
    sourceCurve_dagPath = om2.MGlobal.getSelectionListByName(sourceCurve).getDagPath(0)

    if sourceCurve_dagPath.hasFn(om2.MFn.kNurbsCurve):
        sourceCurve_shapeFn = om2.MFnNurbsCurve(sourceCurve_dagPath)

    all_ids = []
    for i in range(0,sourceCurve_shapeFn.numCVs):
        all_ids.append(i)

    sourceCurve_comp = [sourceCurve + '.cv[' + str(vid) + ']'for vid in all_ids]
    targetCurve_comp = [targetCurve + '.cv[' + str(vid) + ']'for vid in all_ids]

    for sourceCurve_cv,targetCurve_cv in zip(sourceCurve_comp,targetCurve_comp):
        sourceCurve_cv_position = om2.MVector(cmds.xform(sourceCurve_cv,q =True,ws =True, t=True))
        targetCurve_cv_position = om2.MVector(cmds.xform(targetCurve_cv,q =True,ws =True, t=True))
        curPoint_vect = targetCurve_cv_position - cam_position
        curPoint_length = curPoint_vect.length()
        point_vect = sourceCurve_cv_position - cam_position
        point_vect = point_vect.normal()
        dist_vect = point_vect * curPoint_length
        dist_position = cam_position + dist_vect
        cmds.xform(targetCurve_cv,ws =True, t=dist_position)

結合

細々と作ってきたものをまとめるとこんな感じ。
なにかしらカーブを選択して実行。

import maya.cmds as cmds
import maya.api.OpenMaya as om2
import maya.api.OpenMayaUI as omui

pressPosition = []
tmpCurveName = "tempCurve"
toolName = "draggerEditCurveTool"

def getDistPoint(sourceCurve,targetCurve):
    cam_MFnTransIns = om2.MFnTransform(om2.MFnDagNode(omui.M3dView.active3dView().getCamera().transform()).getPath())
    cam_position = om2.MVector(cam_MFnTransIns.translation(om2.MSpace.kWorld))        
    sourceCurve_dagPath = om2.MGlobal.getSelectionListByName(sourceCurve).getDagPath(0)

    if sourceCurve_dagPath.hasFn(om2.MFn.kNurbsCurve):
        sourceCurve_shapeFn = om2.MFnNurbsCurve(sourceCurve_dagPath)

    all_ids = []
    for i in range(0,sourceCurve_shapeFn.numCVs):
        all_ids.append(i)

    sourceCurve_comp = [sourceCurve + '.cv[' + str(vid) + ']'for vid in all_ids]
    targetCurve_comp = [targetCurve + '.cv[' + str(vid) + ']'for vid in all_ids]

    for sourceCurve_cv,targetCurve_cv in zip(sourceCurve_comp,targetCurve_comp):
        sourceCurve_cv_position = om2.MVector(cmds.xform(sourceCurve_cv,q =True,ws =True, t=True))
        targetCurve_cv_position = om2.MVector(cmds.xform(targetCurve_cv,q =True,ws =True, t=True))
        curPoint_vect = targetCurve_cv_position - cam_position
        curPoint_length = curPoint_vect.length()
        point_vect = sourceCurve_cv_position - cam_position
        point_vect = point_vect.normal()
        dist_vect = point_vect * curPoint_length
        dist_position = cam_position + dist_vect
        cmds.xform(targetCurve_cv,ws =True, t=dist_position)

def draggerEditCurve_pressCommand():
    global pressPosition
    pressPosition = cmds.draggerContext(toolName, query=True, anchorPoint=True)    
    if cmds.objExists(tmpCurveName):
        cmds.delete(tmpCurveName)

def draggerEditCurve_dragCommand():
    dragPosition = cmds.draggerContext( toolName, query=True, dragPoint=True)

    if cmds.objExists(tmpCurveName):
        cmds.curve(tmpCurveName , p = [dragPosition], append =True)
    else:
        cmds.curve(name = tmpCurveName , p = [pressPosition,dragPosition], d = 1, bezier = False, periodic = False)
    cmds.refresh()

def draggerEditCurve_releaseCommand(selectCurve):    
    degree = cmds.getAttr(selectCurve + ".degree")
    spans = cmds.getAttr(selectCurve + ".spans")    
    cmds.rebuildCurve(tmpCurveName,ch =False, degree = degree,rebuildType = 0,spans = spans,replaceOriginal = True,keepRange =0)    
    getDistPoint(tmpCurveName,selectCurve)    
    cmds.select(selectCurve,r =True)
    cmds.delete(tmpCurveName)

def draggerEditCurveTool():
    selectCurve = cmds.ls(sl =True)[0]

    if cmds.draggerContext(toolName,q =True, exists=True):
        cmds.deleteUI(toolName)

    cmds.draggerContext(toolName,
                            projection = "viewPlane",
                            pressCommand = "draggerEditCurve_pressCommand()",
                            dragCommand = "draggerEditCurve_dragCommand()",
                            releaseCommand = "draggerEditCurve_releaseCommand(\""+selectCurve+"\")",
                            space = "world"
        )

    cmds.setToolTo(toolName)

draggerEditCurveTool()

現行だとopen以外のカーブは対応してなかったりとか色々限定的ではあるので、後々アップデートしたいなぁ

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2