QTreeView Get Selected Text (pyside2)(python3)


# -*- coding: utf-8 -*-
import os
from functools import partial
import time
import imp

"""
PySide2モジュールを探し、ある場合はそちらをインポートします。
"""
try:
    imp.find_module('PySide2')
    from PySide2.QtWidgets import *
    from PySide2.QtGui import *
    from PySide2.QtCore import *

except ImportError:
    from PySide.QtGui import *
    from PySide.QtCore import *


LOGO_IMAGE = r"画像のパスをここに入れてください。"


def get_maya_pointer():
    """
    Mayaのメインウィンドウを取得する関数
    """
    try:
        import maya.cmds as cmds
        from maya import OpenMayaUI

    except ImportError:
        return None

    """
    実は2017ではshibokenも2になっているので、あればshiboken2をインポートします。
    """
    try:
        imp.find_module("shiboken2")
        import shiboken2
        return shiboken2.wrapInstance(int(OpenMayaUI.MQtUtil.mainWindow()), QWidget)

    except ImportError:
        import shiboken
        return shiboken.wrapInstance(int(OpenMayaUI.MQtUtil.mainWindow()), QWidget)





class TreeView_Selected_Text(QMainWindow):


    def __init__(self, parent = None):
        super(TreeView_Selected_Text, self).__init__(parent)
        self.setObjectName("TreeView_Selected_Text")
        self.setWindowTitle("TreeView_Selected_Text")
        self._initUI()
        self.errorDialog = QErrorMessage(self) # QErrorMessageインスタンスの保持


    def _initUI(self):
        wrapper = QWidget()
        self.setCentralWidget(wrapper)

        mainLayout = QVBoxLayout()
        wrapper.setLayout(mainLayout)

        #-----------------------------------------------------------------------

        #-----------------------------------------------------------------------
        # fifth row
        #-----------------------------------------------------------------------
        fifthHorizontalArea = QHBoxLayout()
        fifthHorizontalArea.setSpacing(20)
        mainLayout.addLayout(fifthHorizontalArea)

        fifthHorizontalArea.addWidget(self._makeTreeWidget())

        mainLayout.addWidget(self._makeHorizontalLine())

        #-----------------------------------------------------------------------


    def _makeHorizontalLine(self):
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        return hline





    def _makeTreeWidget(self):
        """
        QTreeWidgetを作成する関数
        """
        treeWidget = QTreeWidget()
        headerLabels = ["Name", "Age"]
        treeWidget.setColumnCount(len(headerLabels))
        treeWidget.setHeaderLabels(headerLabels)
        treeWidget.setAlternatingRowColors(True)
        treeData = {
            "Male":[
                {"name":"Taro",     "age":"25"},
                {"name":"Ichiro",   "age":"50"},
                {"name":"Jiro",     "age":"40"}
            ],
            "Female":[
                {"name":"Hanako",   "age":"30"}
            ]
        }

        #for sex, profiles in treeData.iteritems():
        for sex, profiles in treeData.items():
            topItem = QTreeWidgetItem([sex])
            treeWidget.addTopLevelItem(topItem)

            for profile in profiles:
                childItem = QTreeWidgetItem(topItem, [profile.get("name"), profile.get("age")])

        treeWidget.expandAll()
        self.treeWidget=treeWidget
        self.treeWidget.selectionModel().selectionChanged.connect(self.treeWidget_selectionChanged)
        
        return treeWidget
    def treeWidget_selectionChanged(self,selected, deselected):
        print("----treeWidget_selectionChanged-----")
        
        
        for QModelIndex in self.treeWidget.selectedIndexes():
            text = QModelIndex.data(Qt.DisplayRole) # or ix.data()
            print("text= "+str(text))
            
            QModelIndex2=QModelIndex.child(0,0).sibling(0,0)
            text2 = QModelIndex2.data(Qt.DisplayRole)   
            print("text2= "+str(text2))   
            QModelIndex3=QModelIndex.child(0,0).sibling(0,1)
            text3 = QModelIndex3.data(Qt.DisplayRole)   
            print("text3= "+str(text3))   



def start():
    maya_win = get_maya_pointer()
    ui = TreeView_Selected_Text(parent = maya_win)
    ui.show()
    return ui


if __name__ == '__main__':

    app = QApplication.instance()
    if app is None:
        app = QApplication([])
    ui = start()
    app.exec_()

選択したグループのそれぞれのジョイントにセットアトリビュートしたあとキーを打つ

Pythonで書き直した

# -*- coding: utf-8 -*- 
from maya import cmds 
import maya.mel as mel
import re
import pymel.core as pm 
def selected_groupName():
    selectedGlp=""
    selectedArr=cmds.ls(sl=1)
    print("selectedArr= "+str(selectedArr))
    if(str(selectedArr)=="[]"):
        print("You Should Select root Group Node!!!")
    else:
        selectedGlp=selectedArr[0]
    #evalStr='$characterName = `hikCreateCharacter('+selectedGlp+')`'
    #myPythonVar=mel.eval('$tempMelVar=$gMainWindow')
    #characterName=mel.eval(evalStr)
    #print(u"characterName= " + str(characterName))
    return selectedGlp
def LongNameToShortName(LongName):
    #childfullpath= |group_meshHIK_Tpose_jointUE4name5|SK_Mannequin|root|hip|spine_01
    LongNameArr=LongName.split("|")
    LongNameArrLong=len(LongNameArr)
    shortName=LongNameArr[LongNameArrLong-1]
    return shortName
    
def Group_in_joint(GroupName,jointName):
    print("jointName= "+jointName)
    HitJointFullPath=""
    groupChild=cmds.ls(GroupName,dag=1,long=1)
    for childfullpath in groupChild:
        searchStr=r'.*'+'\|'+jointName+r'$'
        print("searchStr= "+searchStr +"    childfullpath= "+childfullpath)
        MatchObj=re.match(searchStr, childfullpath)
        MatchBool=bool(MatchObj)
        if(MatchBool==True):
            HitJointFullPath=childfullpath
            print("HitJointFullPath !!!!!!!!= "+HitJointFullPath)
            break
        #shortjointNameArr=cmds.ls(childfullpath,shortNames=1)
        #shortjointName=shortjointNameArr[0]
        shortjointName=LongNameToShortName(childfullpath)
        print("searchStr= "+jointName +"    shortjointName= "+shortjointName)
        if(str(shortjointName)==str(jointName)):
            HitJointFullPath=childfullpath
            print("HitJointFullPath !!!!!!!!= "+shortjointName)
            break
    print("HitJointFullPath= "+HitJointFullPath)
    return HitJointFullPath 

def setAttKeyFrame(GroupName,jointName,attName,attVal):
    #MEL setCharacterObject("root",$characterDefName,0,0);
    jointFullName=Group_in_joint(GroupName,jointName)
    #evalStr='setCharacterObject("'+jointFullName+'","'+characterDefName+'",'+str(RigInt)+','+str(RigInt2)+');'
    #print("evalStr= "+ evalStr)
    attStr=jointFullName+'.'+attName
    cmds.setAttr( attStr, attVal )
    cmds.setKeyframe(jointFullName)
    #mel.eval(evalStr)
       
def UE4JointSetToHumanIK():
    GroupName= selected_groupName()
    #print("characterDefName= "+characterDefName)
    setAttKeyFrame(GroupName,"lowerJaw","rotateX",10)
    setAttKeyFrame(GroupName,"lEyelidUpperInner","translateY",5.2)
    setAttKeyFrame(GroupName,"lEyelidUpper","translateY",5)
    setAttKeyFrame(GroupName,"lEyelidUpperOuter","translateY",5.2)
    setAttKeyFrame(GroupName,"rEyelidUpperInner","translateY",5.2)
    setAttKeyFrame(GroupName,"rEyelidUpper","translateY",5)
    setAttKeyFrame(GroupName,"rEyelidUpperOuter","translateY",5.2)
    
UE4JointSetToHumanIK()

マイナス5frameに移動してそれぞれのジョイントにセットアトリビュートしたあとキーを打つ

currentTime -5 ;

proc setkeyFrame_F(string $innerPath,string $attributeName,float $attributeValue)
{
    
    string $selectedArrFUllPath_F[] = `ls -sl`;
    print("$selectedArrFUllPath_F is ==");
    print($selectedArrFUllPath_F);
    
    string $groupName_F;
    $groupName_F=$selectedArrFUllPath_F[0];
    print("groupName_F= "+$groupName_F+"\n");
    
    string $attpath_F;
    $attpath_F =  "|"+$groupName_F + $innerPath;
    print("attpath_F= "+$attpath_F+"\n");
    
    string $attStr_F;
    $attStr_F =$attpath_F+"."+$attributeName;
    print("attStr= "+$attStr_F+"\n");
    
    setAttr $attStr_F $attributeValue;
    setKeyframe -attribute $attributeName $attpath_F;
   
}
setkeyFrame_F("|SK_Mannequin|root|hip|spine_01|spine_02|spine_03|neck_01|neck_02|head|lowerJaw","rotateX",10);
setkeyFrame_F("|SK_Mannequin|root|hip|spine_01|spine_02|spine_03|neck_01|neck_02|head|upperFaceRig|lEyelidUpperInner","translateY",5.2);
setkeyFrame_F("|SK_Mannequin|root|hip|spine_01|spine_02|spine_03|neck_01|neck_02|head|upperFaceRig|lEyelidUpper","translateY",5);
setkeyFrame_F("|SK_Mannequin|root|hip|spine_01|spine_02|spine_03|neck_01|neck_02|head|upperFaceRig|rEyelidUpperInner","translateY",5.2);
setkeyFrame_F("|SK_Mannequin|root|hip|spine_01|spine_02|spine_03|neck_01|neck_02|head|upperFaceRig|rEyelidUpper","translateY",5);

Add Twist Joint Auto -ツイストジョイントの追加を自動化したよ-

このビデオの腕のツイストジョイントの追加を自動化したよ
腕を回転させれば肘ジョイントが伸びスキニングした際に肘が丸くなるのを防ぎます
import maya.cmds as cmds
import pymel.core as pm
import os
class TwistJointClass:


    def MainWay(self):
        
        self.Selected_Joint_Check()
        
    def Selected_Joint_Check(self):
        # need elbowJoint select
        selected = cmds.ls(sl=True,long=True)
        print("01 selected= "+str(selected))
        if(str(selected)=="[]"):
            print("Need Select Elbow Joint!!!!!!!!!!!!!!!!!!")
        else:
            self.elbowJoint_to_twistjoint(selected)
            
            self.elbowJoint_to_drivenkey(selected)
        
    def elbowJoint_to_drivenkey(self,selected):
        elbow_joint_full=selected[0]
        print("02 elbow_joint_full= "+str(elbow_joint_full))
        
        self.select_fullname(elbow_joint_full)
        
        elbow_joint_name =self.get_fullname_to_name(elbow_joint_full)
        elbow_joint_togeJointName = self.make_elbow_toge_joint(elbow_joint_full)
        
        elbow_mode="Genesis8"
        if(elbow_mode=="Genesis8"):
            elbow_way_rz=".ry"# my model
        else:
            elbow_way_rz=".rz"# tutorial
        print("elbow_way_rz= "+elbow_way_rz)

        
        # Key Value 1
        
        destArr=elbow_joint_name+elbow_way_rz
        cmds.setAttr( destArr, 0 )
        
        
        
        
        destArr=elbow_joint_togeJointName+".tx"
        cmds.setAttr( destArr, 0 )    

        destArr=elbow_joint_togeJointName+elbow_way_rz
        cmds.setAttr( destArr, 0 )
        
        # Set DrivenKey
        
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.translateX;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+'.tx'
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.rotateZ;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+elbow_way_rz
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        
        # Key Value 2
        SideWay=self.check_Left_Or_Right(elbow_joint_name)
        print("64 SideWay= "+SideWay)
        if(SideWay=="R"):
            destArr=elbow_joint_name+elbow_way_rz
            cmds.setAttr( destArr, 180 )
            
            #setAttr "lowerarm_toge_r.translateX" 4;
            destArr=elbow_joint_togeJointName+".tx"
            cmds.setAttr( destArr, 4 )
            
        if(SideWay=="L"):
            destArr=elbow_joint_name+elbow_way_rz
            cmds.setAttr( destArr, -180 )
            
            #setAttr "lowerarm_toge_r.translateX" 4;
            destArr=elbow_joint_togeJointName+".tx"
            cmds.setAttr( destArr, -4 )
        #setAttr "lowerarm_toge_r.rotateZ" 90;
        #destArr=elbow_joint_togeJointName+elbow_way_rz
        #cmds.setAttr( destArr, 90 )
        
        # Set DrivenKey
        
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.translateX;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+'.tx'
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.rotateZ;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+elbow_way_rz
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        
        # reset joint rz
        
        destArr=elbow_joint_name+elbow_way_rz
        cmds.setAttr( destArr, 0 )
        

        
    def check_Left_Or_Right(self,elbow_joint_name):
        SideWay=""
        jointName_arr=elbow_joint_name.split("_")
        if(jointName_arr[0].lower()=="left"):
            SideWay="L"
        if(jointName_arr[0].lower()=="l"):
            SideWay="L"    
        if(jointName_arr[1].lower()=="left"):
            SideWay="L"
        if(jointName_arr[1].lower()=="l"):
            SideWay="L" 
        if(jointName_arr[0].lower()=="right"):
            SideWay="R"
        if(jointName_arr[0].lower()=="r"):
            SideWay="R"    
        if(jointName_arr[1].lower()=="right"):
            SideWay="R"
        if(jointName_arr[1].lower()=="r"):
            SideWay="R"     
        print("SideWay= "+SideWay)
        return SideWay
    def make_elbow_toge_joint(self,elbow_joint_full):
        elbow_joint_name =self.get_fullname_to_name(elbow_joint_full)
        elbow_joint_togeJointName=self.makeName_togejoint(elbow_joint_name)
        
        elbow_pos=cmds.xform(elbow_joint_full,q=1,ws=1,rp=1)
        print("elbow_pos=" +str(elbow_pos))
        jointName2=cmds.joint( p=(elbow_pos[0], elbow_pos[1], elbow_pos[2]-3) ,absolute=True)
        cmds.rename(jointName2,elbow_joint_togeJointName);
        #cmds.parent( elbow_joint_togeJointName, elbow_joint_full )
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        return elbow_joint_togeJointName
        
    def elbowJoint_to_twistjoint(self,selected):
        elbow_joint_full=selected[0]
        print("02 elbow_joint_full= "+str(elbow_joint_full))
        
        hand_joint_full=self.get_one_child_node(elbow_joint_full)
        print("03 hand_joint_full= "+str(hand_joint_full))
        
        upperarm_joint_arr = cmds.listRelatives(str(elbow_joint_full),parent=True,fullPath=True)
        upperarm_joint_full=upperarm_joint_arr[0]
        print("04 upperarm_joint_full= "+str(upperarm_joint_full))

        #shoulder_joint_arr = cmds.listRelatives(str(upperarm_joint_full),parent=True,fullPath=True)
        #shoulder_joint_full= shoulder_joint_arr[0]
        #print("05 shoulder_joint_full= "+str(shoulder_joint_full))

        self.Elbow_Func(hand_joint_full,elbow_joint_full)
        
        self.Hand_Func(hand_joint_full,elbow_joint_full)
        #---------------------------------------------------------------------------------------
        #---------------------------------  upperarm_joint_full  -------------------------------
        #---------------------------------------------------------------------------------------
        self.UpperArm_Func(elbow_joint_full,upperarm_joint_full)
        
        self.Shoulder_Func(upperarm_joint_full)
            
    def Hand_Func(self,hand_joint_full,elbow_joint_full):
        hand_joint_name =self.get_fullname_to_name(hand_joint_full)
        hand_joint_twistJointName=self.makeName_twistjoint(hand_joint_name)
        
        
        hand_pos=cmds.xform(hand_joint_full,q=1,ws=1,rp=1)
        print("hand_pos=" +str(hand_pos))
        jointName2=cmds.joint( p=(hand_pos[0], hand_pos[1], hand_pos[2]) ,absolute=True)
        cmds.rename(jointName2,hand_joint_twistJointName);
        cmds.parent( hand_joint_twistJointName, elbow_joint_full )
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        # -------------Hand CONNECT -----------------------------------------------------
        fromAtt=hand_joint_name+".rotateX"
        destArr=hand_joint_twistJointName+".rotateX"
        cmds.connectAttr( fromAtt, destArr )
        #--------------------------------------------------------------------------------
        
    def Elbow_Func(self,hand_joint_full,elbow_joint_full):
        # make joint
        elbow_joint_name =self.get_fullname_to_name(elbow_joint_full)
        elbow_joint_twistJointName=self.makeName_twistjoint(elbow_joint_name)
        
        elbow_pos=cmds.xform(elbow_joint_full,q=1,ws=1,rp=1)
        hand_pos=cmds.xform(hand_joint_full,q=1,ws=1,rp=1)
        print("elbow_pos=" +str(elbow_pos))
        print("hand_pos=" +str(hand_pos))
        
        average_x=(elbow_pos[0]+hand_pos[0])/2
        average_y=(elbow_pos[1]+hand_pos[1])/2
        average_z=(elbow_pos[2]+hand_pos[2])/2
        
        jointName=cmds.joint( p=(average_x, average_y, average_z) ,absolute=True)
        cmds.rename(jointName,elbow_joint_twistJointName);
        #makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 -pn 1;
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        #cmds.joint( elbow_joint_twistJointName, e=True,position=(0, 0, 0) )
    
    
        #-----------------elbow divide --------------------------------------------------
        # 1 
        DivideName=elbow_joint_name+"_Divide"
        cmds.shadingNode('multiplyDivide', asUtility=True, name=DivideName)
        
        fromAtt=hand_joint_full+".rotateX"
        destArr=DivideName+".input1X"
        self.connectAttr_FullPath( fromAtt, destArr )
        # ------------- CONNECT ----------
        # 2 
        fromAtt=DivideName+".outputX"
        destArr=elbow_joint_twistJointName+".rotateX"
        self.connectAttr_FullPath( fromAtt, destArr )
        # 3 ------------- setAttr --------------------------
        destArr=DivideName+".input2X"
        self.setAttr_FullPath( destArr, 0.5 )
        
        
    def UpperArm_Func(self,elbow_joint_full,upperarm_joint_full):
        #upperarm_joint_arr = cmds.listRelatives(str(elbow_joint_full),parent=True,fullPath=True)
        #upperarm_joint_full=upperarm_joint_arr[0]
        self.select_fullname(upperarm_joint_full)
        
        # make joint -----------------------------------------
        upperarm_joint_name =self.get_fullname_to_name(upperarm_joint_full)
        upperarm_joint_twistJointName=self.makeName_twistjoint(upperarm_joint_name)
        
        upperarm_pos=cmds.xform(upperarm_joint_full,q=1,ws=1,rp=1)
        elbow_pos=cmds.xform(elbow_joint_full,q=1,ws=1,rp=1)
        print("upperarm_pos=" +str(upperarm_pos))
        print("elbow_pos=" +str(elbow_pos))
        
        average_x=(elbow_pos[0]+upperarm_pos[0])/2
        average_y=(elbow_pos[1]+upperarm_pos[1])/2
        average_z=(elbow_pos[2]+upperarm_pos[2])/2
        
        jointName=cmds.joint( p=(average_x, average_y, average_z) ,absolute=True)
        cmds.rename(jointName,upperarm_joint_twistJointName);
        #makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 -pn 1;
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        #-----------------Upperarm divide2 --------------------------
        #hand_joint_name=fullName_to_ShortName(hand_joint_full)
        DivideName2=upperarm_joint_name+"_Divide"
        cmds.shadingNode('multiplyDivide', asUtility=True, name=DivideName2)
        # 1  
        fromAtt=upperarm_joint_name+".rotateX"
        destArr=DivideName2+".input1X"
        self.connectAttr_FullPath( fromAtt, destArr )
        # ------------- CONNECT ----------
        # 2  
        fromAtt=DivideName2+".outputX"
        destArr=upperarm_joint_twistJointName+".rotateX"
        self.connectAttr_FullPath( fromAtt, destArr )
        # 3  ------------- setAttr --------------------------
        destArr=DivideName2+".input2X"
        self.setAttr_FullPath( destArr, -0.5 )
        #-----------------Upperarm divide2 --------------------------END
        
    def Shoulder_Func(self,upperarm_joint_full):
        #upperarm_joint_arr = cmds.listRelatives(str(elbow_joint_full),parent=True,fullPath=True)
        #upperarm_joint_full=upperarm_joint_arr[0]
        self.select_fullname(upperarm_joint_full)
        
        # make joint -----------------------------------------
        upperarm_joint_name =self.get_fullname_to_name(upperarm_joint_full)
        shoulder_joint_twistJointName=self.makeName_twistjoint("shoulder_"+upperarm_joint_name)
        
        upperarm_pos=cmds.xform(upperarm_joint_full,q=1,ws=1,rp=1)
        print("upperarm_pos=" +str(upperarm_pos))
        
        jointName=cmds.joint( p=(upperarm_pos[0], upperarm_pos[1], upperarm_pos[2]) ,absolute=True)
        cmds.rename(jointName,shoulder_joint_twistJointName);
        #makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 -pn 1;
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        #-----------------Upperarm divide3 --------------------------
        #hand_joint_name=fullName_to_ShortName(hand_joint_full)
        DivideName3="shoulder_"+upperarm_joint_name+"_Divide"
        cmds.shadingNode('multiplyDivide', asUtility=True, name=DivideName3)
        # 1  
        fromAtt=upperarm_joint_name+".rotateX"
        destArr=DivideName3+".input1X"
        self.connectAttr_FullPath( fromAtt, destArr )
        # ------------- CONNECT ----------
        # 2  
        fromAtt=DivideName3+".outputX"
        destArr=shoulder_joint_twistJointName+".rotateX"
        self.connectAttr_FullPath( fromAtt, destArr )
        # 3  ------------- setAttr --------------------------
        destArr=DivideName3+".input2X"
        self.setAttr_FullPath( destArr, -1 )
        #-----------------Upperarm divide2 --------------------------END
        
    def select_fullname(self,fullname):
        import sys
        
        try:
            cmds.select( fullname)
        except OSError as err:
            print("OS error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except:
            print("Unexpected error:", sys.exc_info()[0])
            #raise

    def setAttr_FullPath(self, destArr ,value):
        import sys
        
        try:
            cmds.setAttr( destArr, value )
        except OSError as err:
            print("OS error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except:
            print("Unexpected error:", sys.exc_info()[0])
            #raise

    def fullName_to_ShortName(fullName):
        shortName=""
        fullName_index=fullName.find("|")
        if(fullName_index==-1):
            pass
        else:
            fullName_Arr=fullName.split("|")
            fullName_Len=len(fullName_Arr)
            shortName = fullName_Arr[fullName_Len-1]
            print("shortName= "+shortName)
        return shortName

    def connectAttr_FullPath(self, fromAtt, destArr ):
        import sys

        try:
            cmds.connectAttr( fromAtt, destArr )
        except OSError as err:
            print("OS error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except:
            print("Unexpected error:", sys.exc_info()[0])
            #raise
        
        
    def get_one_child_node(self,elbow_joint_full):
        hand_joint_full=""
        
        hand_joint_arr = cmds.listRelatives(str(elbow_joint_full),children=True,fullPath=True)
        
        print("02 hand_joint_arr= "+str(hand_joint_arr))
        temp_child_name=hand_joint_arr[0]
        elbow_arr=elbow_joint_full.split("|")
        elbow_len=len(elbow_arr)-1
        elbow_last=elbow_arr[elbow_len]
        print("elbow_last= "+elbow_last)
        temp_arr=temp_child_name.split("|")
        temp_len=len(temp_arr)-1
        temp_elbowlastlen_name=temp_arr[elbow_len]
        temp_elbowlastlen_plusone_name=temp_arr[elbow_len+1]
        print("temp_elbowlastlen_name= "+temp_elbowlastlen_name)
        if(elbow_last==temp_elbowlastlen_name):
            print("same OK temp_elbowlastlen_name= "+temp_elbowlastlen_name)
            print("temp_elbowlastlen_plusone_name= "+temp_elbowlastlen_plusone_name)
            
            #for jname in temp_arr
            buildStr=""
            #for(int i = 0; i < elbow_len+1; i++)
            for i in range(1,elbow_len+1+1):
                jname = temp_arr[i]
                buildStr=buildStr+"|"+jname
            print("buildStr= "+buildStr)
            hand_joint_full=buildStr
        return hand_joint_full
            
    def handJoint_to_twistjoint(self):
        # need hand select
        selected = cmds.ls(sl=True,long=True)
        
        print("01 selected= "+str(selected))
        hand_joint_full=selected[0]
        
        print("02 hand_joint_full= "+str(hand_joint_full))
        """
        hiji_joint_arr = cmds.listRelatives(str(hand_joint_full),parent=True,fullPath=True)
        hiji_joint_full=hiji_joint_arr[0]
        print("03 hiji_joint_full= "+str(hiji_joint_full))
        """
        #hand_joint_name =self.get_fullname_to_name(hand_joint_full)
        #hiji_joint_name =self.get_fullname_to_name(hiji_joint_full)
        
        
        #hiji_twistJointName=self.makeName_twistjoint(hiji_joint_name)
        
        #cmds.select(hiji_joint_full)
        #cmds.insertJoint( 'joint2' )
        
        #あとで復帰
        #cmds.select(selected)
        #cmds.select(hand_joint_full)
        
        
    def makeName_twistjoint(self,joint_name):
        
        joint_name_arr=  joint_name.split("_")
        twistJointName=joint_name_arr[0]+"_twist_"+joint_name_arr[1]
        print("twistJointName= "+twistJointName)
        return twistJointName
        
    def makeName_togejoint(self,joint_name):
        
        joint_name_arr=  joint_name.split("_")
        togeJointName=joint_name_arr[0]+"_toge_"+joint_name_arr[1]
        print("togeJointName= "+togeJointName)
        return togeJointName
     
    def get_fullname_to_name(self,fullname):
        hand_joint_full_arr=fullname.split("|")
        print("04 hand_joint_full_arr= "+str(hand_joint_full_arr))
        hand_joint_full_len=len(hand_joint_full_arr)
        hand_joint_jointName=hand_joint_full_arr[hand_joint_full_len-1]
        print("05 hand_joint_jointName= "+str(hand_joint_jointName))
        return hand_joint_jointName

ClassIns= TwistJointClass()
ClassIns.MainWay()

だめなスキンバインド設定とマシなスキンバインド設定

デフォルトがかなりダメ

・複数のバインドポーズはエラーの元なのでオフ

・最大インフルエンス数が5は多すぎ3でいい。

・最大インフルエンス数の保持は 無駄にインフルエンスジョイントに影響するのでオフ

・スケルトンのカラー化 無駄いらない オフ

・作成時に非表示の選択項目を含める 非表示のメッシュもバインドしたいので オン

参考URL

http://3dcgr2lab.com/2019/11/30/easy-skin-weight-paint-tool/

スキンウェイトからなくなってるインフルエンスジョイントの追加方法

スキンウェイト 全く抜け落ちた インフルエンスの追加方法

インフルエンス オブジェクトを追加するには
0,バインドポーズにします

2,オブジェクトが作用するスキン メッシュを選択します。
3,インフルエンスジョイントをCtrl押しながら追加選択します。
4,スキン > 影響を編集 > インフルエンスの追加(Skin > Edit Influences > Add Influences) > □ を選択します。

5,インフルエンスの追加オプション(Add Influence options)設定で、
  ウェイトのロッキング:オン にします。
6,適用をクリックします。

7,スキンウェイトペイントツールのインフルエンスの欄に追加されます。

8、ロックを解除してスキンウェイトペイントします。

追加したインフルエンスにウェイトをペイントするとモデルが壊れる

バインド ポーズ以外でスムーズ スキンしたジオメトリにインフルエンス オブジェクトを追加すると、バインド ポーズに戻ったときにわずかに異なるスキン結果となります。たとえば、バインド ポーズでないジオメトリにインフルエンス オブジェクトを追加すると、その領域のウェイト値の再配分によってインフルエンス オブジェクトの配置場所で変形が生じることがあります

https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2016/JPN/Maya/files/GUID-1BEC5727-E97F-40A1-9F26-1B1E6A4E8848-htm.html

より。

スキン>バインドポーズにしてみたらずれてた
バインドポーズにしてからやり直したら大丈夫だった。

ハイポリモデルのスキニングのためのLOWケージモデルの作り方をやってみた。

#CageModel #QuadDrow #SkinWeight #MayaCageModel #MayaQuadDrow #MayaSkinWeight

・エッジのデリート エッジ選択してShift押しながら右クリックメニューで左下のDelete Edge

・インサートエッジループ 選択しないでフェース上でShift押しながら右クリックメニューで下のInsert Edge Loop Tool

・マルチカット  選択しないでフェース上でShift押しながら右クリックメニューで左のMulch Cut でエッジをクリック

・マルチカット  選択しないでフェース上でShift押しながら右クリックメニューで左のMulch Cut で 何もないところからドラッグするとエッジができる。

・コラプス(エッジのマージ)  Ctrl を押しながら 右クリ 左下 Edge Ring Utils >左の To Edge Ring and Collapse

ハイポリ読み込んで
フェース削除して腕だけにして
キューブをヒジにあてて大体腕が収まるサイズにして
長さ分割10
手の甲上面分割3
横向き分割2
ぐらいにして
上下面消して、筒にして
ハイポリ選択して磁石アイコンのマグネットUツールをクリックすると吸着がスタート
Cube選択して頂点モードにして
ウィンドウ右上のモデリングツールキットを表示して
「四角ポリゴン描画」をクリックする
「B」をクリックしてグラデーションが表示され
「Shift」押しながら「マウス左ドラッグ」で一瞬で吸着される。
全部吸着されるまで「Shift」押しながら「マウス左ドラッグ」
「B」をクリックして普通選択へ戻し
「四角ポリゴン描画」をクリックして戻り
モデリングツールキットの「フェース選択」をクリック
ヒジの4つのフェースを選択して
メッシュの編集>押し出し(Extrude)でスケールして
ヒジのメッシュを増やす
あとはまた
「B」をクリックして普通選択へ戻し
「四角ポリゴン描画」をクリックして戻り
ヒジに多めにポリゴンがくるようにたぐりよせる
伸びたほうにオブジェクトモードでマルチカット  選択しないでShift押しながら右クリックメニューで左のMulch Cut で 何もないところからドラッグするとエッジができる。
腕終わり!!

ーーーーーーからだーーーーーーーーー
ハイポリからフェース削除して胴体だけにして
cube作って
上面分割6 頭つけれるように
正面分割4
横面分割3

頭用に用意した中央2面のフェースを削除
腕用に用意した中央上1面のフェースを削除

ハイポリ選択して磁石アイコンのマグネットUツールをクリックすると吸着がスタート
Cube選択して頂点モードにして
ウィンドウ右上のモデリングツールキットを表示して
「四角ポリゴン描画」をクリックする
「B」をクリックしてグラデーションが表示され
「Shift」押しながら上半身の上側を「マウス左ドラッグ」で一瞬で吸着される。(下の方は体がないので変なところに吸着しやすい)

肩パッドらへんをマルチカットでブツリする
オブジェクトモードでフェース上でマルチカットメニューだし  なにも選択しないでShift押しながら右クリックメニューで左のMulch Cut で ポイントをクリックしてエッジを作る、エッジデリートつかう。
肩の周りのメッシュが格子状にすすみつつ
ループ状になるように
穴の筒が三角で終わってるところのエッジを四角に格子になるようにしていく

※マウスホイールで寄ってペイント作業しないと範囲がでかすぎて頂点が変に吸着するのがポイント
Bなしの 四角ポリゴンの描画で
「Shift」押しながら「マウス左ドラッグ」で
肩の筒を平たんにしていく

平たんにした後も多角形になってる部分
脇の下の前後ろ面を90度が下になるようにマルチカット

あとは平たんにしていって

肩の筒にエッジループを足す
エッジモードでインサートエッジループ 選択しないでフェース上でShift押しながら右クリックメニューで下のInsert Edge Loop Tool

あとは脇の下の三角を四角になるように背中からマルチカットするで、、平たんにしたら流れが変わるので
三角が消えるように縦にマルチカット 平たんにしたら
背中のどうでもいいとこに三角が移動するのでコラプスで

つぶしたい縦のエッジを3つ選択して
コラプス(エッジのマージ)  Ctrl を押しながら 右クリ 左下 Edge Ring Utils >左の To Edge Ring and Collapse
平たんにして
ボディの完成!!
ーーーーーボディとハンドの結合編ーーーーー
ボディとハンドをCombineしてとりあえず結合する
すると
 「四角ポリゴンの描画」で「Shift」押しながら
結合部分をマウスで触るとグリーンにハイライトされて
結合用のフェースが表示されるのでクリックすると
面が張られる。
とりあえずクアッドになるように面を張れるところはじゃんじゃんはっていき
あとの三角もとりあえず結合する。
そうしたら
全身モデル選択してにマグネット吸着を切り替える

平たんにする

一旦、三角ができるがコラプスで消していく。
エッジは多めにあとからスライドして多くできるので大丈夫
結合の完成!

ーーーーーー独自のコツ ロングスカート編ーーーーーー

最初にやった分割数だとバグりすぎるので、できるだけ少なくというか
足りないぐらいでいい。あとでエッジループ足す前提。
幅の分割4
高さ6
深度3
で上下のメッシュ消して筒にする
上下のラインとマス以外の部分を「Shift」押しながら「マウス左ドラッグ」であわせていき
上下のラインはエッジからエッジダブルクリックでエッジループから選択項目の変換で
頂点にして縮小するとハイポリに合う、さらに上下を縮小スケールで平行にならぶ
・インサートエッジループ 選択しないでフェース上でShift押しながら右クリックメニューで下のInsert Edge Loop Tool
でだんだん足りてきたら
法線のせいでエッジが立って見えてるかもしれないので
エッジからエッジダブルクリックでエッジループから選択項目の変換で
頂点にしてメッシュ表示>法線>平均 すると面がスムーズに見える。

ーーーーーー以下参考リンクーーーーーーーーー

使っていたPC
hp z640
HP WorkStation Z640 E5-2643 v3 3.40GHz 2CPU メモリ32~GB HDD 2TB NVIDIA Quadro K2200
現在69,800円

human model 3dで検索すると出てくる。今回使ったモデル
https://www.turbosquid.com/ja/3d-models/realistic-male-body-basemesh-model-1609555
高いのも1777ドルっておい
https://www.turbosquid.com/ja/3d-models/male-female-anatomy-body-3d-max/602826

解剖学3Dデータのサンプル
https://www.teamlabbody.com/
無料 human data
https://always3d.com/freesozai-3danatomyman/

3d model anatomyで検索すると出てくる。
https://free3d.com/ja/3d-model/character-male-anatomy-body-base-highpoly-3953.html
https://free3d.com/ja/3d-model/character-female-anatomy-body-base-7442.html

ゲームのスキンウェイトのポイントの解説
https://area.autodesk.jp/column/tutorial/maya_atoz/skin_weights_1/

揺れもの YURAYURA.pyのおすすめ設定方法


A-s-C-e-n-S-i-o-N本家さん

http://a-s-c-e-n-s-i-o-n.blogspot.com/2017/12/maya-yurayurapy.html

maya : 骨にヘアを揺れ物シミュレーションするツール YURAYURA.pyの説明
髪の毛などの数珠繋ぎ階層にヘアシミュレーションをかける揺れ物ツールです。

YURAYURAのおすすめ設定というか、揺れすぎていろんな破滅を起こすので
一番ゆれない状態から設定していくのがいいかもしれないと思い、
一番揺れない設定にしてみた。(ゆれるけど)
といってもnHAIRの設定を見たらわかる。

https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2016/JPN/Maya/files/GUID-89B58075-7927-4117-8D5E-5FECE5669108-htm.html

■■■GENERATE■■■:
髪の毛のルートを選択して、GENERATEボタンを押すと
YURAYURAシミュレーションセットが作られます。
複数選択でき、一度作成した後でも追加で使用できます。

■■■SETTING■■■:

■Gravity:
重力
■Start Curve Attract
開始カーブに引き付け(Start Curve Attract)
現在のヘアの位置を(変形する)開始位置へ引き付ける量を決定します。このアトリビュートは、たとえば、硬めのヘアやキャラクタとともに動くヘアの場合など、多くのヘア ワークフローで役立ちます。さらに、キーフレームを設定されたアニメーションを開始カーブに配置する場合、開始カーブに引き付け(Start Curve Attract)アトリビュートを使用して、シミュレーションと開始カーブ アニメーションをブレンドすることができます。

流れるような長いヘアの場合には、通常、開始カーブに引き付け(Start Curve Attract)の値はゼロのままにします。ただし、短いヘアの場合は、ヘアの十分な剛性を保つことが困難になる場合があります。ヘアの剛性を非常に大きくして、同時に、いくつかのダイナミックなプロパティを持たせる必要がある場合、ゼロより大きい値を使用します。1.0 の値のとき、ヘア位置はカーブ開始位置です(トランスフォームされる毛根からの相対位置になります)。衝突およびフォースだけは、ヘアを偏向させます。Start Curve Attract がない場合、Substep と Damp の値を増やす必要があります(特に、ヘアごとの CV の数が多いとき)。

■Attraction Damp:
引き付けのダンプ(Attraction Damp)
開始カーブに引き付け(Start Curve Attract)のエフェクトをダンプし、ヘアをカーブの開始位置の方に移動させて、ヘアの速度を遅くします。これは、ヘアの弾力性(開始カーブに引き付け(Start Curve Attract)の値が高い場合に発生)を小さくしたい場合や、アニメートされたヘアの頂点にダイナミック フィールドを適用したい場合に便利です。引き付けのダンプ(Attraction Damp)を 1 にすると、開始カーブの方に移動するヘアの動きは完全にダンプされ、開始位置(Start Positions)とフィールド フォースだけをそのままにして、後から任意でその動きにインフルエンスを及ぼせるようにします。

■Drag:
ドラッグ(Drag)
これは、シミュレーションを安定させるのに役立つだけではなく、空気摩擦をシミュレートします。ドラッグ(Drag)の値が 1.0 のとき、ヘアは慣性のモーションやフォロースルーがないように動作するため、粘度が高い液体の中にあるかのように動きます。
■Tangential Drag:
接線のドラッグ(Tangential Drag)
ヘアの方向に沿ってドラッグする量を指定します。0 に設定すると、ヘアは接線方向またはシェイプの方向に沿った移動において抵抗がなくなります。接線のドラッグ(Tangential Drag)を 1 に設定すると、ドラッグ(Drag)はすべての方向に均一になります。ドラッグ(Drag)のレベルが高く、接線のドラッグ(Tangential Drag)が低い場合、ヘアは水中を移動する蛇のような揺らぎモーションの動きをします。
■Motion Drag:
モーション ドラッグ(Motion Drag)
毛根の動きに相対的なヘア カーブの動きをダンプします。モーション ドラッグ(Motion Drag)の値は、ヘア カーブが毛根に合わせて動く量、またヘアのシェイプが他のフォースに影響される程度を決定します。これにより、Substeps の数を増やさなくても、ボビングやウィグルのようなヘアの余分な動きをダンプすることができます。

たとえば、モーション ドラッグ(Motion Drag)を 1.0 に設定すると、ヘアは毛根に合わせて動くので、周囲の大気をそれに合わせてドラッグしているように見えます。
■Damp:
ダンプ(Damp)
ヘアのベンドおよび伸長の方法に影響する個々のヘアの相対的シェイプの変化をダンピングします。
■Stretch Damp:
伸長のダンプ(Stretch Damp)
ヘア カーブ頂点間の伸長による速度がどのくらいダンピングされるかを指定します。伸長のダンプ(Stretch Damp)を大きくすると、ヘアは弾まずに伸長できます。
■■■MODIFY■■■:
SETTING欄の数値を変更して、下にあるMODIFY SETTING ( REFRESH )
ボタンで適用できます。

■■■COLLIDE■■■:
コリジョンをセットしたい場合は、コリジョンオブジェクトを選択して
ADD COLLIDEボタンを押します。

■■■BAKE■■■:
シミュレーション結果が良さそうであれば、BAKEボタンを押すと
元に選択していた階層すべてのRotateにBake Simulationをかけます。
YURAYURAシミュレーションセットは消去され、UIも閉じます。

nHairを使用した揺れものリグセットアップの自動化をしたよ。JointChain Head Select To Make SplineIK nHair Rig

リグブログさんの
https://backbone-studio.com/blog-nhairrig/

この記事を参考にやった。

nHairを使った感じの揺れものシミュレーション

①ジョイントを作成します。
ジョイントはX軸が子供を向くように設定しましょう。
X軸を子供に向けておくと、SplineIK機能のAdvanced Twist Controls(根元と先端のツイストを制御できる)の設定がしやすくなります。
※Advanced Twist Controlsの説明に関しては割愛します。

②ジョイントにSplineIKを設定します。

③作られたcurve1をルートに移動しておく。
curve1を選択して、FX > nHair > Assign Hair System > New Hair Systemを実行します。
※curve1は、自動的にfollicle1の階層に移動します。

④再生すると、シミュレーションによりcurve2は動いていますが、curve1は動いていないことが確認できます。
ノードエディターでSplineIKとnHairの接続関係を確認してみましょう。
上側がSplineIK、下側がnHairの入出力です。
nHairからの情報はcurveShape2へ繋がっているので、nHairのシミュレーションによりcurveShape2が動きます。
一方で、ikHandle1にはnHairからの情報が繋がっていません。

⑤curveShape2のworldSpace[0]出力をikHandle1のInCurveに入力することで、nHairの情報がSplineIKに渡り、ジョイントが動くようになります。
curveShape2のWorldSpace[0]をikHandle1のinCurveに繋ぎます。
各機能の関係性は、下図のようになります。

⑥再生して、ジョイントが動くことを確認しましょう。
あんまり動かないことも。。。

動かないのでいきなり⑨にとんでみた。

⑨ジョイント全体を制御したい場合は、curve1を制御してください。
今回はジョイントの根元に別のジョイントchain_handle_01を作成し、curve1をペアレントコンストレインしてみました。
再生するとエンドフレームでループしていい感じに動き始めた。

なのでリグの方のジョイントチェーンをスケルトンのジョイントチェーンに方向コンストレインしていく

最後にスケルトンのジョイントチェーンにchain_handle_01を位置コンストレインしてあげれば動くはず。
ルートを選択して再生しながら動かしたらスケルトン通りに動きました。

ーーーー以下連続したいときのショート版ーーーーー
1,ジョイントチェーンの複製してグループ化しておく
2,リギング>スケルトン>SplineIKで親と最短クリック
3,できたcurve3に(curveの名前を変えちゃダメ)
FX > nHair > Assign Hair System > New Hair System
していく※curve3は、自動的にfollicle1の階層に移動
hairSystem2OutputCurvesの下にいる
curve4
ノードエディタの+で新規タブを開き入力と出力を接続ボタンを押し
curveShape4のWorldSpace[0]をikHandle1のinCurveに繋ぎます。
ジョイントから複製そしてchain_handle_01を作成し、curve1をペアレントコンストレインでリグ1本完成
リグの方のジョイントチェーンをスケルトンのジョイントチェーンに方向コンストレインしていく
最後にスケルトンのジョイントチェーン頭にchain_handle_01を位置コンストレインしてあげれば動くはず。

この作業を自動化した。
ジョイントチェーンの頭のジョイントを選択して実行するとnHairリグが作られる。
ーーMELーーーーーーーーーーーーーーーーーー

//JointChain Head Select To Make nHairRig 
string $selectedArr[] = `ls -shortNames -sl`;
string $selectedArrFUllPath[] = `ls -long -sl`;
print($selectedArr);
string $selectedJoint = $selectedArr[0];
string $buffer[];
$numTokens = `tokenize $selectedArr[0] "|" $buffer`;
$bufferlong=size($buffer);
string $selectedJointShort = $buffer[$bufferlong-1]+"";

print("$selectedJoint= "+$selectedJoint+"\n");
print("$selectedJointShort= "+$selectedJointShort+"\n");
string $selectedJointFullPath = $selectedArrFUllPath[0];
print("$selectedJointFullPath= "+$selectedJointFullPath+"\n");
string $jointNodes[] = `ls -dag $selectedJoint`;
string $jointNodesFullPath[] = `ls -long -dag $selectedJointFullPath`;
//duplicate
string $RigJoints[] =`duplicate $selectedJoint`;

$RigJointslong=size($RigJoints);
//name check
for($i = 0; $i <$RigJointslong;$i++){
    string $rig_j_name=$RigJoints[$i];
    print("$rig_j_name= "+$rig_j_name+"\n");
}
string $RigJointTop = $RigJoints[0];
print("RigJointTop= "+$RigJointTop+"\n");
parent -world $RigJointTop;
string $groupName = $selectedJointShort+"_group";
group -n $groupName $RigJointTop;
print("groupName= "+$groupName+"\n");
string $rigJointTop =`rename $RigJointTop $selectedJoint`;
//SplineIK
print("$rigJointTop= "+$rigJointTop+"\n");
string $rigjointNodes[] = `ls -dag $rigJointTop`;
print($rigjointNodes);
$rigjointNodeslong=size($rigjointNodes);
print("$rigjointNodeslong= "+$rigjointNodeslong+"\n");
string $rigJointEnd = $rigjointNodes[$rigjointNodeslong-1];
print("$rigJointEnd= "+$rigJointEnd+"\n");

string $ikHandleReturn[] =`ikHandle -solver ikSplineSolver -startJoint $rigJointTop -endEffector $rigJointEnd`;
print($ikHandleReturn);
string $ikHandleRef = $ikHandleReturn[0];
print("$ikHandleRef= "+$ikHandleRef+"\n");
$ikHandleReturnlong=size($ikHandleReturn);
//name check
string $curveRef;
for($i = 0; $i <$ikHandleReturnlong;$i++){
    string $ikHandleRet_name=$ikHandleReturn[$i];
    print("$ikHandleRet_name= "+$ikHandleRet_name+"\n");
    string $type = `objectType $ikHandleRet_name`;
    string $nodetype= `nodeType $ikHandleRet_name`;
    print("$type= "+$type+"\n");
    //if($type == "transform"){
    print("$ikHandleRet_name= "+$ikHandleRet_name+" type= "+$type+" nodetype= "+$nodetype+"\n");
    //}
    $index=`gmatch $ikHandleRet_name "curve*"`;
    if($index > 0){
        $curveRef = $ikHandleRet_name;
        print("$ikHandleRet_name= "+$ikHandleRet_name+" isHit!! "+"\n");
    }
}

//string $curveRef = $ikHandleReturn[2];
print("$curveRef= "+$curveRef+"\n");

select -r $curveRef;
assignNewHairSystem;
//root hairsystem all arr
string $rootHairSystemAll[]=`ls -assemblies "hairSystem*"`;
print($rootHairSystemAll);
print("$groupName= "+$groupName+"\n");
//parent $rootHairSystemAll[0] $groupName;
//parent $rootHairSystemAll[1] $groupName;
//parent $rootHairSystemAll[2] $groupName;
$rootHairSystemAlllong=size($rootHairSystemAll);
//name check
string $hairSystemShape;
for($i = 0; $i <$rootHairSystemAlllong;$i++){
    string $rig_hs_name=$rootHairSystemAll[$i];
    print("$rig_hs_name= "+$rig_hs_name+"\n");
    parent $rig_hs_name $groupName;
    string $rig_hs_Arr[]=`listRelatives -children $rig_hs_name`;
    print($rig_hs_Arr);
    $rig_hs_Arrlong=size($rig_hs_Arr);
    if($rig_hs_Arrlong>0){
        $index=`gmatch $rig_hs_Arr[0] "hairSystemShape*"`;
        if($index>0){
            $hairSystemShape = $rig_hs_Arr[0];
            print("$hairSystemShape= "+$hairSystemShape+"\n");
        }
    }

}
string $hairSystemShapeAtt1=$hairSystemShape+".solverDisplay";
string $hairSystemShapeAtt2=$hairSystemShape+".collideWidthOffset";
setAttr $hairSystemShapeAtt1 1;
setAttr $hairSystemShapeAtt2 1;

parent $ikHandleRef $groupName;
string $rootNucleus[]=`ls -assemblies "nucleus*"`;
print($rootNucleus);
$rootNucleuslong=size($rootNucleus);
if($rootNucleuslong>0){
    print("$rootNucleuslong= "+$rootNucleuslong+"\n");
    if( `objExists $rootNucleus[0]` ) {
        parent $rootNucleus[0] $groupName;
    } else {
        warning("No nucleus exists");
    }
}

string $hairSystem2OutputCurves=$rootHairSystemAll[2];
string $hairSystem2OutputCurveArr[]=`listRelatives -children $hairSystem2OutputCurves`;
print($hairSystem2OutputCurveArr);
string $curve2 = $hairSystem2OutputCurveArr[0];
string $curve2Arr[]=`listRelatives -children $curve2`;
print($curve2Arr);
string $curveShape2 = $curve2Arr[0];
print("$curveShape2= "+$curveShape2+"\n");
string $output1 = $curveShape2 + ".worldSpace[0]";
print("$output1= "+$output1+"\n");
string $input1 = $ikHandleRef + ".inCurve";
print("$input1= "+$input1+"\n");
connectAttr -f $output1 $input1;

//select -r $rigJointTop;
string $RigHandleJoints[] =`duplicate $rigJointTop`;
$RigHandJointslong=size($RigHandleJoints);
//name check
for($i = 0; $i <$RigHandJointslong;$i++){
    string $rig_hj_name=$RigHandleJoints[$i];
    print("$rig_hj_name= "+$rig_hj_name+"\n");
}
string $RigHandleJointsChild=$groupName+"|"+$RigHandleJoints[0]+"|"+$RigHandleJoints[1];
print("$RigHandleJointsChild= "+$RigHandleJointsChild+"\n");
delete $RigHandleJointsChild;
string $RigHandleJointsTop=$groupName+"|"+$RigHandleJoints[0];
print("$RigHandleJointsTop= "+$RigHandleJointsTop+"\n");
string $RigHandleJointsTopName=$selectedJointShort+"_handle";
print("$RigHandleJointsTopName= "+$RigHandleJointsTopName+"\n");
string $rigJointTop =`rename $RigHandleJointsTop $RigHandleJointsTopName`;
string $RigHandleJointsTopNameRadiusAtt  = $RigHandleJointsTopName + ".radius";
setAttr $RigHandleJointsTopNameRadiusAtt 15;
parentConstraint -maintainOffset $RigHandleJointsTopName $curveRef;
/////////////////////////////////////////RIG OK
$rigJointlong=size($rigjointNodes);
for($i = 0; $i <$rigJointlong;$i++){
    string $rig_j_name=$rigjointNodes[$i];
    print("$rig_j_name= "+$rig_j_name+"\n");
    string $joint_j_name = $jointNodesFullPath[$i];
    print("$joint_j_name= "+$joint_j_name+"\n");
    orientConstraint -maintainOffset $rig_j_name $joint_j_name;
}
////////////////////////////Joint Move OK
pointConstraint -maintainOffset $selectedJointFullPath $RigHandleJointsTopName;
string $blendShapeReturn[] =`blendShape $curveRef $curve2`;
$blendShapeReturnlong=size($blendShapeReturn);
string $blendShapeName;
for($i = 0; $i <$blendShapeReturnlong;$i++){
    string $blendshapeRet_name=$blendShapeReturn[$i];
    print("$blendshapeRet_name= "+$blendshapeRet_name+"\n");
    $index=`gmatch $blendshapeRet_name "blendShape*"`;
    if($index > 0){
        $blendShapeName = $blendshapeRet_name;
        print("$blendshapeRet_name= "+$blendshapeRet_name+" isHit!! "+"\n");
    }
}

string $blendShapeAtt=$blendShapeName+"."+$curveRef;
//0 is Move 1 is Stop
setAttr $blendShapeAtt 0.90;

こんなかんじ 画像をクリックしてGIF再生

——–以下しらべもの———–
whatIs assignNewHairSystem;
// 結果: Mel procedure found in: C:/Program Files/Autodesk/Maya2016/scripts/startup/DynCreateHairMenu.mel //

string $hsystems[] = ls -type hairSystem;
int $i;
for( $i = 0; $i < size( $hsystems ); $i++ ){
string $hsys = $hsystems[$i];
string $annot = format -s $hsys $fmt;
menuItem -label $hsys
-image “hairAssignHairSystem.png”
-command (“assignHairSystem “+$hsys)
-annotation $annot;
}

whatIs assignHairSystem;

// 結果: Mel procedure found in: C:/Program Files/Autodesk/Maya2016/scripts/others/assignHairSystem.mel //
ーーーーーーーーーーーーーーーーーーー
⑦次に衝突判定(コリジョン)の設定を行います。
体はバラバラなので体を結合したメッシュを用意して
Genesis8FemaleSkin_for_MantCollider
衝突判定用のジオメトリに使います。
Genesis8FemaleSkin_for_MantColliderを選択して FX > nCloth > Create Passive Collider を実行します。
nRigid1が作成されます。

ーーーブレンドシェイプをつかった調整ーー
⑩揺れ具合などの調整は、hairSystem1の各アトリビュートで行いますが、タイミング毎に調整するのは大変です。
揺れを抑えるのみであれば、BlendShapeのWeightアトリビュートを使用すると簡単に制御できます。
curve1とcurve2を選択してBlendShapeを設定し、
curve2のアトリビュートについたBlendShape1のcurve1というWeightアトリビュート(0~1)を調整して制御します。

ーーーオフセット用のコントローラーを付ける場合ーー
⑪次に、オフセット用のジョイント(コントローラー)の設定を行います。
再生を止めて0フレーム目に戻し、初期ポーズにします。
joint1~7のジョイントを複製し、joint1Offset~7に名前を変更します。
joint1Offset~7のジョイントを複製し、joint1Offset_space~7に名前を変更します。
joint1Offset_spaceジョイントの中にそれぞれjoint1Offsetを入れていきます。
※Spaceノードについてはこちら。https://backbone-studio.com/post-237-3/

⑫一番親のjoint1Offset_spaceを選択し、FreezeTransformationsを実行してRotateの値をjointOrientに移植します。

joint1Offset_space~7からjoint1~7へTranslateとRotateをコンストレインします。

AポーズからTポーズにしてモーションの流し込みやすいMaya HumanIKスケルトンにキレイにモデルを合わせる方法1~Duplicateで固まるメッシュ※0 を使う方法~

AポーズからTポーズにしてモーションの流し込みやすいMaya HumanIKスケルトンにキレイにモデルを合わせる方法1~Duplicateで固まるメッシュ※0 を使う方法~

きれいにというのは「もとのAポーズのモデルのスキンウェイトをつかってTポーズにしようとしてる」と「新しいjointはできるだけHumanIKのジョイントで作ることでHumanIKでバグらせないことが目標」

大きな流れは
 ジョイントをHIKに差し替え→AポーズからTポーズ→Tポーズでのバインド

1,AposeモデルにMeshEdit用のApose JointをHumanIKスケルトンを複製して作る
(これでHumanIKのベースのジョイント方向や階層構造をキープすると流し込みが完璧になる)
2,そのMeshEdit用のjointをスケールしないで移動と回転などしてApose Meshに合わせる。
2.5,MayaHumanIKにはない頭のジョイントをコピーして親子付けする※1

3,Apose MeshにあわせたそのMeshEdit用のApose jointとApose meshをスキンのバインドする 
3.5 元のAposeモデルからのAposeのスキンウェイトのコピーをする。

4.1見る用にHumanIKスケルトンデフォルトのTposeを複製して作る
4.2 AposeジョイントをAポーズからTポーズにアニメーション30でTポーズに全部「S」でキーを打つ 必要なのは肩のキーだけだ。他に見る用にHumanIKスケルトンに足幅が合ってなければもも関節もキーを打つ。
5,Tposeへ変形+バインドされたApose MeshグループをTポーズの30フレームで「Mesh+Joint」のグループごと複製したグループC(groupMeshHIK_Tpose)とする

6.Cのスキンバインドを外す、
6a. フレームヘッドを0フレームに移動し、
6b. Tポーズのジャケットなどをインポートして、
6c. 0 frame Tposeでスキンバインドここ重要
6d. 30 frameでスキンウェイトをコピーここが肝
※Genesis8Femaleの場合スキンウェイトのコピーの設定※
7a,CをHumanIKスケルトン(groupMeshHIK_TposeSK)として定義
モーション流し込みなおすならこのファイルから
 Genesis8Skelton_HumanIK_049_group_meshHIK_AposeToTposeFr30humanIKfinger.mb
https://www.mediafire.com/file/n4ekyeubv6c4m96/Genesis8Skelton_HumanIK_049_group_meshHIK_AposeToTposeFr30humanIKfinger.zip/file
 これに下のMotionMergeツールで作成したmbアニメーション全体を読み込む
 >>full_end_python_saved__all_onetimeline.mb 読み込まれるファイル
7b.HumanIkの青のボタン>定義>スケルトン
 HumanIkの青のボタン>編集>定義>名前の変更
 SK_manequinを「Character_SK_Mannequin」としてHumanIKに定義する。
 全身Assainしていくことになるが、アサイン結果が左右ミラーされるのでちょっと楽
 手の指先までやる。
 

8,groupMeshHIK_TposeSKに2段目のソースにアニメーションを指定してモーションを流し込む 詳細は※2
8a, スケルトン定義に移動して青のボタンから編集>定義>プロパティを編集
8b.リターゲット指定からソースの一致をONにすると歩く歩幅が合わせることが可能
8c.達成度の項目の左手首を1に右手首を1に指定すると手の位置が合ってテーブルのコップがつかめます。ここでやっとアニメーションの見た目が完璧近い状態で合う。
8d.HumanIKパネルに戻って、青いボタンからベイク処理>コントロールリグのベイク処理
8f. ソースのモーションスケルトンをアウトライナから削除とソースキャラクタ定義へ移動しをゴミ箱アイコンで削除。

8f2ここまでやったらアニメーションレイヤー使うかどうかはモーション作業内容次第。
  
 8g.アニメーションレイヤーでの調整作業。
  ベイクしたTポーズ定義でなく「コントロール」タブで背景を
  ダブルクリックしてコントロールリグを全選択し
  (とビデオではいっているがアウトライナで選択しないと指が全部にならなかった。)、  
   チャネルボックス・レイヤエディタ・アニメーションタブを開く。
 8h.アニメーションタブで「選択項目からレイヤを作成」でAnimLayer1が
  作成され上乗せでキーをうつことが可能になる。
 8i.二つのアニメーションレイヤーを選択して右クリックから
  レイヤーのマージでアニメーションをベイクします。

  1. コントロールリグアニメーションを直接編集しなおす。
      リグのキーフレームをフレーム間で削除して修正
      前のリグアニメを書き出した
      それはこれを使った
    https://furcraea.verse.jp/wp/2021/03/18/humanik-effector-ctrl-animationexporter-importer/

10a groupMeshHIK_TposeSK にコントローラのアニメーションをベイクします。
ジョイントツリーを全部開いて選択後、タイムレンジを0~1000(最終fr)に設定
 アニメーションタブのアニメーションのベイクボタンを押す。
10b,FBXをエクスポート スムーズメッシュをオン FBX2014/2015 で書き出し。
E:\Download\Game\UE4_SK_Mannequin_Motions\scenes\OneTimeLine\Unity_fbx
motion_000_000_all_unkeyReduction_fbx.fbx
を上書きします。

10c,UE4で編集>プラグイン>プラグインウィンドウで検索pythonと入力し
Python Editor Script Pluginの Enables をチェックを入れONにします。
プラグインウィンドウで検索Editorと入力し
Editor Scripting Utilitiesの Enables をチェックを入れONにします。
UE4を再起動してプラグインをアクティブにします。

10d.UE4で
見た目でいうと
/コンテンツ/UE4_OneTimeLineGenesis8Tpose/
パスでいうと
/Game/UE4_OneTimeLineGenesis8Tpose/
にmotion_000_000_all_unkeyReduction_fbx.fbxを
インポートウィンドウでスケルトン設定を「なし」で
スケルタルメッシュとしてインポートします。
スケルタルメッシュmotion_000_000_all_unkeyReduction_fbxと
ひとつなぎのアニメーション motion_000_000_all_unkeyReduction_fbx_Anim
ができていたら
/Game/UE4_OneTimeLineGenesis8Tpose/motion/ フォルダを作成しておきます
command + shift + s またはファイル>すべて保存します。

10d.アニメーションスプリットツールでインポートします。

UE4_SK_Mannequin_Motions\script\
UE4_chara_anim_split_importer.py
をテキストエディタで開き
E:\Download\Game\UE4_SK_Mannequin_Motions\
を自分のパスに検索置換します。

それをすべて選択して
UE4 >ウィンドウ>デベロッパーツール>アウトプットログの一番下のCmdのプルダウンをPython(無印)を選択して
Enter Python script…の部分に
さきほどのコピーしたものをペーストし+Enterを押します。
8~10分で読み込まれます。
~やっと終わり~

モーションを修正する場合には

  1. コントロールリグアニメーションを直接編集しなおす。
    からやりなおせばOK

と思ったが
Paragliderのプロジェクトに入れたら問題が出てきた。
UE4のジョイント名でないとr_handからik_handが探せないエラー
できあがったモーションセットをソースとしてSK_mannequinに戻す作業が必要そうだ。
motion_000_000_all_unkeyReduction_fbx.fbxを
つづく。。。

※0 Duplicateで固まるメッシュ というのは スキンバインドしてアニメーションさせたMeshをモーション後のフレームでDuplicate するとその複製されたメッシュがその形状のまま固まる現象をいう。ちょっとしたバグなのか仕様なのかわからない。都合がいい。

※1 MayaHumanIKにはない頭のジョイントをコピーして親子付けすると変なtransformができるが、全ジョイントのスケールをフリーズして、ヒストリ削除したら親子付けできる。
https://www.deathponta.com/entry/190724_parentingAjointProduceMysteriousTransformNode

※2 HumanIKモーションの流し込みのビデオ
https://area.autodesk.jp/movie/start-at-maya/24.html
https://www.youtube.com/watch?v=S214-96uXqc

使用+橋渡しができたプラットフォームのデータ
ここでは DAZ 3D Studio のGenesis8FemaleはAposeなのでHumanIKのTposeにする。
モーションはUnrealEngine4のデフォルトSK_Mannequinのモーションを
書き出して使った。

UE4 FBX Export Options 設定は
▼Exporter
 Fbx Export Compatibility > FBX2013
▼Mesh
 Vertex Color OFF
 Level Of Detail OFF
▼Static Mesh
 コリジョン OFF
▼Skeletal Mesh
 Export Morph Targets OFF
▼Animation
 Export Preview Mesh ON
 Map Skeletal Motion to Root OFF

全モーションのマージにはこれを作った (書き直したが疲れた。)
https://www.mediafire.com/file/x9tdw9jtrl0t2p2/MotionMerge_p030motionbuilder_chimera_0_Start2.zip/file
インストール方法
C:\Users\whaison\Documents\maya\2016\ja_JP\scripts
にpythonフォルダごと突っ込む。

Maya起動後
プロジェクト設定で指定するワークスペースのディレクトリ構造はこう。
scenes\motion\motionbuilder_fbx\ にUE4SK_mannequinのモーションfbxを全部突っ込む
ファイル名は名前順で並ぶようにちゃんとリネームしておくこと。

C:\Users\whaison\Documents\maya\2016\ja_JP\scripts\python\MotionMerge\p030motionbuilder_chimera_0_Start
Motionbuilder_chimera_0_Start_______Maya_____Starter.py
の内容をスクリプトエディタで実行する。と30分後?ぐらいに
scenes\OneTimeLine\
full_end_python_saved__all_onetimeline.mb
ができあがる。

フレームのどこの部分に該当のモーションが入ってるかは下に出力した。
scenes\motion に
frameCSV.txt
motion_[C0000]_000_Tstance,0,0,OnMotionStart,0.0,OnMotionEnd,1.0,
motion_0000_00_000_Tstance_manual,10,10,OnMotionStart,0.0,OnMotionEnd,1.0,
motion_0000_00_000_Tstance,20,20,OnMotionStart,0.0,OnMotionEnd,1.0,
motion_ZZZZ_ZZ_999_TposeEnd,30,30,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPersonIdle,40,103,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPersonJump_Loop_previewMesh2,113,130,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPersonJump_Start,140,151,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPersonRun,161,175,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPersonSwordAttack2,185,206,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPersonWalk,216,240,OnMotionStart,0.0,OnMotionEnd,1.0,
ThirdPerson_Jump,250,254,OnMotionStart,0.0,OnMotionEnd,1.0,
TJ_Paraglider_Deploy_Additive,264,356,OnMotionStart,0.0,OnMotionEnd,1.0,
TJ_Paraglider_Idle,366,606,OnMotionStart,0.0,OnMotionEnd,1.0,
TJ_Paraglider_Idle_AdditiveBase,616,616,OnMotionStart,0.0,OnMotionEnd,1.0,
TJ_Paraglider_Moving_Additive,626,650,OnMotionStart,0.0,OnMotionEnd,1.0,
TJ_Paraglider_Turning_Additive,660,684,OnMotionStart,0.0,OnMotionEnd,1.0,
TK_0-26_A_LedgeClimb,694,720,OnMotionStart,0.0,OnMotionEnd,1.0,
TK_30-102_A_LedgeHold,730,802,OnMotionStart,0.0,OnMotionEnd,1.0,
TK_120-144_A_wallclimb,812,836,OnMotionStart,0.0,OnMotionEnd,1.0,
TK_160-184_A_wallclimbDown,846,870,OnMotionStart,0.0,OnMotionEnd,1.0,
TK_200-249_A_wallCling_01,880,929,OnMotionStart,0.0,OnMotionEnd,1.0,

これをUE4読み込み時にUE4Pythonスクリプトで使う
同じZIPの
https://www.mediafire.com/file/d82x4dd6o1a4k28/MotionMerge_p030motionbuilder_chimera_0_Start4.zip/file
UE4_chara_anim_split_importer.py
E:\Download\Game\UE4_SK_Mannequin_Motions\script\UE4_chara_anim_split_importer.py
に移動して使う
E:/Download/Game/UE4_SK_Mannequin_Motions/scenes/OneTimeLine/
Unity_fbx/motion_000_000_all_unkeyReduction_fbx.fbxが入ってる前提で動く
必要な場合はパスを検索置換したらうごく。


※Genesis8Femaleの場合スキンウェイトのコピーの設定※は
サーフェースの関連付け:UV空間 or レイキャスト
インフルエンスの関連付け1:名前
インフルエンスの関連付け2:なし
インフルエンスの関連付け3:なし
にしたら顔のウェイトが比較的良く転送できた。目の周りのジョイントは位置が同じでUVは違うのでこうなったようだ。
といってもこんなもん
コピー元


コピー先

ほかの設定だと全くコピーされないか、完全におかしいコピーだった。

キーワード
Daz3D,DazStudio
UE4,UnrealEngine4,UnrealEngine
HumanIK
Apose,Tpose,AposeからTposeへの変換
スキニング,スキンウェイト

UE4 IK Two Bone IKノード Paraglider アセットで手をグライダーにかける方法

UE4 IK Two Bone IKノード Paraglider アセットで手をグライダーにかける方法

モデルを変更した結果
Paragliderのプロジェクトに入れたら問題が出てきた。
UE4のジョイント名でないとr_handからik_hand、lowerarm_lが探せないエラー

LogAnimation: Warning: FBoneReference::Initialize BoneIndex for Bone ‘lowerarm_l’ does not exist in Skeleton ‘motion_000_000_all_unkeyReduction_fbx_Skeleton’


lowerarm_lだけならTwo Bone IKノードのJointTarget>JointTarget>lowerarm_lを別のヒジジョイント名に変えるだけでOKだ。


そんなことは後で知ったので
Mayaでjointの名前を変更した。>大変だったが必要なのは
root>ik_hand_root>ik_hand_r と
root>(hipあってもなくてもいい)>pelvis >spine_01>spine_2>spine_03>clavicle_r>upperarm_r>lowerarm_r>hand_r
の流れだった。
実はヒジのジョイント名だけでいいかもしれない
あとはちゃんとik_hand がhandジョイントにコンストレインされて同じように動いていることかもしれない。

いがいと、ジョイント名が変わっても
ジョイント位置+メッシュ頂点位置でスキンウェイトコピーが反応してくれて大丈夫だった

「余裕がないとかからない」ので
ThirdPersonCharactor_BPのビューポートでParagliderComponent_BPの位置を
位置
z:109.897697
から
z:85にして近づけたら
グライダーとモデルの間隔がせばまって届くようになった。