ON-BLOG

CGのこと、あれこれ書いてます。

膝パーツの組み方

よくある事例なんですが、いつも接続で?ってなるのでメモ。

画像みたいに、ひざにパーツがついてる時があります。
特にメカ系なんかに多いんですが…
f:id:tommy_on:20180529221831p:plain

これを足の骨だけでそのまま回すと
こうなるかと思います。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
f:id:tommy_on:20180529221849p:plain

このままだと、硬い物等で違和感が生じる為、骨を足して
処理を追加します。
※膝と同階層に
画像のように配置します。
f:id:tommy_on:20180529221900p:plain

ウェイトは繋がっていない限り、パーツに全振りします。
んで、この骨に対して接続を行います。
f:id:tommy_on:20180529221928p:plain

※デモの為、jointOrientをしていません汗・・・・
kneeの回転値Zを各【remapvalue】の【入力値】に接続し、出力値をnodeとしいう階層に接続してます。
この出力値は、追加した骨を拘束しており、ドリブンされています。
とりあえず、【TX】ノードの接続をみていきます。
f:id:tommy_on:20180529221941p:plain


基本的には画像の通り。
膝の回転値を変換して、最大は動かないように【0】にして最小の値を【-1】にしています。
このように他のチャンネルにも接続すると、

Knee_Rig from tommy_on on Vimeo.

このような挙動になります。
はじめはclampノードを使っていたんですが
clampだと、リミット時にカクッとなる為
代案を考えておりました。
いろんなデータを落としたりしてる中で、IKFKの切り替えで
【remapvalue】を使っている所を確認したので
試した所きれいにいったのでこれをつかってます。
先人達には感謝がつきませんね…



では… 

NameSpaceをすべて削除

リグ組んでたり、アニメーションを読み込みしてたりすると
偶にネームスペースが邪魔になることがある。
その都度一々、ネームスペースエディタを開いていたら
面倒なので、マクロを作りました。
※家用。

# -*- encoding: utf-8 -*-
import maya.cmds as cmds
def main():
    NameSpace = cmds.namespaceInfo(recurse=1,listOnlyNamespaces=1)
    NameSpace.remove(u'UI')
    NameSpace.remove(u'shared')
    if len(NameSpace) > 0:
        for i in NameSpace:
            cmds.namespace(mergeNamespaceWithRoot = True , removeNamespace = i)
        cmds.headsUpMessage( u'NameSpaceを削除しました', verticalOffset=20 )
    else:
        print "NotNameSpace"


今後は指定したやつだけ残す機能とか付けたい。

以上です。

カメラを作成

スクリプトからカメラを作るコード。
これ自体はなんら意味のないものですが
これに色々載せると、自由なカメラリグに。

というか、Aimカメラの作り方がわからなかったので
それを実行しただけですが…


def Normal_Camera(self):
    cameraName = cmds.camera()
    cmds.select(cameraName[0])
    Sel = cmds.ls(sl=True)[0]
    Camera = cmds.rename(cameraName[0],"Camera")
    cmds.setAttr(Camera + "Shape.horizontalFilmAperture",0.935)
    cmds.setAttr(Camera + "Shape.filmFit",1)
    cmds.setAttr(Camera + "Shape.focalLength",float(55))
    cmds.setAttr(Camera + "Shape.locatorScale",10)
    cmds.setAttr(Camera + ".rotateY", 0)
    cmds.select(cl=True)

def Aim_Camera(self):
    cameraName = cmds.camera()
    cmds.select(cameraName[0])
    Sel = cmds.ls(sl=True)[0]
    Camera = cmds.rename(cameraName[0],"Aim_Camera")
    cmds.setAttr(Camera + "Shape.horizontalFilmAperture",0.935)
    cmds.setAttr(Camera + "Shape.filmFit",1)
    cmds.setAttr(Camera + "Shape.focalLength",float(20))
    cmds.setAttr(Camera + "Shape.locatorScale",10)
    GrpCam = cmds.createNode('lookAt',n="Camera_Set_grp")
    AimLoc = cmds.spaceLocator(n="Aim")[0]
    cmds.setAttr(AimLoc + ".translateZ", -50)

    cmds.parent(Camera,GrpCam)
    cmds.parent(AimLoc,GrpCam)
    cmds.connectAttr(GrpCam + ".distanceBetween", Camera + "Shape.centerOfInterest")
    cmds.connectAttr(AimLoc + ".translateX", GrpCam + ".target[0].targetTranslateX")
    cmds.connectAttr(AimLoc + ".translateY", GrpCam + ".target[0].targetTranslateY")
    cmds.connectAttr(AimLoc + ".translateZ", GrpCam + ".target[0].targetTranslateZ")
    cmds.connectAttr(AimLoc + ".parentMatrix[0]", GrpCam + ".target[0].targetParentMatrix")
    cmds.connectAttr(AimLoc + ".rotatePivot", GrpCam + ".target[0].targetRotatePivot")
    cmds.connectAttr(AimLoc + ".rotatePivotTranslate", GrpCam + ".target[0].targetRotateTranslate")
    cmds.connectAttr(Camera + ".translate", GrpCam + ".constraintTranslate")
    cmds.connectAttr(Camera + ".parentInverseMatrix[0]", GrpCam + ".constraintParentInverseMatrix")
    cmds.connectAttr(Camera + ".rotatePivot", GrpCam + ".constraintRotatePivot")
    cmds.connectAttr(Camera + ".rotatePivotTranslate", GrpCam + ".constraintRotateTranslate")
    cmds.connectAttr(GrpCam + ".constraintRotateX", Camera + ".rotateX")
    cmds.connectAttr(GrpCam + ".constraintRotateY", Camera + ".rotateY")
    cmds.connectAttr(GrpCam + ".constraintRotateZ", Camera + ".rotateZ")

    cmds.setAttr(GrpCam + ".aimVectorZ", -1)
    cmds.setAttr(GrpCam + ".aimVectorX", 0)
    cmds.setAttr(AimLoc + "Shape.localScaleX", 10)
    cmds.setAttr(AimLoc + "Shape.localScaleY", 10)
    cmds.setAttr(AimLoc + "Shape.localScaleZ", 10)
    
Normal_Camera(None)
Aim_Camera(None)


以上。

名前変更

まぁよくあるやつ。
何回書いたことか…

って事で今後ググらないように、雛形をここにメモ。

import os
import glob

#パス指定
path = "D:/demo"
#拡張子FBXだけ取得
files = glob.glob(path + '/*.fbx')

for f in files:
 #例題
    #player_mot_0000.fbx
    #↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    #enemy_mot_0000.fbx
 #頭6文字を置き換え
    os.rename(f, os.path.join(path, 'enemy' + os.path.basename(f)[6:]))

以上。

animCurveについてメモ

animCurveについてメモ。
いつもいつもあれ?なんだっけ?
ってなるんで、メモ代わりに残こそうかと。

ヘルプを見るとこれだけあります。
animCurve
animCurveTA
animCurveTL
animCurveTT
animCurveTU
animCurveUA
animCurveUL
animCurveUT
animCurveUU


以下が説明。

animCurve・・・・・・・・アニメーションカーブ全部
animCurveTA・・・・・ローテーションのカーブ
animCurveTL・・・・・トランスレーションのカーブ
animCurveTT・・・・・Timeなどのカーブ
animCurveTU・・・・・スケールとビジビリティのカーブ
※頭の【T】は【Time】なので、アニメーションを表す。

animCurveUA・・・・・ドリブンキーのローテーションカーブ
animCurveUL・・・・・ドリブンキーのトランスレーションカーブ
animCurveUT・・・・・ドリブンキーのTimeカーブ
animCurveUU・・・・・ドリブンキーのスケールとビジビリティカーブ
※頭の【U】は【Double】なので許容桁数が多い少数値になり
  MAYAでは、ドリブンキーなどの数値を表す。

ちなみに、【A】はAngle
【L】Distance
【U】Double
【T】Time
になる。



以上メモ。

小物メモ2

続き

選択のコンストレイントを削除するやつ。
ツール作るまではこれで、コンストを削除してました。

import maya.cmds as cmds

def SelAll_Const_Del():
    sel= cmds.ls(sl=True,type="constraint")
    for i in sel:
        cmds.delete(i)


続いて、これは入力した文字数頭から
文字列を削除してます。
あやまって変な名前を頭に付けてしまったときに
一度だけ使った気がします。。。
これが
f:id:tommy_on:20180502225917p:plain
こうなる。
f:id:tommy_on:20180502225934p:plain

# coding: UTF-8
import sys
import maya.cmds as cmds 

err = []

def Renamen(Counts):
    sel = cmds.ls(sl=True,shortNames=True)
    for file in sel:
        RenameSet = file.rsplit('|')[-1]
        Front = RenameSet[:Counts]
        End = RenameSet[Counts:]
        try:
            cmds.rename(file ,End)
        except:
            err.append(file)
    if len(err) > 0 :
        st = u"以下のファイルに同名処理の疑いがある為、スキップしています。\n" + str(err)
        cmds.confirmDialog(message = st  ,b= u"確認")
    else:
        cmds.headsUpMessage( u'作業が終了しました。', verticalOffset=20 )

result = cmds.promptDialog(title=u'分割するカット数を入力ください。',
message=u'分割数(数字以外入れないで下さい)',
text=u"2",
button=['OK', 'Cancel'],
defaultButton='OK',
cancelButton='Cancel',
dismissString='Cancel')
if result == "OK":
    text = cmds.promptDialog(query=True, text=True)
    if text.isdigit():
        Counts = int(text)
        Renamen(Counts)
    else:
        cmds.confirmDialog(message = u"数字を入力してください",b= u"確認")
        print u"キャンセルされました"
else:
    print u"キャンセルされました"

これは選択したアニメーション範囲に
シーンのライムレンジを合わせるスクリプト
今は他のツールに統合してるので使ってない。

import maya.cmds as cmds

Sel = cmds.ls(sl=True)
if len(Sel) > 0:

    cmds.playbackOptions(e=True,ast='-10000')
    cmds.playbackOptions(e=True,min='-10000')
    cmds.playbackOptions(e=True,aet='10000')
    cmds.playbackOptions(e=True,max='10000')
    In = cmds.findKeyframe(timeSlider=True, which='first') 
    Out = cmds.findKeyframe(timeSlider=True, which='last') 
    
    cmds.playbackOptions(e=True,ast=In)
    cmds.playbackOptions(e=True,min=In)
    cmds.playbackOptions(e=True,aet=Out)
    cmds.playbackOptions(e=True,max=Out)

とりあえずこれで最後に
こいつはなぜ作ったのか?まったく覚えてないんですが
あったんでとりあえずアップ。
骨選んで実行すると
同じような階層でロケーターができます。
これが
f:id:tommy_on:20180502225712p:plain
こうなります。
f:id:tommy_on:20180502225729p:plain

# -*- coding: utf-8 -*-
"""
骨選んで実行すると、その階層と同じロケーターが作成され
選択された骨は、こちらに回転コンストレインがかけられる。
"""

import maya.cmds as cmds

Sel = cmds.ls(sl=True)

if len(Sel) > 0:
    RigGrp = cmds.group(n="Rigging",empty=True)
    index = 0
    Hako = []
    Oya_Loc = ""
    for i in Sel:
        Loc = cmds.spaceLocator(n="Tail_Transfer_" + str(index))
        PosC = cmds.pointConstraint(i,Loc)
        OriC = cmds.orientConstraint(i,Loc)
        cmds.delete(PosC,OriC)
        if index == 0:
            Oya_Loc = Loc[0]
        index = index + 1
        Hako.append(Loc)
    Hako.reverse()
    for p in range(len(Hako)):
        try:
            cmds.parent(Hako[p],Hako[p+1])
            cmds.select(Hako[p+1])
        except:
            print "NG"
    cmds.parent(Oya_Loc,RigGrp)
    cmds.select(Oya_Loc,hierarchy=True)
    SelLoc = cmds.ls(sl=True,tr=True)
    for L in range(len(SelLoc)):
        print SelLoc[L]
        print Sel[L]
        OriC = cmds.orientConstraint(SelLoc[L],Sel[L])
else:
    print "NG"

ほかにもあるけど、ちょいちょい仕事の内容も含みながら書いてたりするので
この程度で…

どうせまた増えるし…

小物メモ

MacBookAirのデスクトップに放置してた、スクリプトをメモ代わりにここに残そうかと。

●SpeedChange
FPSを簡単に変えるスクリプト
モーション作成時に、一々変更するのが
面倒だったので作ったと思います。
f:id:tommy_on:20180501231151p:plain

# -*- encoding: utf-8 -*-
import maya.cmds as cmds
import maya.mel as mel

def SetTime(item):
    print item
    if item == "realtime":
        cmds.playbackOptions( edit=True , ps=1.0)
    elif item == "3x":
        cmds.playbackOptions( edit=True , ps=3.0)
    elif item == "2x":
        cmds.playbackOptions( edit=True , ps=2.0)
    elif item == "1/2x":
        cmds.playbackOptions( edit=True , ps=0.5)
    elif item == "1/3x":
        cmds.playbackOptions( edit=True , ps=0.3)
    elif item == "1/4x":
        cmds.playbackOptions( edit=True , ps=0.2)
    elif item == "1/5x":
        cmds.playbackOptions( edit=True , ps=0.1)
             
def main():
    ChangeFPS_window = "ChangeFPS"
    WindowWidth_Size = 170
    WindowHight_Size = 60

    if cmds.window(ChangeFPS_window,exists=True):
        cmds.deleteUI(ChangeFPS_window,window=True)
    MakeWindow = cmds.window(ChangeFPS_window,title=ChangeFPS_window,sizeable=False,mxb=False,mnb=False,wh=[WindowWidth_Size,WindowHight_Size])

    cmds.columnLayout(w=WindowWidth_Size)
    cmds.text(l=u"選択した設定に、再生スピードを変更します。")
    cmds.optionMenu( label='Speed', changeCommand=SetTime)
    cmds.menuItem( label='realtime' )
    cmds.menuItem( label='3x' )
    cmds.menuItem( label='2x' )
    cmds.menuItem( label='1/2x' )
    cmds.menuItem( label='1/3x' )
    cmds.menuItem( label='1/4x' )
    cmds.menuItem( label='1/5x' )
    cmds.showWindow()
main()

●ネームスペース取得Tips
これで取得できるのが知らなかったのでメモ

# -*- encoding: utf-8 -*-
import maya.cmds as cmds
NameSpace = cmds.namespaceInfo(recurse=1,listOnlyNamespaces=1)
NameSpace.remove(u'UI')
NameSpace.remove(u'shared')
print NameSpace


●スキンクラスターあれこれ取得
これはかなり昔のやつ。
一応メモ。

# -*- coding: utf-8 -*-
from maya import cmds
selection = cmds.ls(sl=True)
shapes = cmds.listRelatives(selection[0],s=True,pa=True,type='mesh')

if not shapes:
	cmds.error('Node has no shape')
else:
	srcSkinCluster = cmds.listConnections(shapes[0]+'.inMesh',s=True,d=False)
	#スキンクラスター
	srcSkinCluster = srcSkinCluster[0]
	#スキング方法
	skinningMethod = cmds.getAttr(srcSkinCluster+'.skm')
	#ドロップオフ率
	dropoffRate = cmds.getAttr(srcSkinCluster+'.dr')
	#最大インフルエンス数の保持
	maintrainMaxInfluences = cmds.getAttr(srcSkinCluster+'.mmi')
	#最大インフルエンス数
	maxInfluences = cmds.getAttr(srcSkinCluster+'.mi')
	#ジョイントとジオメトリのポイントの間の最短距離
	bindMethod = cmds.getAttr(srcSkinCluster+'.bm')
	#ウェイトの正規化
	normalizeWeight = cmds.getAttr(srcSkinCluster+'.nw')
	#インフルエンスオブジェクト
	influences = cmds.skinCluster(srcSkinCluster,q=True,inf=True)
	print dropoffRate

まだあるけど、一旦これだけアップ。
以上。