TexturePath Replace Python Script for Maya

Select HyperShade Textures And Do Script
import maya.cmds as cmds
import pymel.core as pm
import os

def remap_selected_texture(z_path):
    
    # figure out what's selected
    selected = pm.ls(sl=True)
    workspace_path = cmds.workspace(query=True, rootDirectory=True)
    print("workspace_path= "+workspace_path)
    for item in selected:
        test_path = pm.getAttr(item+".ftn")
        fileName = test_path.split('/')[-1]
        fileName = fileName.replace('//', '')
        fileName = fileName.replace('/', '')
        print("fileName2= "+fileName)
        #if ':' not in test_path:
        if(fileName=="GraceYong_ArmsColorD1001.jpg"):
            fileName="GraceYong_ArmsColorD_1001.jpg"
        if (1==1):   
            
            #print("fileName1= "+fileName)
            
            
            #new_path = os.path.join(z_path, 'cartoon_room', second)
            new_path = os.path.join(workspace_path,z_path, fileName)
            new_path = new_path.replace('\\', '/')
            new_path = new_path.replace('//', '/')
            relative_path = os.path.join(z_path, fileName)
            relative_path = relative_path.replace('\\', '/')
            new_path = new_path.replace('//', '/')
            if os.path.exists(new_path):
                if(fileName==""):
                    print("item= "+str(item)+" is No fileName= "+ fileName)
                    cmds.select( str(item), r=True )
                    cmds.delete( str(item) )
                else:
                    print("new_path= "+new_path+' is exists! OK')
                    pm.setAttr(item+'.ftn', new_path)
                #pm.setAttr(item+'.ftn', relative_path)
            else:
                print("new_path= "+new_path+ ' not exists NG' )
        if os.path.exists(test_path):
            pass
        else:
            PersonalIndex=test_path.find("Personal")
            if(PersonalIndex==-1):
                pass
            else:
                print("test_path= "+test_path+ ' not exists NG' )
                pm.setAttr(item+'.ftn', "")
                cmds.select( str(item), r=True )
                cmds.delete( str(item) )
         
    cmds.select(selected)
    print("--------------remap_selected_texture----------END")
    
remap_selected_texture("GraceYong.images")

モデルフォルダの自動認識と出力フォルダ引数のパターン

#remap_selected_filenode_texture_path
import maya.cmds as cmds
import pymel.core as pm
import os

def remap_selected_texture(z_path):
    
    # figure out what's selected
    selected = pm.ls(sl=True)
    # workspace_project_path
    workspace_path = cmds.workspace(query=True, rootDirectory=True)
    print("workspace_path= "+workspace_path)
    # ma_file_path
    ma_file_path=cmds.file(q=True, sn=True)
    print("ma_file_path= "+ma_file_path)
    ma_file_path_arr = ma_file_path.split('/')
    ma_Folder=ma_file_path_arr[-2]
    
    print("ma_Folder= "+ma_Folder)
    for item in selected:
        item_path = pm.getAttr(item+".ftn")
        print("item_path= "+item_path)
        item_path_arr = item_path.split('/')
        texFolderName = item_path_arr[-2]
        print("texFolderName= "+texFolderName)
        fileName = item_path_arr[-1]
        print("fileName= "+fileName)
        fileName = fileName.replace('//', '')
        fileName = fileName.replace('/', '')
        print("fileName2= "+fileName)
        
        
        
        #if ':' not in test_path:

        if (1==1):   
            
            #print("fileName1= "+fileName)
            
            
            #new_path = os.path.join(z_path, 'cartoon_room', second)
            new_path = os.path.join(workspace_path,z_path, fileName)
            new_path = new_path.replace('\\', '/')
            new_path = new_path.replace('//', '/')
            #relative_path = os.path.join(z_path, fileName)
            #====================================================
            relative_path = ma_Folder+"/"+z_path+"/"+fileName
            #====================================================
            print("relative_path= "+relative_path)
            #relative_path = relative_path.replace('\\', '/')
            abs_path = os.path.abspath(workspace_path+"/"+relative_path)
            abs_path = abs_path.replace('//', '/')
            print(" abs_path= "+abs_path)
            new_path= abs_path
            print(" new_path= "+new_path)
            print("----------------------------end--------------------------")
            
            if os.path.exists(new_path):
                if(fileName==""):
                    print("item= "+str(item)+" is No fileName= "+ fileName)
                    cmds.select( str(item), r=True )
                    cmds.delete( str(item) )
                else:
                    print("new_path= "+new_path+' is exists! OK')
                    pm.setAttr(item+'.ftn', new_path)
                
            else:
                print("new_path= "+new_path+ ' not exists NG' )

    cmds.select(selected)
    print("--------------remap_selected_texture----------END")
    
remap_selected_texture("texture")

Scene押してシーンディレクトリ取得、押してWalkでテクスチャファイルをwalkで自動検索

#remap_selected_filenode_texture_path
import maya.cmds as cmds
import pymel.core as pm
import os
   
def dir_walk(walkDir,TextureFileName):
    resultPath=""
    for curDir, dirs, files in os.walk(walkDir):
        print('===================')
        print("現在のディレクトリ: " + curDir)
        curDir=curDir.replace("\\","/")
        curDir_arr=curDir.split("/")
        
        curDir_endDirName = curDir_arr[-1]
        print("curDir_endDirName= "+curDir_endDirName)
        if(curDir_endDirName==".mayaSwatches"):
            print("処理をスキップします。。。")
            pass
        else:
            
            print("内包するディレクトリ:" + str(dirs))
            print("内包するファイル: " + str(files))
            for fileName in files: 
                if(fileName==TextureFileName):
                    print("Hit : fileName= "+fileName+ "== TextureFileName= "+TextureFileName)
                    resultPath=curDir+"/"+fileName
        print('===================')
    return resultPath
     
def remap_selected_texture2(sceme_path):
    
    # figure out what's selected
    selected = cmds.ls(sl=True)
    # workspace_project_path
    workspace_path = cmds.workspace(query=True, rootDirectory=True)
    print("workspace_path= "+workspace_path)
    # ma_file_path
    ma_file_path=cmds.file(q=True, sn=True)
    print("ma_file_path= "+ma_file_path)
    ma_file_path_arr = ma_file_path.split('/')
    ma_Folder=ma_file_path_arr[-2]
    
    print("ma_Folder= "+ma_Folder)
    for item in selected:
        item_path = cmds.getAttr(item+".ftn")
        print("item_path= "+item_path)
        item_path_arr = item_path.split('/')
        texFolderName = item_path_arr[-2]
        print("texFolderName= "+texFolderName)
        fileName = item_path_arr[-1]
        print("fileName= "+fileName)
        fileName = fileName.replace('//', '')
        fileName = fileName.replace('/', '')
        print("fileName2= "+fileName)
        
        fixTexturePath=dir_walk(sceme_path,fileName)
        print("fixTexturePath= "+fixTexturePath)
        #if ':' not in test_path:

        if (1==1):   
            
            #print("fileName1= "+fileName)
            
            
            #new_path = os.path.join(z_path, 'cartoon_room', second)
            #new_path = os.path.join(workspace_path,z_path, fileName)
            new_path = fixTexturePath
            new_path = new_path.replace('\\', '/')
            new_path = new_path.replace('//', '/')
            #relative_path = os.path.join(z_path, fileName)
            #====================================================
            #relative_path = ma_Folder+"/"+z_path+"/"+fileName
            #====================================================
            #print("relative_path= "+relative_path)
            #relative_path = relative_path.replace('\\', '/')
            #abs_path = os.path.abspath(workspace_path+"/"+relative_path)
            #abs_path = abs_path.replace('//', '/')
            #print(" abs_path= "+abs_path)
            #new_path= abs_path
            print(" new_path= "+new_path)
            print("----------------------------end--------------------------")
            
            if os.path.exists(new_path):
                if(fileName==""):
                    print("item= "+str(item)+" is No fileName= "+ fileName)
                    cmds.select( str(item), r=True )
                    cmds.delete( str(item) )
                else:
                    print("new_path= "+new_path+' is exists! OK')
                    #cmds.setAttr(item+'.ftn', new_path)
                    cmds.setAttr(item+'.fileTextureName', new_path,type='string')
            else:
                print("new_path= "+new_path+ ' not exists NG' )

    cmds.select(selected)
    print("--------------remap_selected_texture----------END")
    

def remap_fileNode_texture(self):
    text_Field_id="remap_selected_filenode_texture_path_Window|USD_layout|pathTxtFld"
    textField_outputFolder = cmds.textField(text_Field_id, q=True, text=True)
    remap_selected_texture2(textField_outputFolder)

def get_scenePath():
    scenefilePath = cmds.file(q=1, sceneName=1)
    mayaPath,mayaFile = os.path.split(scenefilePath)
    #mayaPath = mayaPath + "/Usd/"
    #mayaPath = mayaPath + "/"
    mayaPath=os.path.abspath(mayaPath)
    mayaPath=mayaPath.replace('\\', '/')
    print("mayaPath= "+mayaPath)
    mayaPath_len=len(mayaPath)
    last_str=mayaPath[mayaPath_len-1:]
    print("mayaPath= "+mayaPath+ " last_str= "+last_str)
    if(last_str=="/"):
        pass
    else:
        mayaPath=mayaPath+"/"
    
    return mayaPath

def btn_scene(self):
    scenePath = get_scenePath()
    
    #textureFolder= cmds.textField('textField_outputFolder', q=True, text=True)
    
    
    
    #lastExportDirPath=scenePath+textureFolder+"/"
    
    
    
    set_lastExportDirPath(scenePath)


def set_lastExportDirPath(lastExportDirPath):
    
    selectList=cmds.ls(sl=True)
    if(str(selectList)== "[]"):
        print("なにも選択されていません。0 set_lastExportDirPath")

            
    text_Field_id="remap_selected_filenode_texture_path_Window|USD_layout|pathTxtFld"
    cmds.textField(text_Field_id, edit=True, text=lastExportDirPath)
    cmds.select(selectList)



def createWindow():
    scenefilePath = cmds.file(q=1, sceneName=1)

    USD_window = cmds.window("remap_selected_filenode_texture_path_Window", widthHeight=(400, 200))
    USD_layout = cmds.columnLayout("USD_layout",adjustableColumn=True, parent=USD_window)
    cmds.text (label="選択したハイパーシェードのテクスチャのパスを置換するツールです。", align='left', parent=USD_layout)
    cmds.text (label="シーンのパス以下のフォルダーから検索して自動的に置換します。", align='left', parent=USD_layout)
    cmds.separator(parent=USD_layout)
    cmds.text (label="", align='left', parent=USD_layout)
    
    cmds.text (label="1、Sceneを押してください。", align='left', parent=USD_layout)
    cmds.button(label="Scene", command=btn_scene, parent=USD_layout)
    text_field = cmds.textField("pathTxtFld", parent="USD_layout",text="")
    #cmds.text (label="2、テクスチャフォルダ名を指定してください。", align='left', parent=USD_layout)
    #text_field = cmds.textField("textField_outputFolder", parent="USD_layout",text="texture")
    cmds.separator(parent=USD_layout)
    cmds.text (label="", align='left', parent=USD_layout)

    
    
    
    cmds.text (label="2、HyperShadeのテクスチャTabで(例:file1,file2,複数可)を選択して、ボタンを押してください。", align='left', parent=USD_layout)
    #CheckBox_Absolute_Path_Bool = cmds.checkBox('CheckBox_Absolute_Path', q=True, value=True)
    cmds.button(label="Remap FileNode Texture ", command=remap_fileNode_texture, parent=USD_layout)
    
    #cmds.separator(parent=USD_layout)

    #cmds.button(label="Add USD Referernce/Payload... ", command=add_prim_xform_for_stage_layer, parent=USD_layout)

    cmds.showWindow(USD_window)
    return None

    
def remap_selected_filenode_texture_path():
    if cmds.window("remap_selected_filenode_texture_path_Window",exists=True):
        cmds.deleteUI("remap_selected_filenode_texture_path_Window")
    createWindow()



remap_selected_filenode_texture_path()

maya mel python 環境変数 一覧 path MAYA_SCRIPT_PATH

maya mel python environment variables list path MAYA_SCRIPT_PATH

MEL

//getenv "MAYA_SCRIPT_PATH";//パスを確認

$sPath=`getenv "PATH"`;
print("$sPath= "+$sPath+"\n");
$sMAYA_SCRIPT_PATH=`getenv "MAYA_SCRIPT_PATH"`;
print("$sMAYA_SCRIPT_PATH= "+$sMAYA_SCRIPT_PATH+"\n");

$array = stringToStringArray($sMAYA_SCRIPT_PATH, ";");

for ($MSP in $array) {
    print($MSP+"\n");
}

Python

import os
print("------------------------PATH---------------------------")
ePath = os.environ["PATH"]
ePath_List=ePath.split(";")
for ePath_line in ePath_List:
    #for ev in environ:
    print(ePath_line)

print("------------------------MAYA_SCRIPT_PATH-----------------------------")

mayaScriptPath = os.environ["MAYA_SCRIPT_PATH"]
mayaScriptPath_List=mayaScriptPath.split(";")
for mayaScriptPath_line in mayaScriptPath_List:
    #for ev in environ:
    print(mayaScriptPath_line)

Python3.11 で 簿記3級 の勉強

今回はPython3.11.5を使った。

https://www.python.org/downloads/windows/

python-3.11.5-amd64.exe

まあまあ時間かかる。。。。

システム環境変数追加なんで再起動して下さい。

F:\Python311に入れた

C:\Users\furcr>F:

F:>cd F:\Python311

F:\Python311>pip

動いたら

pip install pandas

動いたら

https://qiita.com/et47/items/ec05beb03c09d79a9f09

をやっていく

とりま


#仕訳をPandasのDataFrame形式で、仕訳帳 df_siwake に入力します。
#Siwakeクラスの関数 entry を呼び出すことで、df_siwakeに仕訳データの行を追加し、更新します。
#仕訳ルール①:借方(左側)、貸方(右側)に勘定科目と金額を記載する
#に従い、仕訳を入力するための空のDataFrameとして仕訳帳 df_siwake を作成します。


import pandas as pd
df_siwake = pd.DataFrame(index=[],columns=['仕訳番号', '日付', '借方科目', '借方金額', '貸方科目', '貸方金額'])
print("df_siwake= "+str(df_siwake))



#仕訳入力時に必ず貸借が一致していることにより、後ほど残高試算表を作るときにも、
#貸借金額が一致することが保証されます。

#そこで仕訳入力用のクラス Siwake を定義し、まずは①複合仕訳の入力に対応する形で
#関数 entry を定義します。

#※最終的には Siwake 内に②データ型チェック、③貸借一致チェックの関数を実装しますが、
#コードが長くなるため、末尾に補足として追記します。

class Siwake:
    def __init__(self):
        self.siwake_no = 0
        print("self.siwake_no= "+str(self.siwake_no))

    def entry(self, df, date, kari, kashi): 
        self.siwake_no += 1 # ...仕訳番号を更新
        print("self.siwake_no= "+str(self.siwake_no))

        for i in range(len(kari)): # ...複合仕訳に対応するため[借方科目、借方金額]の数だけループを回す                    
            kari_entry = pd.Series([self.siwake_no] + [date] + kari[i] + ["", 0], index=df.columns)          
            print("kari_entry= "+str(kari_entry))
            df = df._append(kari_entry, ignore_index=True)

        for i in range(len(kashi)): # ...複合仕訳に対応するため[貸方科目、貸方金額]の数だけループを回す                    
            kashi_entry = pd.Series([self.siwake_no] + [date] + ["", 0] + kashi[i], index=df.columns)
            print("kashi_entry= "+str(kashi_entry))
            df = df._append(kashi_entry, ignore_index=True)

        return df
        
siwake = Siwake()


#仕訳①:会社を設立
#現金1000を元手に会社を設立しました。
#この元手のことを資本金と呼び、仕訳は以下の通りです。
print(u"------------会社を設立-----------")
df_siwake = siwake.entry(df_siwake, 20200401,[['現金', 1000]],[['資本金', 1000]])
df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]

#仕訳②:商品の仕入
#商品500を外部業者より仕入れました。
#仕訳は以下の通りです。
print(u"------------商品の仕入-----------")
df_siwake = siwake.entry(df_siwake, 20200402,[['商品', 500]],[['買掛金', 500]])
df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]

#仕訳③:商品を売上
#仕入れた商品のうち200について、価格300で販売しました。
#売上についての仕訳は以下の通りです。
print(u"------------商品を売上-----------")
df_siwake = siwake.entry(df_siwake, 20200403,[['売掛金', 300]],[['売上', 300]])
df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]

#仕訳④:仕入代金を支払
#仕入代金500のうち300について、外部業者に支払いました。
#(残りの200は翌月支払の契約と仮定します)
#仕訳は以下の通りです。
print(u"------------仕入代金を支払-----------")
df_siwake = siwake.entry(df_siwake, 20200420,[['買掛金', 300]],[['現金', 300]])
df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]

#仕訳⑤:販売代金を回収
#販売代金200について、販売先から現金で回収しました。
#(残りの100は翌月回収の契約と仮定します)
#仕訳は以下の通りです。
print(u"------------販売代金を回収-----------")
df_siwake = siwake.entry(df_siwake, 20200430,[['現金', 200]],[['売掛金', 200]])
df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]

参考URL

https://www.sejuku.net/blog/64370

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

[maya] pymel.tools.mel2py の python3版 変換できない問題がある20220926現在

簡単な解決策はmaya2022 以前の2020,2019バージョンを起動して そこでmel2pyを使うことだ。

A simple solution is to launch a maya2020 or maya2019 version prior to maya2022 and use mel2py there.

githubで解決していると思いダウンロードして試したが無理だった

https://github.com/LumaPictures/pymel/blob/master/pymel/tools/mel2py/melparse.py

import pymel_master.tools.mel2py as mel2py
mel_command = 'setDrivenKeyframe "-currentDriver pCube1.translateY pCube2.translateX";setDrivenKeyframe "-currentDriver pCube1.translateY pCube2.translateY";setDrivenKeyframe "-currentDriver pCube1.translateY pCube2.translateZ";'
pythonCode = mel2py.mel2pyStr(mel_command, pymelNamespace='pm')
print(pythonCode)



import pymel_master.tools.mel2py as mel2py
mel_command = '$currentNodes = `ls -sl -l`;'
pythonCode = mel2py.mel2pyStr(mel_command, pymelNamespace='pm')
print(pythonCode)

python3 Error: AttributeError: file C:\Program Files\Autodesk\Maya2023\Python\lib\site-packages\pymel\tools\mel2py\melparse.py line 438: ‘str’ object has no attribute ‘lineno

StackOverFlowのように

https://stackoverflow.com/questions/73656852/maya-2023-pymel-i-cant-access-mel2py-with-python3/73839888#73839888

上記エラーがでて無理だった。

1行ならどうにかなるが、関数などの複数行だとこのlinenoが取得できないようでバグるものしか作れなかった

        # cycle through our kwargs and format them
        for flag, value in kwargs.items():
            print("melparse.py  - format_command() - "+" flag= "+str(flag)+" ,value= "+str(value))
            if value is None:
                value = '1'

            # multi-use flag
            #    mel:     ls -type "transform" -type "camera"
            #    python:    ls( type=["transform", "camera"] )
            if isinstance(value, list):
                #sep = ', '
                # if len(value) > t.lexer.format_options['kwargs_newline_threshhold']:
                #    sep = ',\n\t'
                #pargs.append( '%s=[%s]' % ( flag, sep.join(value) )  )
                value = assemble(t, 'multiuse_flag', ', ', value, matchFormatting=True)
                #pargs.append(Token('%s=[%s]' % (flag, value), None, flag.lineno))
                pargs.append(Token('%s=[%s]' % (flag, value), None, 0))#mycode
            else:
                print("melparse.py  - format_command() -  flag= "+str(flag))
                #pargs.append(Token('%s=%s' % (flag, value), None, flag.lineno))
                pargs.append(Token('%s=%s' % (flag, value), None, 0))#mycode

本体の更新に期待する。

MayaのAngle Of VIewを求める

MayaのAngle Of VIewは内部計算値なのでGetできない。

    def get_aov(self):
        import math
        focalLength = cmds.getAttr('perspShape.focalLength')
        horizontalFilmAperture = cmds.getAttr('perspShape.horizontalFilmAperture')
        Aov = 2.0 * math.atan(  ( horizontalFilmAperture * 25.4 ) / ( focalLength*2.0 )  )
        #Aov = 2 * math.atan(float(horizontalFilmAperture) / (2*float(focalLength)))
        Aov = math.degrees(Aov) # 19.2600082544
        Aov = round(Aov, 2)
        return Aov

[maya]ウェイトのリストを高速に取得してみる。

基本は

cmds.skinPercent( skincluster, vtx, transform=bone, query=True)
経過時間 = 00h:03m:16s

だけどgetAttrでとろうとするとこうなる
参考 http://www.marcuskrautwurst.com/2012/12/skinweights-savingloading-in-pymel.html

経過時間 = 00h:03m:38s  ちょっと遅いんかい。

#get
skincluster="skinCluster1"
vert=8155
influence='joint1'

bones=pm.listConnections(str(skincluster) + ".matrix")

print("bones= "+str(bones))

boneInt=0
boneslen=len(bones)
for b in range(0,boneslen):
    bonename=bones[b]
    if influence in str(bonename):
        print("found hit")
        boneInt=b
print("boneInt= "+str(boneInt))   
evalStr=str(skincluster)+'.weightList['+str(vert)+'].weights['+str(boneInt)+']'
resultVal=pm.getAttr(evalStr)
print("resultVal= "+str(resultVal))

setAttrするにもこう

#set
skincluster="skinCluster1"
vert=8155
influence='joint1'
weight=1

bones=pm.listConnections(str(skincluster) + ".matrix")

print("bones= "+str(bones))

boneInt=0
boneslen=len(bones)
for b in range(0,boneslen):
    bonename=bones[b]
    if influence in str(bonename):
        print("found hit")
        boneInt=b
print("boneInt= "+str(boneInt)) 

evalStr=str(skincluster)+'.weightList['+str(vert)+'].weights['+str(boneInt)+']'
#print("evalStr= "+str(evalStr))
#pm.setAttr('%s.weightList[%s].weights[%s]'%(skincluster,vert,skinData[each].influence),weights)
pm.setAttr(evalStr,weight)

om2でとるとこうなる。参考URL https://jamesbdunlop.github.io/om2/2018/03/29/IOSkins.html

import logging
import time, os
#import simplejson as json
import maya.api.OpenMaya as om2
import maya.cmds as cmds
#from OM2core.plugs.utils import getPlugValue, findPlugOnNode

def findPlugOnNode(node, plugName):
    """
    :param node: MObjectHandle
    :return: MPlug
    """
    if not node.isValid():
        raise Exception("Node is no longer valid!")

    mFn = om2.MFnDependencyNode(node.object())
    for x in xrange(mFn.attributeCount()):
        attr = om2.MFnAttribute(mFn.attribute(x))
        if attr.name == plugName:
            attr = mFn.attribute(plugName)
            plug = om2.MPlug(node.object(), attr)
            return plug

    raise Exception("PlugName {} is not valid!".format(plugName))


def getPlugValue(plug):
    """
    :param plug: MPlug. The node plug.
    :return: The value of the passed in node plug or None
    """
    pAttribute = plug.attribute()
    apiType = pAttribute.apiType()

    # Float Groups - rotate, translate, scale; Com2pounds
    if apiType in [om2.MFn.kAttribute3Double, om2.MFn.kAttribute3Float, om2.MFn.kCompoundAttribute]:
        result = []
        if plug.isCompound:
            for c in xrange(plug.numChildren()):
                result.append(getPlugValue(plug.child(c)))
            return result
    # Distance
    elif apiType in [om2.MFn.kDoubleLinearAttribute, om2.MFn.kFloatLinearAttribute]:
        return plug.asMDistance().asCentimeters()
        # Angle
    elif apiType in [om2.MFn.kDoubleAngleAttribute, om2.MFn.kFloatAngleAttribute]:
        return plug.asMAngle().asDegrees()
        # TYPED
    elif apiType == om2.MFn.kTypedAttribute:
        pType = om2.MFnTypedAttribute(pAttribute).attrType()
        # Matrix
        if pType == om2.MFnData.kMatrix:
            return om2.MFnMatrixData(plug.asMObject()).matrix()
            # String
        elif pType == om2.MFnData.kString:
            return plug.asString()
            # MATRIX
    elif apiType == om2.MFn.kMatrixAttribute:
        return om2.MFnMatrixData(plug.asMObject()).matrix()
        # NUMBERS
    elif apiType == om2.MFn.kNumericAttribute:
        pType = om2.MFnNumericAttribute(pAttribute).numericType()
        if pType == om2.MFnNumericData.kBoolean:
            return plug.asBool()
        elif pType in [om2.MFnNumericData.kShort, om2.MFnNumericData.kInt, om2.MFnNumericData.kLong,
                       om2.MFnNumericData.kByte]:
            return plug.asInt()
        elif pType in [om2.MFnNumericData.kFloat, om2.MFnNumericData.kDouble, om2.MFnNumericData.kAddr]:
            return plug.asDouble()
    # Enum
    elif apiType == om2.MFn.kEnumAttribute:
        return plug.asInt()

    return None

def _iterForSkinCluster(node):
    """
    :param node: MObject for the source connection
    :return: MObject
    """
    if node.apiType() == om2.MFn.kSkinClusterFilter:
        return om2.MObjectHandle(node)

    iterDg = om2.MItDependencyGraph(node,
                                    om2.MItDependencyGraph.kDownstream,
                                    om2.MItDependencyGraph.kPlugLevel)
    while not iterDg.isDone():
        currentItem = iterDg.currentNode() # use currentItem for 2017 and below
        if currentItem.hasFn(om2.MFn.kSkinClusterFilter):
            return om2.MObjectHandle(currentItem)

        iterDg.next()
def _findSkinCluster(mesh=None):
    """
    Returns a skinCluster attached to the kMesh or kNurbsCurve
    @:param mesh: MObjectHandle. Not the shape! Use the transform.
    :return: MObject
    """
    if not mesh.isValid():
        logger.warning("Destination is no longer valid!")
        return

    dagPath = om2.MDagPath()
    geo = dagPath.getAPathTo(mesh.object())

    ## Does it have a valid number of shapes?
    if geo.numberOfShapesDirectlyBelow() != 0:
        ## Fetch the shape of the geo now.
        shapeMobj = geo.extendToShape().node()
        mFn_shape = om2.MFnDependencyNode(shapeMobj)
        apiType = shapeMobj.apiType()
        if apiType == om2.MFn.kMesh:
            ## Look at the inMesh attr for the source
            inMesh_attr = mFn_shape.attribute('inMesh')
        elif apiType == om2.MFn.kNurbsCurve:
            inMesh_attr = mFn_shape.attribute('create')
        else:
            logger.warning("This type of om2.MFn node is not supported! int: {}".format(apiType))
            return

        inMesh_plug = om2.MPlug(shapeMobj, inMesh_attr)
        getSource = inMesh_plug.source().node()

        ## Now use the iterForSkinCluster() function to find the skinCluster in the connected network.
        skinClusterNode_MObjH = _iterForSkinCluster(getSource)

        if skinClusterNode_MObjH is not None:
            return skinClusterNode_MObjH
        else:
            return None

    return None

def _findInfluences(skinClusterMobjH=None):
    """
    Returns all the valid influences from the .matrix attribute on the skinCluster node.
    @:param mesh: MObjectHandle for the skinCluster. Using the handles here may be playing it a little too safe. But meh.
    :return: MObject
    """
    if not skinClusterMobjH.isValid():
        logger.warning("Skincluster is no longer valid! Did it get deleted?")
        return

    skClsMFnDep = om2.MFnDependencyNode(skinClusterMobjH.object())
    mtxAttr = skClsMFnDep.attribute("matrix")
    matrixPlug = om2.MPlug(skinClusterMobjH.object(), mtxAttr)

    ## Get a list of all the valid connected indices in the matrix array now.
    indices = matrixPlug.getExistingArrayAttributeIndices()
    influences = []
    for idx in indices:
        name = om2.MFnDependencyNode(matrixPlug.elementByLogicalIndex(idx).source().node()).absoluteName()
        influences.append(str(om2.MNamespace.stripNamespaceFromName(name)))

    return influences

def fileExists(filePath):
    if filePath is not None and os.path.isfile(filePath):
        logger.info("File exists!")
        return True

    return False

def writetoJSON(filePath, data):
    with open(filePath, 'w') as outfile:
        outfile.write(json.dumps(data))

    return True

def readFromJSON(filePath):
    with open(filePath) as infile:
        data = json.load(infile)
        return data

    return None

def _fetchSkinWeights(geoList=None, skipZeroWeights=True):
    """
    If you send in a list of geo, we'll use that. Else we assume we're working off selected.
    :param geoList: list() of string names for geometry to fetch data for
    :param skipZeroWeights: if you want to avoid saving all 0.0 weight data
    :return:
    """
    geo = om2.MSelectionList()
    if geoList is not None:
        for eachGeo in geoList:
            geo.add(eachGeo)
    else: #Assume selected
        for eachGeo in cmds.ls(sl=True):
            geo.add(eachGeo)

    weightData = {}
    for x in range(geo.length()):
        geoMObjH = om2.MObjectHandle(geo.getDependNode(x))
        geoName = om2.MFnDependencyNode(geoMObjH.object()).name()
        skinClusterMObjH = _findSkinCluster(geoMObjH)
        if skinClusterMObjH is None:
            logger.warning("Skipping {} has no skinCluster!".format(geoName))
            continue

        skName = str(om2.MFnDependencyNode(skinClusterMObjH.object()).name())

        influences = _findInfluences(skinClusterMObjH)
        ## Add the data to the dict
        weightData[geoName] = {}
        weightData[geoName][skName] = {}
        weightData[geoName][skName]['influences'] = influences
        weightData[geoName][skName]['maxInf'] = cmds.skinCluster(skName, q=True, maximumInfluences=True)
        weightData[geoName][skName]['weights'] = {}

        ## Fetch the weights now
        weightPlug = findPlugOnNode(skinClusterMObjH, 'weightList')
        weightCount = weightPlug.getExistingArrayAttributeIndices()
        for x in range(len(weightCount)):
            # .weightList[x]
            p = weightPlug.elementByLogicalIndex(weightCount[x])
            # .weights
            c = p.child(0)

            ## Now fetch the list of idx numbers that should relate to the inf [23, 66, 99]
            w = c.getExistingArrayAttributeIndices()

            ## For each idx we're going to build a tuple (idx, infName, weightVal)
            weightList = list()
            for i in range(len(w)):
                childPlug = c.elementByLogicalIndex(w[i])
                weightValue = getPlugValue(childPlug)

                if skipZeroWeights and weightValue == 0.0:
                    continue

                idx = w[i]
                weightList.append((idx, weightValue))

            weightData[geoName][skName]['weights'][str(x)] = weightList
            print("weightData["+str(geoName)+"]["+str(skName)+"][weights]["+str(x)+"]"+"= "+str(weightList))
    return weightData

weightData=_fetchSkinWeights(None,False)
#print("weightData= "+str(weightData))
_Weights=weightData[dupMesh][skincluster]["weights"][str(vert)]
print("_Weights= "+str(_Weights))


boneInt=0
        bones = pm.listConnections(str(skincluster) + ".matrix")
        boneslen=len(bones)
        for b in range(0,boneslen):
            bonename=bones[b]
            if influence in str(bonename):
                #print("found hit")
                boneInt=b


print("boneInt= "+str(boneInt))
weight=0
for _Weight in _Weights:
     #_Weight=(0, 0.8388942003250122)
     boneNum=_Weight[0]
     if(boneNum==boneInt):
           weight=_Weight[1]
print("weight= "+str(weight))

経過時間 = 00h:07m:10s om2なのに遅い。。。。
データ参照するためにfor分2個使うせいだな。
print消しても
経過時間 = 00h:04m:17s  おそい。。。

もっと早く取りたい

skincluster.getPointsAffectedByInfluence

インフルエンス骨基準で頂点のウェイトを問い合わせ回数を減らすことで早くなる。

getData = skincluster.getPointsAffectedByInfluence(InfluenceJoint)  

で取れるみたい。

詳しくはこちら。

https://www.marcuskrautwurst.com/2012/12/skinweights-savingloading-in-pymel.html


こんな感じで minidomに保存してそこからロードして使う。


import xml.dom.minidom as minidom

class SkinWeight_To_MiniDom():
    def getMeshVertex(self,objName):
        vtx = cmds.ls(objName+'.vtx[*]', fl=True)    
        return vtx
    def _showProgressDialog(self):
        self.WindowRef._showProgressDialog()#---------------------ProgressBar Starting--------------------------
        
    def setProgress(self,count):
        self.WindowRef.setProgress(count)

    def fnFindSkinCluster(self,mesh):
        skincluster = None
        for each in pm.listHistory(mesh):  
            if type(each)==pm.nodetypes.SkinCluster:   
                skincluster = each
        return skincluster
    def fnSaveSkinning(self,mesh,path): 
        print("SkinWeight_To_MiniDom---------fnSaveSkinning("+mesh+" path: "+path+")")
        # 次は、スキンウェイトの保存機能から始めましょう。
        ##skinClusterクラスには、influenceObjects()と呼ばれる関数があり、
        ##skinclusterにバインドされているすべてのジョイントを返します。
        ##次に、基本的に各ジョイントを反復処理し、各インフルエンスに対して関数getPointsAffectedByInfluence()を実行します。
        ##これにより、各頂点とその重みを含むリストが返されます。
        ##これらすべての値を適切なリストに保存し、minidomモジュールを利用してxmlファイルに保存できるようにします。
        
        ## データを収集します
        skincluster = self.fnFindSkinCluster(mesh)
     
        ## スキンクラスターが存在するかどうかを確認します
        if skincluster!=None:
            print(u"スキンクラスターがありました!")
            ## XMLxml_documentを準備します
            xml_doc = minidom.Document()
            xml_header = xml_doc.createElement("influences") 
            xml_doc.appendChild(xml_header)   

            ## ジョイントID/名前テーブルを書き出す  
            for each in skincluster.getInfluence():
                getData = skincluster.getPointsAffectedByInfluence(each)  
                tmpJoint= xml_doc.createElement(each)
                vertData = []
                if len(getData[0])>0:
                    ## すべての頂点IDを収集し、vertDataリストに保存します
                    for each in getData[0][0]:
                        vertData.append(each.currentItemIndex())
                    ## 次に、vertDataリストを「vertices」属性値として保存します
                    tmpJoint.setAttribute("vertices",str(vertData))
                    tmpJoint.setAttribute("weights",str(getData[1]))
                    xml_header.appendChild(tmpJoint)
         
            ## Save XML
            file = open(path, 'w')
            file.write(xml_doc.toprettyxml())
            pm.warning("Saved '%s.skinning' to '%s'"%(mesh,path))
        else:
            print(u"スキンクラスターがありません!")
            pm.warning('No skincluster connected to %s'%mesh)
 

    def fnLoadSkinning(self,mesh,path):  
        
        ##次に、いくつかの変数を使用して関数を設定し、メッシュがすでにスキンされている場合は、そのスキンクラスターを削除するようにします。
        ##後で新しいジョイントを作成し、スキンウェイトファイルに基づいてすべてのジョイントを自動的に追加します。
        
        ## 変数
        jointData = []
        skinData = []

        ### メッシュがすでにスキンされている場合は、メッシュをクリーンアップします
        skincluster = fnFindSkinCluster(mesh)
        if skincluster!=None:
            pm.runtime.DetachSkin(skincluster)
        
        ## 次に、xmlファイルを解析して、すべてのデータを整理しましょう。カスタムクラスcSkinningに基づいてオブジェクトを作成し、
        ## skinDataというリストに保存します。
        
        
        ## ドキュメントを解析し、XML形式に変換して、メモリにロードします
        xml_doc = minidom.parse(path)
        xml_doc.toxml()
         
        ## ルートノードを取得
        joints = xml_doc.childNodes[0].childNodes
    
        ## すべてのデータを収集し、cSkinningオブジェクトをskinDataリストに保存します
        for joint in joints:
            if joint.localName!=None:
                vertices = []
                weights = []
                jointData.append(joint.localName)   
                vertices = eval(joint.attributes.item(1).nodeValue)
                weights = eval(joint.attributes.item(0).nodeValue)
                skinData.append(cSkinning(vertices,joint.localName,weights))
        
        ##skinDataからアイテムをPrintすると、
        ##item.id、item.influence、またはitem.weightsを印刷すると、そのクラスに格納されているデータを確認できます。
        ##インフルエンスとウェイトはコヒーレントテーブルであるため、.weightsのインデックス15はインフルエンス15のウェイトを表すことがわかります。
        ##次に、スキンクラスターを作成し、すべてのジョイントを追加します。ウェイト属性を適用する前に、
        ##normalizeWeights属性を0に設定する必要があります。そうしないと、Mayaはウェイトを追加するたびにスキンウェイトを正規化します。
        ##また、skinPercentを使用してスキンをバインドする場合は、マヤの標準スキンウェイトを削除する必要があります。

        
        skincluster = pm.animation.skinCluster(mesh,jointData)
        skincluster.setNormalizeWeights(0)
        pm.skinPercent(skincluster, mesh, nrm=False, prw=100)
        
        ##ウェイトを適用する前に、最後に行う必要があることが1つあります。MayaはIDに基づいてWeightを保存します。新しいスキンクラスターを追加したため、
        ##これらのIDは古いIDと一致しなくなりました。ここでのこのコードは、skinDataリストでそれらを更新するだけです。
        
        tmpJoint = []
        for storedJoint in jointData:
            for skinnedJoint in skincluster.influenceObjects():
                if skinnedJoint==storedJoint:
                    tmpJoint.append(skincluster.indexForInfluenceObject(storedJoint))
             
        for each in range(0,len(skinData)):  
            skinData[each].influence = tmpJoint[each]
        
        ##素晴らしい、今ここに楽しい部分があります。setAttrを使用してスキンウェイトを追加しましょう。それが終わったら、スキンウェイトの正規化を再度オンにすることを忘れないでください。
        
        for each in range(0,len(skinData)):  
            for vertex in range(0,len(skinData[each].id)):
                vert = skinData[each].id[vertex]
                weights = skinData[each].weights[vertex]   
                pm.setAttr('%s.weightList[%s].weights[%s]'%(skincluster,vert,skinData[each].influence),weights)
                
        ##約30kの頂点を持つメッシュの場合、約3秒かかりました。かなり許容できる約6秒の読み込み。スクリプトはMaya2012でテストされ、
        ##Maya 2013でこれを機能させるのに問題があると聞きましたが、残念ながらまだ調査する時間がありませんでした。聞いてくれてありがとう。
        
        #--------------------------------------------------

class cSkinning(): 
    def __init__(self,id,infl,weights):
        
        ##これでデータを保存できますが、ロードすることもできます。これはもう少し苦痛であることが判明しました。
        ##skinPercentを使用すると、スキンウェイトの設定が非常に遅くなる可能性があります。したがって、この場合、 
        ##setAttrを使用して値を直接設定しました。これはかなり高速です。
        ##少しずつ見ていきましょう。まず、データを効率的に保存するためのクラスを設定します。
    
        self.id = id  
        self.influence = infl
        self.weights = weights



SkinWeight_To_MiniDomClass=SkinWeight_To_MiniDom()
BaseMesh="Mesh"
#cmds.select(BaseMesh)
SkinWeight_To_MiniDomClass.fnSaveSkinning(BaseMesh,"baseMesh_SkinWeight_"+BaseMesh+".txt")

Maya get Mesh Width Height Depth 幅,高さ、奥行きを測る

バウンディングボックスの関数をつかって測る

あくまでMayaの座標系での話だけど、まあ一緒か。

def get_MeshWidthHeightDepth(MeshName):
    boundingBox=cmds.polyEvaluate(MeshName, boundingBox=True )
    print("boundingBox= "+str(boundingBox))
    tapleX=boundingBox[0]
    tapleY=boundingBox[1]
    tapleZ=boundingBox[2]
    
    minX=tapleX[0]
    maxX=tapleX[1]
    depth=maxX-minX
    print("depth= "+str(depth))

    minY=tapleY[0]
    maxY=tapleY[1]
    height=maxY-minY
    print("height= "+str(height))
    
    minZ=tapleZ[0]
    maxZ=tapleZ[1]
    width=maxZ-minZ
    print("width= "+str(width))
    
    return width,height,depth

width,height,depth = get_MeshWidthHeightDepth("pCube2")

#UnrealEngine #UE5 #UE4 #Python .uassetを強引にバイナリファイルとして開いてテキストファイルとして保存してエンコーディングエラーやbytesからストリング変換エラーをうやむやにして文字列としてロード

    def assetPath_to_HDpath(self,assetPath):
        get_project_file_path=unreal.Paths.get_project_file_path()
        HD_get_project_file_path=os.path.abspath(get_project_file_path)
        project_file_dir=os.path.dirname(HD_get_project_file_path)
        project_file_dir=project_file_dir.replace("\\","/")
        unreal.log_warning("project_file_dir= "+project_file_dir)
        # /Game/
        assetHDPath=project_file_dir+"/Content"+assetPath[5:]
        assetHDPath_without_ext = os.path.splitext(assetHDPath)[0]
        assetHDPath_uasset=assetHDPath_without_ext+".uasset"
        unreal.log_warning("assetHDPath_uasset= "+assetHDPath_uasset)
        
        #print("")
        return assetHDPath_uasset
    
    def uasset_textFile_read(self,path):
        file = open(path, 'rb')
        #file = open(path, encoding="utf8", errors='ignore')
        print("1 binary open!!")
        BytesDataBox=b""
        BytesDataStr=u""
        #BytesDataStr = file.read()
        #print("BytesDataStr="+BytesDataStr)
        bytes = file.read(1)
        #print("2 binary valiabled!!")
        while bytes:
            #print(bytes)
            #print("2 printed!!")
            BytesDataBox = BytesDataBox+bytes
            #print("2 BytesDataBox added !!")
            #decoded=bytes.decode("utf-8") 
            #print("2 decoded!!")
            #print(decoded)
            #print("2 decoded printed!!")
            #ByteDataBox=ByteDataBox+decoded
            #print("2 ByteDataBox insert!!")
            bytes = file.read(1)
            #print("2 byte = file.read(1)!!")
        
        print("3 while byte end!!")
        print("BytesDataBox= ")
        #print(BytesDataBox)
        print("4 printed!!")
        print(type(BytesDataBox))
        print("4 class printed!!")
        BytesDataBox=BytesDataBox.strip()
        print("4 striped!!")
        file.close() 
        #BytesDataStr = str(BytesDataBox, 'utf-8')
        #BytesDataStr=BytesDataBox.decode(encoding ='utf-8', errors='ignore')
        self.fileWrite_byte(BytesDataBox)
        BytesDataStr=self.fileRead_byte_()
        print("4 decoded!!")
        

        pattern = r'/Game/.*?\\'

        # findall 
        results = re.findall(pattern, BytesDataStr, re.S)
        results_len=len(results)
        print("results_len= "+str(results_len))
        # Type:list
        print(type(results))
        print("4 all hit list printed!!")
        # 抽出
        for result in results:
            result_len=len(result)
            good_result=result[0:result_len-1]
            print("result_len= "+str(result_len)+"     good_result= "+ good_result)
        
        print("4 for printed!!")
        
    def fileWrite_byte(self,s):
        ReportFolderPath=self.getMyDir()+"Report"
        self.my_makedirs(ReportFolderPath)
        path_cp=ReportFolderPath+"/bytes_"+".txt"
        
        fout_utf = codecs.open(path_cp, 'w', encoding='cp932')
        fout_utf.write(s)
    def fileRead_byte_(self):
        ReportFolderPath=self.getMyDir()+"Report"
        self.my_makedirs(ReportFolderPath)
        path_cp=ReportFolderPath+"/bytes_"+".txt"
        
        fout_utf = codecs.open(path_cp, 'r', encoding='cp932')
        data=fout_utf.read()
        print("4 data!!="+data)
        return data

#UE4 #UE4Study #UE5 #UE5Study #UnrealEngineのPythonScriptPluginのpython3へのPyside2のインストール方法

Pyside2はpipを使ってインストールするのが基本です。

https://forums.unrealengine.com/t/fyi-ue4-switching-to-python-3-7-7-by-default-4-26/151803

より

C:\Program Files\Epic Games\UE_4.26\Engine\Plugins\Experimental\PythonScriptPlugin\Source\PythonScriptPluginPreload\PythonScriptPluginPreload.Build.csで

// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;

namespace UnrealBuildTool.Rules
{
	public class PythonScriptPluginPreload : ModuleRules
	{
		public PythonScriptPluginPreload(ReadOnlyTargetRules Target) : base(Target)
		{
			PublicDependencyModuleNames.AddRange(
				new string[] {
					"Core",
				}
			);

			if (Target.bBuildEditor)
			{
				PrivateIncludePathModuleNames.AddRange(
					new string[] {
						"Python3",
					}
				);
			}
			else
			{
				PrivateDefinitions.Add("WITH_PYTHON=0");
			}
		}
	}
}

となっているのでPython3を参照しているので

::python.exeへ移動して
cd C:\Program Files\Epic Games\UE_4.26\Engine\Binaries\ThirdParty\Python3\Win64
::pip install Pyside2というかんじで詳細はこのようにインストール
python -m pip install --target="C:\Program Files\Epic Games\UE_4.26\Engine\Binaries\ThirdParty\Python3\Win64\Lib\site-packages" Pyside2


するとローカルではうまく起動しました。

参考URL
https://qiita.com/7CIT/items/a480a84bb9d249544f5f

プラグインを有効にする感じのやり方もあります。
Python Editor¥3,177 これをインストールしてしまえば使えるようです。
https://www.unrealengine.com/marketplace/ja/product/python-editor?sessionInvalidated=true

参照