ikソルバーとは?

ikつまり逆運動学の問題を解く計算方法のこと
たとえば

つま先から各関節の位置を決める計算方法のことで

ikハンドル(エンドエフェクタ)の位置や姿勢が与えられたときに、その位置や姿勢を達成するために必要な各関節の角度を求めます。

ソルバー計算で、この逆運動学問題を解くことで、3Dキャラクターやロボットアームなどの動きを制御することができます。

IKソルバー計算には、様々な種類があります。代表的なものには、運動学的制約を用いる数値的解法や、数学的最適化問題を解く方法などがあります。

IKソルバーは、3Dキャラクターやロボットアームなどの動きを制御するためのアルゴリズムのことです。
例えば、ロボットアームが目標の位置に移動するために、各関節の角度を計算して制御する際に使用されます。これにより、子供たちも楽しめるロボットの動きが実現されます。

[unrealEngine,Maya]で腕や足がスカートを貫通しないようにしたい

あくまで、自分の研究例ですと
スカートで足に追従させたいものは
「膝にスキニングしたほうが作業的に効率的」です。
ジャンプや走るモーションで
前側のスカートは膝で突き破るので、
膝にスキンウェイト当てておきます。
というより

タイトスカートのスキンウェイトは、まず足にスキンウェイトを足の一部のようにスキンウェイトをコピーします。
前側の又の部分は左右の足から同じ左0.5、右0.5になるようにスキンウェイトします。
ロングタイトスカートはこれでできます。

スカートのケージモデルが膝に追従する例です。
ただ、まだ、突き破っているので、スカートモデルと体の隙間をもっと大きくした方がいいでしょう


あとは物理で動かしたい頂点は下のようにします
さらに、フレアスカートの場合は
スカートの左右と後ろ部分は、放射状にジョイントをいれヒザのスキンウェイトとグラデーションするようにスキンウェイトします。あとは、おかずさんのkawaii physics で、マニュアル通り設定します。

関連

AmbitionEarlyHourSky

#アンリアルクエスト に出したゲームのクオリティをアップした。

キャラクターの作り直しを何度もやった。

ハイヒールのカラーをルブタンみたいにして

ニーアみたいなマスクをつけて
kawaiiphysicsでスカートをひらひらさせた。
kawaiiphysicsで胸も揺らした
kawaiiphysicsで髪をなびくようにジョイントを入れ

レベルデザインも少しちゃんとした。

#kawaiiphysics #UE4 #Unrealお兄さん と#塩谷さん と #おかず さん の おかげです。

ダウンロードはこちら

https://drive.google.com/file/d/1q6O0NIBkd-oH1zD50XCDv74sUi6QfIai/view?usp=sharing

最近開いてみたらこんなエラーが出た

This Project requires the ‘ShallowWater’ plugin whitch could not be found.Would you like to desable it continue?If you do you will no longer be able to open any assets created with it. if not the application will close.

このプロジェクトには、見つからなかった「ShallowWater」プラグインが必要です。引き続き無効にしますか?そうすると、それで作成されたアセットを開くことができなくなります。 そうでない場合、アプリケーションは終了します。

ビルドの必要がありそうなので

A案

cd C:\Program Files\Epic Games\UE_5.0\Engine\Build\BatchFiles
Build.bat AmbitionEarlyHourSky Win64 Development "F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\AmbitionEarlyHourSky.uproject" -rocket

B案

cd C:\Program Files\Epic Games\UE_5.0\Engine\Binaries\DotNET\UnrealBuildTool
UnrealBuildTool.exe AmbitionEarlyHourSky Win64 Development "F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\AmbitionEarlyHourSky.uproject" -rocket

ERROR: Unable to find plugin ‘ShallowWater’ (referenced via AmbitionEarlyHourSky.uproject). Install it and try again, or remove it from the required plugin list.

と言われるので。

AmbitionEarlyHourSky.uprojectの Plugin から ShallowWaterを消す。

{
	"FileVersion": 3,
	"EngineAssociation": "5.0",
	"Category": "",
	"Description": "",
	"Modules": [
		{
			"Name": "AmbitionEarlyHourSky",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"Engine"
			]
		}
	],
	"Plugins": [
		{
			"Name": "ShallowWater",
			"Enabled": true
		},
		{
			"Name": "Water",
			"Enabled": true
		},
		{
			"Name": "PythonScriptPlugin",
			"Enabled": true
		},
		{
			"Name": "EditorScriptingUtilities",
			"Enabled": true
		},
		{
			"Name": "Bridge",
			"Enabled": true,
			"SupportedTargetPlatforms": [
				"Win64",
				"Mac",
				"Linux"
			]
		}
	]
}

Build.batできたっぽい


C:\Users\furcr>cd C:\Program Files\Epic Games\UE_5.0\Engine\Binaries\Win64\

C:\Program Files\Epic Games\UE_5.0\Engine\Binaries\Win64>cd ../../

C:\Program Files\Epic Games\UE_5.0\Engine>cd C:\Program Files\Epic Games\UE_5.0\Engine\Build\BatchFiles

C:\Program Files\Epic Games\UE_5.0\Engine\Build\BatchFiles>Build.bat AmbitionEarlyHourSky Win64 Development "F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\AmbitionEarlyHourSky.uproject" -rocket
Using bundled DotNet SDK
Log file: C:\Users\furcr\AppData\Local\UnrealBuildTool\Log.txt
Creating makefile for AmbitionEarlyHourSky (Build.version is newer)
ERROR: Unable to find plugin 'ShallowWater' (referenced via AmbitionEarlyHourSky.uproject). Install it and try again, or remove it from the required plugin list.

C:\Program Files\Epic Games\UE_5.0\Engine\Build\BatchFiles>Build.bat AmbitionEarlyHourSky Win64 Development "F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\AmbitionEarlyHourSky.uproject" -rocket
Using bundled DotNet SDK
Log file: C:\Users\furcr\AppData\Local\UnrealBuildTool\Log.txt
Creating makefile for AmbitionEarlyHourSky (Build.version is newer)
Parsing headers for AmbitionEarlyHourSky
  Running UnrealHeaderTool "F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\AmbitionEarlyHourSky.uproject" "F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\Intermediate\Build\Win64\AmbitionEarlyHourSky\Development\AmbitionEarlyHourSky.uhtmanifest" -LogCmds="loginit warning, logexit warning, logdatabase error" -Unattended -WarningsAsErrors -abslog="C:\Users\furcr\AppData\Local\UnrealBuildTool\Log_UHT.txt" -installed
Reflection code generated for AmbitionEarlyHourSky in 6.3933034 seconds
Building AmbitionEarlyHourSky...
Using Visual Studio 2019 14.29.30141 toolchain (C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133) and Windows 10.0.18362.0 SDK (C:\Program Files (x86)\Windows Kits\10).
[Adaptive Build] Excluded from AmbitionEarlyHourSky unity file: MyBlueprintFunctionLibrary.cpp, SaveToText.cpp, TextFileToString.cpp, AmbitionEarlyHourSky.cpp, AmbitionEarlyHourSkyCharacter.cpp, AmbitionEarlyHourSkyGameMode.cpp
Distributing 23 actions to XGE
--------------------Build System Warning---------------------------------------
License is invalid:
    License information is invalid. Please try reloading your license file using the Coordinator Monitor application on the Coordinator machine, or reinstall IncrediBuild.
    This build will run in standalone mode.

-------------------------------------------------------------------------------

Build ID: {5E64F7BF-47B0-4AF8-8F9B-4464A50705EC}

--------------------Project: Default-------------------------------------------
[1/23] SharedPCH.Engine.ShadowErrors.cpp (0:51.37 at +0:00)
[2/23] OpenImageDenoise.dll (0:00.64 at +0:51)
[3/23] tbb.dll (0:00.26 at +0:52)
[4/23] d3d12SDKLayers.dll (0:00.31 at +0:52)
[5/23] D3D12Core.dll (0:00.28 at +0:52)
[6/23] tbb12.dll (0:00.31 at +0:52)
[7/23] AmbitionEarlyHourSkyCharacter.cpp (0:01.64 at +0:53)
[8/23] AmbitionEarlyHourSkyGameMode.cpp (0:01.01 at +0:54)
[9/23] SaveToText.cpp (0:00.60 at +0:55)
[10/23] MyBlueprintFunctionLibrary.gen.cpp (0:00.62 at +0:56)
[11/23] AmbitionEarlyHourSkyCharacter.gen.cpp (0:00.92 at +0:57)
[12/23] MyBlueprintFunctionLibrary.cpp (0:00.57 at +0:58)
[13/23] TextFileToString.gen.cpp (0:00.62 at +0:58)
[14/23] AmbitionEarlyHourSky.cpp (0:00.70 at +0:59)
[15/23] AmbitionEarlyHourSky.init.gen.cpp (0:00.64 at +1:00)
[16/23] TextFileToString.cpp (0:15.11 at +1:00)
[17/23] AmbitionEarlyHourSkyGameMode.gen.cpp (0:01.00 at +1:15)
[18/23] Default.rc2 (0:00.48 at +1:16)
[19/23] Module.KawaiiPhysics.cpp (0:03.53 at +1:17)
[20/23] Module.KawaiiPhysics.gen.cpp (0:03.40 at +1:20)
[21/23] SaveToText.gen.cpp (0:00.65 at +1:24)
[22/23] AmbitionEarlyHourSky.exe (0:26.03 at +1:24)
   Creating library F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\Binaries\Win64\AmbitionEarlyHourSky.lib and object F:\Download\Game\AmbitionEarlyHourSky6.0NoCascade\Binaries\Win64\AmbitionEarlyHourSky.exp
[23/23] AmbitionEarlyHourSky.target (0:00.34 at +1:50)
---------------------- Done ----------------------

    Rebuild All: 1 succeeded, 0 failed, 0 skipped

1 build system warning(s):
   - License is invalid

Total time in XGE executor: 111.50 seconds
Total execution time: 128.20 seconds

C:\Program Files\Epic Games\UE_5.0\Engine\Build\BatchFiles>

リビルドするか聞かれる。リビルドで、30秒後ぐらいに起動した!

スカートのリグなどを頑張ったオリジナル作品のAmbitionSkyWaterをUE5でビルドしなおして、ポスプロなどブラッシュアップして動画を取り直した #UE5 #UnrealEngine5 #スカート #リグ #Rig #skirts

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

より。

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

揺れもの 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をコンストレインします。