カーソルの軌跡に沿ってナーブスカーブを編集してみたかったので、
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次元上の位置情報を取得
オプションを変えてみて判ったことは
-
space を wolrdにしているので3次元上の座標になるが、screenにするとこでビューポートの左下を0,0としたX,Y座標を取得できる
-
オブジェクトの指定方法がよく変わらない
その上でnurbsCurveをどうこうしたい
どうこうしたいので、どうしよう。
ざっくりと考えるとこんな感じかしら?
カメラ = A CV 元位置 = B ストローク上 = C CV 移動先 = P と置きなおすと
ベクトル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以外のカーブは対応してなかったりとか色々限定的ではあるので、後々アップデートしたいなぁ