UE4でBluePrintの変数の値をテキストファイルとして保存する方法(UE4.26)

以下を参考にさせてもらいました。

https://htsuda.net/archives/1815

プロジェクトファイル(拡張子が .uproject となっているファイル)があるフォルダの中に Source という名前のフォルダをまず作成します。次にC++ プロジェクトを作成します。プロジェクトファイルを右クリックすると、メニューの中に Generate Visual Studio project files というのがあるのでそれをクリックします。

レベルエディタのメニューから「ファイル File」> 「新規C++クラス New C++ Class」を選びます。親クラスは Actor にします。ファイル名は SaveToText とします。公開設定はパブリックを選んでおきます。クラス作成ボタンを押すとしばらくのコンパイル時間の後にヘッダファイルと cpp ファイルが作成され、VS が開きます。

C++ のエディタが開いていない場合はコンテンツブラウザの C++ クラス(C++ Classes)フォルダ内にある SaveToText のファイルをダブルクリックします。そして、SaveToText.hと SaveToText.cpp を下記のように書き換えます。

クラス名の自動生成されている部分class ゲーム名_APIは書き換えずにおきます。
class AMBITIONEARLYHOURSKY_API USaveToText : public UBlueprintFunctionLibrary
あとは
public: の行以下の部分を追加するだけでOKです。

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "SaveToText.generated.h"

UCLASS()
class AMBITIONEARLYHOURSKY_API USaveToText : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
public:	
    UFUNCTION(BlueprintCallable, Category = "save")
        static bool FileSaveString(FString SaveTextB, FString FileNameB);

    UFUNCTION(BlueprintPure, Category = "save")
        static bool FileLoadString(FString FileNameA, FString& SaveTextA);

    UFUNCTION(BlueprintCallable, Category = "save")
        static FString FileLoadAndReturnString(FString FileNameA);

};

cpp ファイルも下記記のように編集します。以下のコードは https://answers.unrealengine.com/questions/174839/loading-text-to-a-string.html で紹介されているものです(保存以外にもテキストファイルの読み込み関数があります)。ちなみに、クラス名は ASaveToText と先頭に A が付いていますが、これが U であったりする場合もあります。その場合は cpp ファイルの中でクラス名が付いている箇所もそれに合わせるようにしてください。コンパイル時にエラーが出た時はヘッダと cpp ファイルでクラス名が一致していないことが原因だと思われます

// Fill out your copyright notice in the Description page of Project Settings.


#include "SaveToText.h"

// Load and save text files
bool USaveToText::FileSaveString(FString SaveTextB, FString FileNameB)
{
    return FFileHelper::SaveStringToFile(SaveTextB, *( FileNameB));
}

bool USaveToText::FileLoadString(FString FileNameA, FString& SaveTextA)
{
    return FFileHelper::LoadFileToString(SaveTextA, *( FileNameA));
}

FString USaveToText::FileLoadAndReturnString(FString FileNameA)
{
    FString myString;
    bool myBool = true;
    myBool = FFileHelper::LoadFileToString(myString, *( FileNameA));
    return myString;
}

h と .cpp ファイルを保存したら、UE4 のエディタ上でコンパイルボタン(ビルドボタンの右にある)を押します。コンパイルが成功したら作ったこの関数をブループリントで使えるようになります。

レベルブループリントなどを開いて記事冒頭のようなノードを組みます。

そして実行すれば、プロジェクトフォルダ内にテキストファイルが保存されています。やりました!

maya セット(Sets)の概念を理解する

セットとクイック選択セットの 2 つある

ちなみにセットは非破壊(戻せる)、アセットは破壊(戻せない)機能のようだ。

Python

 import maya.cmds as cmds

 いくつかのオブジェクトを作成するーサンプルとして
 cmds.sphere( n="sphere1" ) 
 cmds.cone( n="cone1" ) 

 現在アクティブなものでセットを作成する
 cmds.select( 'sphere1' ) 
 newSet1 = cmds.sets() 
 cmds.select( 'cone1' ) 
 newSet2 = cmds.sets()

 セットのメンバーをクエリする
 cmds.sets( newSet1, q=True )

 2つのセットを含むセットを作成します
 cmds.sets( newSet1, newSet2, name="setOfSets" )

 セットを選択するには、-noExpandフラグを使用する必要があります。さもないと
 代わりにセットのメンバーが選択されます。
 cmds.select( newSet1, noExpand=True ) 
 cmds.ls( selection=True )

 セットのメンバーを選択します
 cmds.select( newSet1 ) 
 cmds.ls( selection=True )

 ballVerticesという名前の頂点セットを作成します。これには含まれます
 球のすべての頂点。
 cmds.sets( 'sphere1', name="ballVertices", vertices=1 ) 
 cmds.select( 'ballVertices' ) 

 2つのセットの和集合を返す
 cmds.sets( newSet2, union=newSet1 )

 セットのリストに共通のメンバーがあるかどうかをテストします
 cmds.sets( 'ballVertices',isIntersecting=newSet1)

 球がセットのメンバーであるかどうかをテストします
 cmds.sets('sphere1',isMember=newSet1)

 球をセットから削除します
 cmds.sets( 'sphere1', remove=newSet1 )

 球がセットのメンバーであるかどうかを再度テストします
 cmds.sets( 'sphere1', isMember=newSet1 )
import maya.cmds as cmds

# いくつかのオブジェクトを作成するーサンプルとして
cmds.sphere( n="sphere1" ) 
cmds.cone( n="cone1" ) 


# 現在アクティブなものでセットを作成する
cmds.select( 'sphere1' ) 
newSet1 = cmds.sets() 
cmds.select( 'cone1' ) 
newSet2 = cmds.sets()

# セットのメンバーをクエリする
cmds.sets( newSet1, q=True )

# 2つのセットを含むセットを作成します
cmds.sets( newSet1, newSet2, name="setOfSets" )

# セットを選択するには、-noExpandフラグを使用する必要があります。さもないと
# 代わりにセットのメンバーが選択されます。
cmds.select( newSet1, noExpand=True ) 
cmds.ls( selection=True )

# セットのメンバーを選択します
cmds.select( newSet1 ) 
cmds.ls( selection=True )

# ballVerticesという名前の頂点セットを作成します。これには含まれます
# 球のすべての頂点。
cmds.sets( 'sphere1', name="ballVertices", vertices=1 ) 
cmds.select( 'ballVertices' ) 

# 2つのセットの和集合を返す
cmds.sets( newSet2, union=newSet1 )

# セットのリストに共通のメンバーがあるかどうかをテストします
cmds.sets( 'ballVertices',isIntersecting=newSet1)

# 球がセットのメンバーであるかどうかをテストします
cmds.sets('sphere1',isMember=newSet1)

# 球をセットから削除します
cmds.sets( 'sphere1', remove=newSet1 )

# 球がセットのメンバーであるかどうかを再度テストします
cmds.sets( 'sphere1', isMember=newSet1 )

重複してたらそのセットから削除してから新規セットに追加する




def unique_obj_sets_make_selected(newSetName):
    #重複してたらそのセットから削除してから新規セットに追加する ---------------------------
    #-------------------------------------------------------------
    selected_arr=cmds.ls(selection=True)#  [pCube9,pCube10,pCube11]
    #newSet01_arr=cmds.sets( "newSet1", q=True )#  [pCube4,pCube5,pCube6]
    #newSet02_arr=cmds.sets( "newSet2", q=True )#  [pCube7,pCube8,pCube9]
    print("selected_arr= "+str(selected_arr))
    #print("newSet01_arr= "+str(newSet01_arr))
    #print("newSet02_arr= "+str(newSet02_arr))
    # python のsetを使ってそれぞれユニーク化する
    selected_set=set(selected_arr)
    #newSet01_set=set(newSet01_arr)
    #newSet02_set=set(newSet02_arr)
    print("selected_set= "+str(selected_set))
    #print("newSet01_set= "+str(newSet01_set))
    #print("newSet02_set= "+str(newSet02_set))
    # old_set を作る(和集合を使う)
    #old_set=newSet01_set | newSet02_set
    #print("old_set= "+str(old_set))
    
    # old_set_full を作る(和集合を使う)
    all_sets=cmds.ls(type="objectSet")
    print("all_sets= "+str(all_sets))
    old_arr_full=[]
    old_set_full=set(old_arr_full)
    for sets_name in all_sets:
        sets_arr=cmds.sets( sets_name, q=True )
        print("sets_arr= "+str(sets_arr))
        
        if(str(sets_arr)=="None"):
            print("None line")
        else:
            print("OK line")
            sets_arr_len=len(sets_arr)
            print("sets_arr_len= "+str(sets_arr_len))
            sets_set=set(sets_arr)
            old_set_full=old_set_full | sets_set
    print("old_set_full= "+str(old_set_full))
    
    # 積集合(共通部分をとる)
    s_intersection = old_set_full & selected_set
    print("s_intersection= "+str(s_intersection))
    list_intersection=list(s_intersection)
    #どこに入ってるかを調べる
    top_all=cmds.ls()
    #------------Get Type Name Code----------- 
    #print("top_all= "+str(top_all))
    #for top_obj in top_all:
    #    objectType=cmds.objectType( top_obj )
    #    print("objectType="+str(objectType)+" top_obj= "+str(top_obj))
    #----------------------------------------
    all_sets=cmds.ls(type="objectSet")
    print("all_sets= "+str(all_sets))
    for sets_name in all_sets:
        set_arr=cmds.sets( "newSet1", q=True )
        for intersect_obj in list_intersection:
            #セットのメンバーであるかどうかをテストします
            isMemberBool=cmds.sets(intersect_obj,isMember=sets_name)
            if(isMemberBool==True):
                print(" sets_name= "+str(sets_name)+" in intersect_obj="+str(intersect_obj))
                #セットから削除します
                cmds.sets( intersect_obj, remove=sets_name )
    
    cmds.select(selected_arr)
    newSet3 =cmds.sets( selected_arr, name=str(newSetName) )
    #newSet3 = cmds.sets() 
    
unique_obj_sets_make_selected("newSet3")

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

より。

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

ThirdPerson Idol UE4 upperarm_twist_01_l is Not shoulder Position

ThirdPerson Idol UE4 upperarm_twist_01_l is Not shoulder Position

Steps.
Step01 Make ThirdPerson Project
Step02 Export FBX ThirdPersonIdle
Step03 Checkbox All OFF
Step04 Checkbox Only Export PreviewMesh ON
Step05 Export
Step06 Open FBX
Step07 Check upperarm_twist_01_l is Not shoulder Position
Step08 Check lowerarm_twist_01_l is Not hand_l Position

Step07 Check upperarm_twist_01_l is shoulder Position
Step08 Check lowerarm_twist_01_l is hand_l Position

ThirdPersonIdle.FBX
ThirdPerson_Jump.FBX
ThirdPersonJump_End.FBX
ThirdPersonJump_Loop.FBX
ThirdPersonJump_Start.FBX
ThirdPersonRun.FBX
ThirdPersonWalk.FBX
is All Have this miss takes

nobolu.ootsuka.unrealengine@gmail.com

ハイポリモデルのスキニングのための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も閉じます。