CARLA
 
载入中...
搜索中...
未找到
MapGenFunctionLibrary.cpp
浏览该文件的文档.
1// Copyright (c) 2023 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
9// 引擎头文件
10#include "AssetRegistry/AssetRegistryModule.h"
11#include "Materials/MaterialInstance.h"
12#include "StaticMeshAttributes.h"
13#include "RenderingThread.h"
14// Carla C++ 头文件
15
16// Carla 插件头文件
17// 定义一个日志类别,名为LogCarlaMapGenFunctionLibrary。
18// 这个类别在程序运行过程中可用于输出特定的日志信息,便于开发者调试代码以及追踪与Carla地图生成功能库相关的执行情况、错误等内容,方便定位问题所在。
19DEFINE_LOG_CATEGORY(LogCarlaMapGenFunctionLibrary);
20// 声明一个静态的常量,类型为单精度浮点数(float),用于表示从OpenStreetMap(OSM)单位到厘米单位的缩放因子。
21// 这里将其值设定为100.0f,意思是在涉及到OSM相关数据转换为厘米单位的操作时,每1个OSM单位对应100厘米,方便后续进行长度、距离等相关的换算。
22static const float OSMToCentimetersScaleFactor = 100.0f;
23
24// 这是一个类UMapGenFunctionLibrary的成员函数BuildMeshDescriptionFromData的定义。
25// 该函数的目的是根据传入的不同参数构建一个FMeshDescription类型的网格描述信息,这个网格描述会包含诸如顶点、三角形、材质等构建一个完整网格所需要的各种元素信息,下面是具体的函数参数和函数体逻辑。
26
28 const FProceduralCustomMesh& Data,
29 const TArray<FProcMeshTangent>& ParamTangents,
30 UMaterialInstance* MaterialInstance )
31{
32// 获取传入的自定义网格数据结构(Data)中顶点的数量,存储到名为VertexCount的整型变量中。
33 // 通过调用Num()函数获取数组元素个数的方式来得到顶点数量,后续可以基于这个数量进行循环遍历顶点等操作,比如依次设置每个顶点的坐标等信息。
34 int32 VertexCount = Data.Vertices.Num();
35 int32 VertexInstanceCount = Data.Triangles.Num();
36 int32 PolygonCount = Data.Vertices.Num()/3;
37
38 FMeshDescription MeshDescription;
39 FStaticMeshAttributes AttributeGetter(MeshDescription);
40 AttributeGetter.Register();
41
42// 获取多边形组名称的引用,这些名称与不同的材质插槽相关联
43TPolygonGroupAttributesRef<FName> PolygonGroupNames = AttributeGetter.GetPolygonGroupMaterialSlotNames();
44// 获取顶点位置的引用,包含了模型所有顶点的空间坐标
45TVertexAttributesRef<FVector> VertexPositions = AttributeGetter.GetVertexPositions();
46// 获取顶点实例切线的引用,用于确定顶点的切线方向,影响光照计算
47TVertexInstanceAttributesRef<FVector> Tangents = AttributeGetter.GetVertexInstanceTangents();
48// 获取顶点实例的双法线符号,用于确定顶点的双法线方向,影响法线贴图
49TVertexInstanceAttributesRef<float> BinormalSigns = AttributeGetter.GetVertexInstanceBinormalSigns();
50// 获取顶点实例法线的引用,用于确定顶点的法线方向,影响光照计算
51TVertexInstanceAttributesRef<FVector> Normals = AttributeGetter.GetVertexInstanceNormals();
52// 获取顶点实例颜色的引用,用于自定义顶点颜色,影响渲染效果
53TVertexInstanceAttributesRef<FVector4> Colors = AttributeGetter.GetVertexInstanceColors();
54// 获取顶点实例UV坐标的引用,用于将纹理映射到顶点
55TVertexInstanceAttributesRef<FVector2D> UVs = AttributeGetter.GetVertexInstanceUVs();
56
57// 计算每个ProcMesh元素类型的总计,并为MeshDescription预留空间
58FPolygonGroupID PolygonGroupForSection;
59MeshDescription.ReserveNewVertices(VertexCount); // 为新顶点预留空间
60MeshDescription.ReserveNewVertexInstances(VertexInstanceCount); // 为新顶点实例预留空间
61MeshDescription.ReserveNewPolygons(PolygonCount); // 为新多边形预留空间
62MeshDescription.ReserveNewEdges(PolygonCount * 2); // 为新边预留空间,每个多边形有两条边
63UVs.SetNumIndices(4); // 设置UV坐标的索引数量,通常用于四边形
64
65// 创建材质映射
66TMap<UMaterialInterface*, FPolygonGroupID> UniqueMaterials; // 存储唯一的材质和对应的多边形组ID
67const int32 NumSections = 1; // 材质段的数量,这里为1
68UniqueMaterials.Reserve(1); // 为材质映射预留空间
69FPolygonGroupID NewPolygonGroup = MeshDescription.CreatePolygonGroup(); // 创建新的多边形组
70
71// 根据MaterialInstance添加材质到UniqueMaterials映射中,并设置多边形组名称
72if( MaterialInstance != nullptr ){
73 UMaterialInterface *Material = MaterialInstance;
74 UniqueMaterials.Add(Material, NewPolygonGroup); // 将材质添加到映射中
75 PolygonGroupNames[NewPolygonGroup] = Material->GetFName(); // 设置多边形组名称为材质名称
76}else{
77 UE_LOG(LogCarla, Error, TEXT("MaterialInstance is nullptr")); // 如果MaterialInstance为空,记录错误日志
78}
79PolygonGroupForSection = NewPolygonGroup; // 将新创建的多边形组ID赋值给PolygonGroupForSection
80
81// 创建模型顶点
82int32 NumVertex = Data.Vertices.Num(); // 获取顶点数据的数量
83TMap<int32, FVertexID> VertexIndexToVertexID; // 存储顶点索引和顶点ID的映射
84VertexIndexToVertexID.Reserve(NumVertex); // 为顶点索引到顶点ID的映射预留空间
85for (int32 VertexIndex = 0; VertexIndex < NumVertex; ++VertexIndex) // 遍历所有顶点数据
86{
87 const FVector &Vert = Data.Vertices[VertexIndex]; // 获取顶点位置
88 const FVertexID VertexID = MeshDescription.CreateVertex(); // 在MeshDescription中创建新顶点
89 VertexPositions[VertexID] = Vert; // 设置顶点位置
90 VertexIndexToVertexID.Add(VertexIndex, VertexID); // 将顶点索引和顶点ID添加到映射中
91}
92
93// 创建VertexInstance,即模型中每个顶点的具体实例
94// "VertexInstance"是三维图形学和计算机图形学中的术语,它指的是模型中一个特定顶点的实例或具体实现
95int32 NumVertexInstances = Data.VertexInstances.Num(); // 获取顶点实例的数量
96TMap<FVertexID, FVertexInstanceID> VertexToInstanceID; // 存储顶点ID和顶点实例ID的映射
97VertexToInstanceID.Reserve(NumVertexInstances); // 为顶点到顶点实例的映射预留空间
98for (int32 VertexInstanceIndex = 0; VertexInstanceIndex < NumVertexInstances; ++VertexInstanceIndex) // 遍历所有顶点实例数据
99{
100
101}
102
103 int32 NumIndices = Data.Triangles.Num();
104 int32 NumTri = NumIndices / 3;
105 TMap<int32, FVertexInstanceID> IndiceIndexToVertexInstanceID;
106 IndiceIndexToVertexInstanceID.Reserve(NumVertex);
107 for (int32 IndiceIndex = 0; IndiceIndex < NumIndices; IndiceIndex++)
108 {
109 const int32 VertexIndex = Data.Triangles[IndiceIndex];
110 const FVertexID VertexID = VertexIndexToVertexID[VertexIndex];
111 const FVertexInstanceID VertexInstanceID =
112 MeshDescription.CreateVertexInstance(VertexID);
113 IndiceIndexToVertexInstanceID.Add(IndiceIndex, VertexInstanceID);
114 Normals[VertexInstanceID] = Data.Normals[VertexIndex];
115
116 // 检查传入的参数Tangents数量是否与顶点数量相等,如果相等则设置切线和双法线符号
117 if(ParamTangents.Num() == Data.Vertices.Num())
118 {
119 Tangents[VertexInstanceID] = ParamTangents[VertexIndex].TangentX;
120 BinormalSigns[VertexInstanceID] =
121 ParamTangents[VertexIndex].bFlipTangentY ? -1.f : 1.f;
122 }else{
123 // 如果不相等,这里没有代码,可能需要处理不匹配的情况
124 }
125 // 设置顶点颜色为黑色
126 Colors[VertexInstanceID] = FLinearColor(0,0,0);
127 // 检查UV0数量是否与顶点数量相等,如果相等则设置UV坐标
128 if(Data.UV0.Num() == Data.Vertices.Num())
129 {
130 // 如果不相等,则设置UV坐标为(0,0)
131 UVs.Set(VertexInstanceID, 0, Data.UV0[VertexIndex]);
132 }else{
133 UVs.Set(VertexInstanceID, 0, FVector2D(0,0));
134 }
135 // 将其他UV通道设置为(0,0)
136 UVs.Set(VertexInstanceID, 1, FVector2D(0,0));
137 UVs.Set(VertexInstanceID, 2, FVector2D(0,0));
138 UVs.Set(VertexInstanceID, 3, FVector2D(0,0));
139 }
140
141 // 遍历三角形,将每个多边形添加到网格描述中
142 for (int32 TriIdx = 0; TriIdx < NumTri; TriIdx++)
143 {
144 FVertexID VertexIndexes[3];
145 TArray<FVertexInstanceID> VertexInstanceIDs;
146 VertexInstanceIDs.SetNum(3);
147
148 // 获取三角形的每个角的顶点索引和实例ID
149 for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex)
150 {
151 const int32 IndiceIndex = (TriIdx * 3) + CornerIndex;
152 const int32 VertexIndex = Data.Triangles[IndiceIndex];
153 VertexIndexes[CornerIndex] = VertexIndexToVertexID[VertexIndex];
154 VertexInstanceIDs[CornerIndex] =
155 IndiceIndexToVertexInstanceID[IndiceIndex];
156 }
157
158 // 将一个多边形插入到网格中
159 MeshDescription.CreatePolygon(NewPolygonGroup, VertexInstanceIDs);
160
161 }
162
163 return MeshDescription;
164}
165
166// UMapGenFunctionLibrary类的静态方法,用于根据给定的数据创建网格
168 const FProceduralCustomMesh& Data,
169 const TArray<FProcMeshTangent>& ParamTangents,
170 UMaterialInstance* MaterialInstance,
171 FString MapName,
172 FString FolderName,
173 FName MeshName)
174{
175 IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
176
177 UStaticMesh::FBuildMeshDescriptionsParams Params;
178 Params.bBuildSimpleCollision = true;
179
180 // 构建包的路径
181 FString PackageName = "/Game/CustomMaps/" + MapName + "/Static/" + FolderName + "/" + MeshName.ToString();
182
183 // 检查包路径是否存在,如果不存在则创建目录
184 if (!PlatformFile.DirectoryExists(*PackageName))
185 {
186 //PlatformFile.CreateDirectory(*PackageName);
187 }
188
189
190 // 从给定的数据和切线信息构建网格描述
191 FMeshDescription Description = BuildMeshDescriptionFromData(Data,ParamTangents, MaterialInstance);
192
193 // 检查构建的网格描述中是否有多边形
194 if (Description.Polygons().Num() > 0)
195 {
196 // 创建一个新的包(Package),用于存储静态网格
197 UPackage* Package = CreatePackage(*PackageName);
198 // 检查包是否创建成功
199 check(Package);
200 // 在新建的包中创建一个新的静态网格对象
201 UStaticMesh* Mesh = NewObject<UStaticMesh>( Package, MeshName, RF_Public | RF_Standalone);
202
203 // 初始化网格资源
204 Mesh->InitResources();
205 // 为网格设置一个新的光照Guid
206 Mesh->LightingGuid = FGuid::NewGuid();
207 // 将材质实例添加到网格的静态材质列表中
208 Mesh->StaticMaterials.Add(FStaticMaterial(MaterialInstance));
209 // 从网格描述构建网格
210 Mesh->BuildFromMeshDescriptions({ &Description }, Params);
211 // 为网格创建刚体设置
212 Mesh->CreateBodySetup();
213 // 设置网格的碰撞追踪标志,使用复杂网格作为简单网格
214 Mesh->BodySetup->CollisionTraceFlag = ECollisionTraceFlag::CTF_UseComplexAsSimple;
215 // 为网格的刚体设置创建物理网格
216 Mesh->BodySetup->CreatePhysicsMeshes();
217 // Build mesh from source
218 Mesh->NeverStream = false;
219 TArray<UObject*> CreatedAssets;
220 CreatedAssets.Add(Mesh);
221
222 // Notify asset registry of new asset
223 FAssetRegistryModule::AssetCreated(Mesh);
224 //UPackage::SavePackage(Package, Mesh, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, *(MeshName.ToString()), GError, nullptr, true, true, SAVE_NoError);
225 Package->MarkPackageDirty();
226 return Mesh;
227 }
228 return nullptr;
229}
230
231FVector2D UMapGenFunctionLibrary::GetTransversemercProjection(float lat, float lon, float lat0, float lon0)
232{
233 // earth radius in m
234 const float R = 6373000.0f;
235 // 将输入的纬度和经度从度数转换为弧度,并调整经度以相对于中央经线 (lon0)
236 float latt = FMath::DegreesToRadians(lat);
237 float lonn = FMath::DegreesToRadians(lon - lon0);
238 float latt0 = FMath::DegreesToRadians(lat0);
239 // 计算中间变量 eps 和 nab,用于后续计算 x 和 y 坐标
240 float eps = atan(tan(latt)/cos(lonn));
241 float nab = asinh(sin(lonn)/sqrt(tan(latt)*tan(latt)+cos(lonn)*cos(lonn)));
242 // 根据地球半径和拉伸量计算投影后的 x 和 y 坐标
243 float x = R*nab;
244 float y = R*eps;
245 // 计算参考点 (lat0, lon0) 的投影坐标
246 float eps0 = atan(tan(latt0)/cos(0));
247 float nab0 = asinh(sin(0)/sqrt(tan(latt0)*tan(latt0)+cos(0)*cos(0)));
248 float x0 = R*nab0;
249 float y0 = R*eps0;
250 // 计算最终的投影坐标,并应用缩放因子 OSMToCentimetersScaleFactor 将单位转换为厘米
251 FVector2D Result = FVector2D(x, -(y - y0)) * OSMToCentimetersScaleFactor;
252 // 返回计算得到的投影坐标
253 return Result;
254}
255
256// UMapGenFunctionLibrary类的方法,用于使当前线程休眠指定的秒数
258 //FGenericPlatformProcess::Sleep(seconds);
259}
260
261// UMapGenFunctionLibrary类的方法,用于在蓝图中刷新渲染命令
263 // 刷新渲染命令,确保所有图形操作都已完成
264 FlushRenderingCommands(true);
265 // 在游戏线程中刷新待删除的RHI资源
266 FlushPendingDeleteRHIResources_GameThread();
267}
268
269// UMapGenFunctionLibrary类的方法,用于清理GEngine
271 // 执行垃圾回收并清理Actor
272 GEngine->PerformGarbageCollectionAndCleanupActors();
273// 如果编译器配置为使用编辑器
274#if WITH_EDITOR
275 // 创建一个文本对象,用于重置操作的描述
276 FText TransResetText(FText::FromString("Clean up after Move actors to sublevels"));
277 // 如果GEditor的Trans对象存在
278 if ( GEditor->Trans )
279 {
280 // 重置事务
281 GEditor->Trans->Reset(TransResetText);
282 // 清理编辑器,包括移动Actor到子级别
283 GEditor->Cleanse(true, true, TransResetText);
284 }
285#endif
286}
UE_LOG(LogCarla, Log, TEXT("UActorDispatcher::Destroying actor: '%s' %x"), *Id, Actor)
static const float OSMToCentimetersScaleFactor
DEFINE_LOG_CATEGORY(LogCarlaMapGenFunctionLibrary)
static void FlushRenderingCommandsInBlueprint()
static UStaticMesh * CreateMesh(const FProceduralCustomMesh &Data, const TArray< FProcMeshTangent > &ParamTangents, UMaterialInstance *MaterialInstance, FString MapName, FString FolderName, FName MeshName)
static void SetThreadToSleep(float seconds)
static FMeshDescription BuildMeshDescriptionFromData(const FProceduralCustomMesh &Data, const TArray< FProcMeshTangent > &ParamTangents, UMaterialInstance *MaterialInstance)
static FVector2D GetTransversemercProjection(float lat, float lon, float lat0, float lon0)
A definition of a Carla Mesh.
TArray< FVector2D > UV0