官网PythonAPI教程

教程链接https://dev.epicgames.com/community/learning/courses/wk4/an-in-depth-look-at-using-python-for-game-development/vymW/an-in-depth-look-at-using-python-for-game-development-introduction

获得路径下的所有文件路径

def listAssetPaths(path=‘/Game’):
assetPaths = unreal.EditorAssetLibrary.list_assets(path)
for assetPath in assetPaths: print(assetPath)

EditorUtilityLibrary和EditorActorSubsystem

EditorUtilityLibrary可以让我们获取和内容浏览器有关的功能
EditorActorSubsystem可以可以提供和世界大纲视图有关的功能(这个类在UE5里面有,UE4.27里面没有)
EditorLevelLibrary 和 EditorActorSubsystem具有差不多的功能,UE4.27可以用这个来尝试代替EditorActorSubsystem

EditorUtilityLibrary

方法:get_selected_assets (获取选择的资产)
举例:
# 输出选择的资产的对象信息
def getSelectionContentBrowser():
selectAssets = unreal.EditorUtilityLibrary.get_selected_assets()
for selectAsset in selectAssets: print(selectAsset)

EditorActorSubsystem(这个类在UE5里面有,UE4.27里面没有)

方法:
get_all_level_actors(获取关卡中的所有ACtor) image.pngimage.png EAS是变量名无需深究

get_selected_level_actors(获取选择的关卡actor)

EditorLevelLibrary(4.27可以使用的和EditorActorSubSystem差不多功能的类)(UE5虽然也能使用但是将要废弃这个类)

方法:get_all_level_actors(获取关卡中的所有ACtor) 同样是获取关卡中的所有ACtor经过测试4.27版本的UE使用这个类是不需要参数传递的,EditorActorSubsystem的这个方法需要传递参数。

按类组织资产

EditorAssetLibrary

方法:find_asset_data(asset_path)→AssetData 接受资产路径返回资产的数据,类型为AssetData。什么是AssetData类型:AssetData类型存取了资产的各种信息,可以直接print AssetData类型的变量可以发现它是一个字典。这个类型也自带一些方法,比如获取资产的名字,长名,资产的类型,判断是否加载等。https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/AssetData.html#unreal.AssetData

1
2
3
4
5
6
7
8
9
10
11
# 根据类型列举物体
def getAssetClass(classType):
assetPaths = unreal.EditorAssetLibrary.list_assets('/Game/MyAsset')
print(assetPaths)
assets = []
for assetPath in assetPaths:
assetData = unreal.EditorAssetLibrary.find_asset_data(assetPath)
assetClass = assetData.asset_class
if assetClass == classType:
assets.append(assetData.get_export_text_name())
for asset in assets: print(asset)

获取特定类的信息

首先看到这一节可以明确的感知到,UEPython中有很多自定义的类型,然后这些类型都有属于自己的函数,因此帮助文档很重要。
staticMesh,image.png编辑器属性就是这种类型的可调节的属性,我们可以通过staticMesh类型的对象中的get_editor_property方法来获取这些属性
它们都继承自_ObjectBaseimage.png所以对象也可以使用这些方法,例如get_name

StaticMesh的AssetImportData与lod_group属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 根据类型列举物体
def getAssetClass(classType):
assetPaths = unreal.EditorAssetLibrary.list_assets('/Game')
# print(assetPaths)
assets = []
for assetPath in assetPaths:
assetData = unreal.EditorAssetLibrary.find_asset_data(assetPath)
assetClass = assetData.asset_class
if assetClass == classType:
assets.append(assetData.get_asset())
# for asset in assets: print(asset)
return assets


# 获取静态网格体的信息
def getStaticMeshData():
staticMeshs = getAssetClass('StaticMesh') # 获取所有类型为StaticMesh的对象
for staticMesh in staticMeshs:
# assetImportData = staticMesh.get_editor_property('asset_import_data') # 获取静态网格体对象的编辑器中的导入信息的属性
# fbxFilePath = assetImportData.extract_filenames() # 得到导入信息属性中的fbx路径
# print(fbxFilePath)
# print(staticMesh.get_editor_property('lod_group'))
# print(staticMesh.get_num_lods())
# 如果静态网个体对象的lod组的属性为None并且lod数量只有一个时将lod组的属性改为LargeProp
if staticMesh.get_editor_property('lod_group') == 'None':
if staticMesh.get_num_lods() == 1:
staticMesh.set_editor_property('lod_group', 'LargeProp')

获取staticMesh的lod数据

先提一下名词解释,这里使用的方法除了利用了lod的索引外还利用了分段的索引,通过观看教程理解分段的意义:首先我们的目的是获取这里模型的三角形的数量image.png,当切换一个LOD时分段数量跟材质球的数量是相同的,也就是说分段的意思是当前LOD对应的模型的组成数量。image.png
涉及到的类与方法:
ProceduralMeshLibrary:get_section_from_static_meshimage.pnghttps://docs.unrealengine.com/4.27/en-US/PythonAPI/class/ProceduralMeshLibrary.html?highlight=proceduralmeshlibrary#unreal.ProceduralMeshLibrary
得到的数据经过输出可以看出来得到的是一个元组,元组里面有多个数组元素组成,有意向可以遍历这些数组来观察数组中的内容。因为我们需要得到三角形的数量遍历三角形的数据后发现官方输出了很多重复的数据,当我们把数组的长度除以3以后才能够得到我们需要的正确的三角形的数量。
“很多数值是重复的 我想这是因为输出了 和每个三角形有关的所有顶点 之所以这么认为是因为 如果让这个数字 这个长度 我们可以生成它 然后除以3 得到的结果 就是我们想要的数据 这是个窍门 只是个小窍门 只要让这个数组的长度除以3”这是官方教程的原话

image.png
StaticMesh: get_num_sections(lod)得到模型的lod对应的分段数https://docs.unrealengine.com/4.27/en-US/PythonAPI/class/StaticMesh.html?highlight=staticmesh#unreal.StaticMesh.get_num_sections

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 根据类型列举物体
def getAssetClass(classType):
assetPaths = unreal.EditorAssetLibrary.list_assets('/Game')
# print(assetPaths)
assets = []
for assetPath in assetPaths:
assetData = unreal.EditorAssetLibrary.find_asset_data(assetPath)
assetClass = assetData.asset_class
if assetClass == classType:
assets.append(assetData.get_asset())
# for asset in assets: print(asset)
return assets

# 获取静态网格体的lod信息
def getStaticMeshLODData():
staticMeshs = getAssetClass('StaticMesh')
for staticMesh in staticMeshs:
staticMeshTriCount = [] # 负责记录模型的三角形数量
numLODs = staticMesh.get_num_lods()
for i in range(numLODs):
LODTriCount = 0 # 记录当前LOD的三角形数量
numSections = staticMesh.get_num_sections(i)
for j in range(numSections): # 遍历LOD对应的分段得到LOD对应的三角形数量
# 得到静态网格体对应的分段信息
sectionData = unreal.ProceduralMeshLibrary.get_section_from_static_mesh(staticMesh, i, j)
sectionTriCount = (len(sectionData[1]) / 3) # 把数组的长度除以3以后才能够得到我们需要的正确的三角形的数量。
LODTriCount += sectionTriCount
staticMeshTriCount.append(LODTriCount) # 记录LOD对应的三角形数量
staticMeshReductions = [100] # 负责记录模型的LOD对应的三角形百分比
for i in range(1, numLODs):
staticMeshReductions.append(int(staticMeshTriCount[i]/staticMeshTriCount[0]*100))
print(staticMesh.get_name())
print(staticMeshTriCount)
print(staticMeshReductions)

获取关卡中的模型以及出现的数量

因为是要获取实例化的数量也即获取关卡中存在的Actor,因此要使用EditorLevelLibrary中的方法
在这里获得到了个小知识点,image.png当我们将内容浏览器中的资产拖入到关卡中,ue会自动将其变成staticMeshActor类型,因此找到关卡中出现的Actor以后还需要找到这个Acotr对应的组件,然后再根据组件找到对应的静态网格体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 获取关卡中的模型以及出现的次数
def getStaticMeshInstanceCounts():
levelActors = unreal.EditorLevelLibrary().get_all_level_actors() # 获取关卡中的所有Actor

staticMeshActors = [] # 负责记录所有staticMeshActor的名字
staticMeshActorCounts = [] # 负责记录所有Actor在关卡中出现的数量

for levelActor in levelActors:
if (levelActor.get_class().get_name()) == 'StaticMeshActor':
staticMeshComponent = levelActor.static_mesh_component # 得到这个Actor的组件
staticMesh = staticMeshComponent.static_mesh # 得到这个组件对应的静态网格体
staticMeshActors.append(staticMesh.get_name())

processedActors = [] # 用来记录场景中的所有staticMeshActor但是不会出现相同的名字
for staticMeshActor in staticMeshActors:
if staticMeshActor not in processedActors:
actorCounts = (staticMeshActor, staticMeshActors.count(staticMeshActor)) # 元组,负责记录actor以及对应的关卡出现数量
staticMeshActorCounts.append(actorCounts)
processedActors.append(staticMeshActor)
# key=lambda a: a[1] 的意思是按照列表中的元素中的第二项进行排列,在这里是按照actor出现的次数进行排序
staticMeshActorCounts.sort(key=lambda a: a[1], reverse=True)
for item in staticMeshActorCounts: print(item)

LOD视图的开启与介绍

image.png
白色代表LOD0,红色代表LOD1,依次往后是绿色蓝色

获取关卡中的模型名字以及对应的在场景中的LOD1的三角形数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 获取静态网格体的lod信息
def getStaticMeshLODData():
staticMeshs = getAssetClass('StaticMesh')
staticMeshLODData = []
for staticMesh in staticMeshs:
staticMeshTriCount = [] # 负责记录模型的三角形数量
numLODs = staticMesh.get_num_lods()
for i in range(numLODs):
LODTriCount = 0 # 记录当前LOD的三角形数量
numSections = staticMesh.get_num_sections(i)
for j in range(numSections): # 遍历LOD对应的分段得到LOD对应的三角形数量
# 得到静态网格体对应的分段信息
sectionData = unreal.ProceduralMeshLibrary.get_section_from_static_mesh(staticMesh, i, j)
sectionTriCount = (len(sectionData[1]) / 3) # 把数组的长度除以3以后才能够得到我们需要的正确的三角形的数量。
LODTriCount += sectionTriCount
staticMeshTriCount.append(LODTriCount) # 记录LOD对应的三角形数量
staticMeshReductions = [100] # 负责记录模型的LOD对应的三角形百分比
for i in range(1, numLODs):
staticMeshReductions.append(int(staticMeshTriCount[i] / staticMeshTriCount[0] * 100))
# print(staticMesh.get_name())
# print(staticMeshTriCount)
# print(staticMeshReductions)

try:
LODData = (staticMesh.get_name(), staticMeshTriCount[1]) # 之所以try是因为有的模型只有LOD0,把只有LOD0的过滤掉
except:
pass
staticMeshLODData.append(LODData)
return staticMeshLODData



# 获取关卡中的模型以及出现的次数
def getStaticMeshInstanceCounts():
levelActors = unreal.EditorLevelLibrary().get_all_level_actors() # 获取关卡中的所有Actor

staticMeshActors = [] # 负责记录所有staticMeshActor的名字
staticMeshActorCounts = [] # 负责记录所有Actor在关卡中出现的数量

for levelActor in levelActors:
if (levelActor.get_class().get_name()) == 'StaticMeshActor':
staticMeshComponent = levelActor.static_mesh_component # 得到这个Actor的组件
staticMesh = staticMeshComponent.static_mesh # 得到这个组件对应的静态网格体
staticMeshActors.append(staticMesh.get_name())

processedActors = [] # 用来记录场景中的所有staticMeshActor但是不会出现相同的名字
for staticMeshActor in staticMeshActors:
if staticMeshActor not in processedActors:
actorCounts = (staticMeshActor, staticMeshActors.count(staticMeshActor)) # 元组,负责记录actor以及对应的关卡出现数量
staticMeshActorCounts.append(actorCounts)
processedActors.append(staticMeshActor)
# key=lambda a: a[1] 的意思是按照列表中的元素中的第二项进行排列,在这里是按照actor出现的次数进行排序
staticMeshActorCounts.sort(key=lambda a: a[1], reverse=True)
# for item in staticMeshActorCounts: print(item)

LODData = getStaticMeshLODData()

# for item in LODData: print(item)

aggregateTriCounts = []

for i in range(len(staticMeshActorCounts)):
for j in range(len(LODData)):
if staticMeshActorCounts[i][0] == LODData[j][0]:
aggregateTriCount = (staticMeshActorCounts[i][0],staticMeshActorCounts[i][1] * LODData[j][1])
aggregateTriCounts.append(aggregateTriCount)

aggregateTriCounts.sort(key=lambda a: a[1], reverse=True) # 存取场景中的actor的mesh名字以及对应的场景中的所有mesh的LOD1的三角形数量
for item in aggregateTriCounts: print(item)

dir()与help(),材质实例

当知道一个类的名字以后,如果想要得到这个类对应的所有方法,可以通过dir()函数来得到,并且有的方法官方文档可能没有。
例如如果想知道StaticMeshComponent的方法可以通过:
for item in dir(unreal.StaticMeshComponent): print (item)
得到类对应的所有方法,并且可以通过搜索得到对应的方法,知道方法的名字后可以使用help()函数来得到方法的细节:help(unreal.StaticMeshComponent.get_num_materials)
image.pngimage.pngimage.png
将场景中的所有模型的材质更改为/Game/python/MI_test这个材质实例
image.png

1
2
3
4
5
6
7
8
9
10
11
def returnMaterialInformationSMC():

levelActors = unreal.EditorLevelLibrary().get_all_level_actors()
testMat = unreal.EditorAssetLibrary.find_asset_data('/Game/python/MI_test').get_asset()

for levelActor in levelActors:
if (levelActor.get_class().get_name()) == 'StaticMeshActor':
staticMeshComponent = levelActor.static_mesh_component

for i in range(staticMeshComponent.get_num_materials()):
staticMeshComponent.set_material(i, testMat)

使用关卡蓝图更改模型材质

根据场景中的staticmesh的material数量决定使用不同的材质实例,只在运行游戏时启用。
Northwood-EventGraph.png
image.png