前言
前文说了在UE4中使用Python的方法,这篇文章就说一下在使用Python做UE4开发时常用的一些功能。
以下代码基于UE4.26,引擎自带的Python版本为3.7。
添加自定义菜单
这个功能可以在UE4的菜单栏上添加自定义的菜单,执行自定义的功能,方便用户使用。
import unreal menus = unreal.ToolMenus.get() main_menu = menus.find_menu("LevelEditor.MainMenu") # 获取unreal的菜单控件 added_menu = main_menu.add_sub_menu(main_menu.get_name(), "MyMenu", "我的菜单", "我的菜单") # 添加子菜单 entry = unreal.ToolMenuEntry( name='func1', type=unreal.MultiBlockType.MENU_ENTRY, insert_position=unreal.ToolMenuInsert('', unreal.ToolMenuInsertType.DEFAULT) ) # 按钮 entry.set_label('测试') entry.set_string_command(unreal.ToolMenuStringCommandType.PYTHON, "Name", 'print("测试一下")') # 设置按钮的功能 added_menu.add_menu_entry('MyMenu', entry) # 将按钮添加到子菜单 menus.refresh_all_widgets() # 刷新菜单ui
运行后生成的菜单如下
点击测试菜单命令后出现log如下
图形界面
在UE4中使用Python的PyQt库也可以制作图形界面,但因为UE4的图形界面是使用C++开发的,因此PyQt开发的页面是无法嵌入到UE4页面中的,这一点需要注意。
下面就来实现一个Qt窗口。
首先UE4自带的Python中没有PySide库,因此需要先给引擎自带的python(路径在Engine\Binaries\ThirdParty\Python3\Win64)安装PySide库。
pip install PySide2
另外同样由于UE4的图形界面是C++开发的,因此需要将Qt的窗口类与UE4的窗口进行关联,否则会导致UE4闪退或者卡死。
一个简单窗口的代码如下
import unreal from functools import partial from PySide2 import QtWidgets def __QtAppTick__(delta_seconds): QtWidgets.QApplication.sendPostedEvents() def bind_widget_to_unreal(widget): winid = widget.winId() unreal.parent_external_window_to_slate(winid) unreal_app = QtWidgets.QApplication.instance() if not unreal_app: unreal_app = QtWidgets.QApplication([]) tick_handle = unreal.register_slate_post_tick_callback(__QtAppTick__) __QtAppQuit__ = partial(unreal.unregister_slate_post_tick_callback, tick_handle) unreal_app.aboutToQuit.connect(__QtAppQuit__) w = QtWidgets.QWidget() bind_widget_to_unreal(w) w.show()
执行后效果如下
再结合QtDesigner制作的ui文件和通过Qt.py加载ui文件,就可以实现一个足够强大并且可以方便随时修改的UI窗口。
导入资产
对于图片、视频等资产的导入,实现是很简单的。
task = unreal.AssetImportTask() # 创建导入的任务 task.set_editor_property('automated', True) task.set_editor_property('destination_path', "/Game/test") task.set_editor_property('destination_name', "mypic") task.set_editor_property('filename', "D:/test.png") task.set_editor_property('replace_existing', True) # 替换已存在 task.set_editor_property('save', True) # 导入后保存 unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # 执行导入任务
运行后,图片就被导入成功了。
而对于fbx、abc、obj等模型文件的导入,就会比较复杂,在导入模型资产时会有如下这样的设置窗口。
因此在使用Python导入模型资产时,也需要对这部分设置进行配置。
options = unreal.FbxImportUI() #声明导入配置 options.set_editor_property('import_mesh', True) options.set_editor_property('import_textures', False) #不导入材质 options.set_editor_property('import_materials', False) #不导入贴图 # 对于静态的fbx设置静态数据,包括合并网格,转换单位和方向等 options.set_editor_property('import_as_skeletal', False) options.static_mesh_import_data.set_editor_property('combine_meshes', True) options.static_mesh_import_data.set_editor_property('auto_generate_collision', False) options.static_mesh_import_data.set_editor_property('generate_lightmap_u_vs', False) options.static_mesh_import_data.set_editor_property('convert_scene', True) options.static_mesh_import_data.set_editor_property('convert_scene_unit', True) options.static_mesh_import_data.set_editor_property('vertex_color_import_option', unreal.VertexColorImportOption.REPLACE) task = unreal.AssetImportTask() # 创建导入的任务 task.set_editor_property('automated', True) task.set_editor_property('destination_path', "/Game/test") task.set_editor_property('destination_name', "fbx") task.set_editor_property('filename', "D:/test.fbx") task.set_editor_property('replace_existing', True) # 替换已存在 task.set_editor_property('save', True) # 导入后保存 # 将设置放到导入任务中 task.set_editor_property('options', options) unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # 执行导入任务
导入后效果如下
而在导入特效或毛发等文件时,会用到abc格式,这时候需要设置abc的导入配置。
另外由于轴向的问题,默认导入的物体朝向是错误的,需要修复。
# 修复abc的轴向问题 abc_conversion_settings = unreal.AbcConversionSettings( preset=unreal.AbcConversionPreset.MAYA, flip_u=False, flip_v=True, scale=[1.0, -1.0, 1.0], rotation=[90.0, 0.0, 0.0]) options = unreal.AbcImportSettings() #abc导入配置 options.set_editor_property('import_type', unreal.AlembicImportType.STATIC_MESH) options.set_editor_property('conversion_settings', abc_conversion_settings) task = unreal.AssetImportTask() # 创建导入的任务 task.set_editor_property('automated', True) task.set_editor_property('destination_path', "/Game/test") task.set_editor_property('destination_name', "abc") task.set_editor_property('filename', "D:/test.abc") task.set_editor_property('replace_existing', True) # 替换已存在 task.set_editor_property('save', True) # 导入后保存 # 将设置放到导入任务中 task.set_editor_property('options', options) unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # 执行导入任务
效果如下
除了轴向以外,从Maya中导入模型时还需要注意世界比例导致的缩放问题。
其他功能
资产管理
# 创建文件夹 unreal.EditorAssetLibrary.make_directory('/Game/Test/NewDirectory') # 复制文件夹 unreal.EditorAssetLibrary.duplicate_directory('/Game/Test/OldDirectory', '/Game/Test/NewDirectory') # 删除文件夹 unreal.EditorAssetLibrary.delete_directory('/Game/Directory') # 重命名文件夹 unreal.EditorAssetLibrary.rename_directory('/Game/Directory', '/Game/NewDirectory') # 复制资产 unreal.EditorAssetLibrary.duplicate_asset('/Game/Test/Old', '/Game/Test/New') # 删除资产 unreal.EditorAssetLibrary.delete_asset('/Game/Test/File') # 判断资产是否存在 unreal.EditorAssetLibrary.does_asset_exist('/Game/Test/New') # 重命名资产 unreal.EditorAssetLibrary.rename_asset('/Game/Test/Old', '/Game/Test/New') #选择指定资产 paths = ['/Game/Test/abc','/Game/Textures/Sky/Cloud'] unreal.EditorAssetLibrary.sync_browser_to_objects(paths)
物体操作
# 从资产创建物体 asset = unreal.EditorAssetLibrary.load_asset("/Game/Test/Fbx") actor_location = unreal.Vector(0.0, 0.0, 0.0) actor_rotation = unreal.Rotator(0.0, 0.0, 0.0) unreal.EditorLevelLibrary.spawn_actor_from_object(asset, actor_location,actor_rotation) # 从蓝图实例化物体 actor_class = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BluePrint/MyActor') actor_location = unreal.Vector(0.0, 0.0, 0.0) actor_rotation = unreal.Rotator(0.0, 0.0, 0.0) unreal.EditorLevelLibrary.spawn_actor_from_class(actor_class, actor_location, actor_rotation) # 获取场景中的所有物体 actors = unreal.EditorLevelLibrary.get_all_level_actors() # 获取场景中的所有组件 components = unreal.EditorLevelLibrary.get_all_level_actors_components() # 获取场景中所选的物体 unreal.EditorLevelLibrary.get_selected_level_actors() #在场景中选择物体 unreal.EditorLevelLibrary.set_selected_level_actors(actors_to_select) # 获取GameWorld world = unreal.EditorLevelLibrary.get_editor_world() # 获取场景中某类的物体 unreal.GameplayStatics.get_all_actors_of_class(unreal.EditorLevelLibrary.get_editor_world(), bpname) # 获取场景中有某tag的物体 unreal.GameplayStatics.get_all_actors_of_class(unreal.EditorLevelLibrary.get_editor_world(), tagname)
本文参考自影视后期流程小白的Unreal Python系列文章和Vanny Yuan的UnrealPython基础学习,有修改。
人生不能后悔,只能遗憾,
因为遗憾只是在感叹错过,
后悔却是否定了自己曾经的选择。
《一切都是最好的安排》
——辉姑娘
评论
338051 787390Outstanding post, I conceive blog owners really should acquire a lot from this blog its very user pleasant. 455836
557036 772320Wonderful blog layout here. Was it hard creating a nice seeking web site like this? 823725