CARLA
 
载入中...
搜索中...
未找到
Mesh.cpp
浏览该文件的文档.
1// Copyright (c) 2020 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
7#include <carla/geom/Mesh.h>
8
9#include <string>
10#include <sstream>
11#include <ios>
12#include <iostream>
13#include <fstream>
14
15#include <carla/geom/Math.h>
16
17namespace carla {
18namespace geom {
19
20 bool Mesh::IsValid() const {
21 // 至少应为某个顶点
22 if (_vertices.empty()) {
23 std::cout << "Mesh validation error: there are no vertices in the mesh." << std::endl;
24 return false;
25 }
26
27 // 如果有 indices,数量必须是3的倍数
28 if (!_indexes.empty() && _indexes.size() % 3 != 0) {
29 std::cout << "Mesh validation error: the index amount must be multiple of 3." << std::endl;
30 return false;
31 }
32
33 if (!_materials.empty() && _materials.back().index_end == 0) {
34 std::cout << "Mesh validation error: last material was not closed." << std::endl;
35 return false;
36 }
37
38 return true;
39 }
40
41 // 添加 三角形条带(triangle strip)
42 // 三角形条带是一条,每增加一个点增加一个三角形
43 // 参考:https://blog.csdn.net/tomorrow_opal/article/details/70140965
44 // e.g:
45 // 1 3 5 7
46 // #---#---#---#
47 // | / | / | / |
48 // #---#---#---#
49 // 2 4 6 8
50 // Mesh类中的AddTriangleStrip函数,作用是向Mesh对象添加三角形条带(Triangle Strip)数据
51// 参数vertices是一个包含Mesh顶点类型(Mesh::vertex_type)的向量引用,代表了构成三角形条带的顶点集合
52void Mesh::AddTriangleStrip(const std::vector<Mesh::vertex_type> &vertices) {
53 // 如果传入的顶点向量大小为0,说明没有顶点数据可用于构建三角形条带,直接返回,不做后续操作
54 if (vertices.size() == 0) {
55 return;
56 }
57 // 使用DEBUG_ASSERT进行调试断言,确保传入的顶点数量至少为3个
58 // 因为三角形条带至少需要3个顶点才能构成最基本的图形结构,否则不符合逻辑
59 DEBUG_ASSERT(vertices.size() >= 3);
60
61 // 获取当前Mesh对象已有的顶点数量,然后在此基础上加2,用于后续构建三角形条带索引时的起始位置计算
62 // 这个起始位置的计算方式是基于Mesh对象内部存储顶点和索引的机制来确定的
63 size_t i = GetVerticesNum() + 2;
64
65 // 调用AddVertices函数(应该是Mesh类内部的另一个函数)将传入的顶点数据添加到Mesh对象中
66 // 这样Mesh对象就包含了构建三角形条带所需的顶点信息
67 AddVertices(vertices);
68
69 // 初始化一个布尔变量,表示索引的添加顺序是否为顺时针方向,初始化为true,即先按顺时针方向添加索引
70 bool index_clockwise = true;
71
72 // 开始循环构建三角形条带的索引,只要当前索引位置(i)小于Mesh对象的总顶点数量,就继续循环
73 while (i < GetVerticesNum()) {
74 // 每次循环切换索引的添加顺序,即本次循环如果是顺时针,下次就是逆时针,反之亦然
75 // 这样交替的顺序可以正确地构建出连续的三角形条带
76 index_clockwise =!index_clockwise;
77 if (index_clockwise) {
78 // 如果当前是顺时针方向,按照顺时针顺序添加索引
79 // 先添加当前顶点的下一个顶点索引(i + 1)
80 AddIndex(i + 1);
81 // 再添加当前顶点索引(i)
82 AddIndex(i);
83 // 最后添加当前顶点的上一个顶点索引(i - 1)
84 AddIndex(i - 1);
85 } else {
86 // 如果当前是逆时针方向,按照逆时针顺序添加索引
87 // 先添加当前顶点的上一个顶点索引(i - 1)
88 AddIndex(i - 1);
89 // 再添加当前顶点索引(i)
90 AddIndex(i);
91 // 最后添加当前顶点的下一个顶点索引(i + 1)
92 AddIndex(i + 1);
93 }
94 // 将索引位置向后移动一位,准备构建下一组三角形的索引
95 ++i;
96 }
97}
98
99 // 添加 三角形扇(triangle fan)
100 // 三角形扇是第一个点是中心,其他的点都围绕着它,第2个点和最后一个点是一样的就可以围成一个圈了
101 // 例如:
102 // 2 1 6
103 // #---#---#
104 // | / | \ |
105 // #---#---#
106 // 3 4 5
107 void Mesh::AddTriangleFan(const std::vector<Mesh::vertex_type> &vertices) {
108 DEBUG_ASSERT(vertices.size() >= 3);
109 const size_t initial_index = GetVerticesNum() + 1;
110 size_t i = GetVerticesNum() + 2;
111 AddVertices(vertices);
112 while (i < GetVerticesNum()) {
113 AddIndex(initial_index);
114 AddIndex(i);
115 AddIndex(i + 1);
116 ++i;
117 }
118 }
119
121 _vertices.push_back(vertex);
122 }
123
124 void Mesh::AddVertices(const std::vector<Mesh::vertex_type> &vertices) {
125 std::copy(vertices.begin(), vertices.end(), std::back_inserter(_vertices));
126 }
127
129 _normals.push_back(normal);
130 }
131
133 _indexes.push_back(index);
134 }
135
137 _uvs.push_back(uv);
138 }
139
140 void Mesh::AddUVs(const std::vector<uv_type> & uv) {
141 std::copy(uv.begin(), uv.end(), std::back_inserter(_uvs));
142 }
143
144 void Mesh::AddMaterial(const std::string &material_name) {
145 const size_t open_index = _indexes.size();
146 if (!_materials.empty()) {
147 if (_materials.back().index_end == 0) {
148 // @todo: 将此注释更改为调试警告
149 // std::cout << "last material was not closed, closing it..." << std::endl;
150 EndMaterial();
151 }
152 }
153 if (open_index % 3 != 0) {
154 std::cout << "open_index % 3 != 0" << std::endl;
155 return;
156 }
157 _materials.emplace_back(material_name, open_index, 0);
158 }
159
161 const size_t close_index = _indexes.size();
162 if (_materials.empty() ||
163 _materials.back().index_start == close_index ||
164 _materials.back().index_end != 0) {
165 // @todo: 将此注释更改为调试警告
166 // std::cout << "WARNING: Bad end of material. Material not started." << std::endl;
167 return;
168 }
169 if (_indexes.empty() || close_index % 3 != 0) {
170 // @todo: 将此注释更改为调试警告
171 // std::cout << "WARNING: Bad end of material. Face not started/ended." << std::endl;
172 return;
173 }
174 _materials.back().index_end = close_index;
175 }
176
177 std::string Mesh::GenerateOBJ() const {
178 if (!IsValid()) {
179 return "";
180 }
181 std::stringstream out;
182 out << std::fixed; // 避免使用科学计数法
183
184 out << "# List of geometric vertices, with (x, y, z) coordinates." << std::endl;
185 for (auto &v : _vertices) {
186 out << "v " << v.x << " " << v.y << " " << v.z << std::endl;
187 }
188
189 if (!_uvs.empty()) {
190 out << std::endl << "# List of texture coordinates, in (u, v) coordinates, these will vary between 0 and 1." << std::endl;
191 for (auto &vt : _uvs) {
192 out << "vt " << vt.x << " " << vt.y << std::endl;
193 }
194 }
195
196 if (!_normals.empty()) {
197 out << std::endl << "# List of vertex normals in (x, y, z) form; normals might not be unit vectors." << std::endl;
198 for (auto &vn : _normals) {
199 out << "vn " << vn.x << " " << vn.y << " " << vn.z << std::endl;
200 }
201 }
202
203 if (!_indexes.empty()) {
204 out << std::endl << "# Polygonal face element." << std::endl;
205 auto it_m = _materials.begin();
206 auto it = _indexes.begin();
207 size_t index_counter = 0u;
208 while (it != _indexes.end()) {
209 // While exist materials
210 if (it_m != _materials.end()) {
211 // 如果当前材料在此索引处结束
212 if (it_m->index_end == index_counter) {
213 ++it_m;
214 }
215 // 如果当前材料从该索引开始
216 if (it_m->index_start == index_counter) {
217 out << "\nusemtl " << it_m->name << std::endl;
218 }
219 }
220
221 // 使用 3 个连续的索引添加实际表面
222 out << "f " << *it; ++it;
223 out << " " << *it; ++it;
224 out << " " << *it << std::endl; ++it;
225
226 index_counter += 3;
227 }
228 }
229
230 return out.str();
231 }
232
233 std::string Mesh::GenerateOBJForRecast() const {
234 if (!IsValid()) {
235 return "";
236 }
237 std::stringstream out;
238 out << std::fixed; // 避免使用科学计数法
239
240 out << "# List of geometric vertices, with (x, y, z) coordinates." << std::endl;
241 for (auto &v : _vertices) {
242 // 为 Recast 库切换“y”和“z”
243 out << "v " << v.x << " " << v.z << " " << v.y << std::endl;
244 }
245
246 if (!_indexes.empty()) {
247 out << std::endl << "# Polygonal face element." << std::endl;
248 auto it_m = _materials.begin();
249 auto it = _indexes.begin();
250 size_t index_counter = 0u;
251 while (it != _indexes.end()) {
252 // While exist materials
253 if (it_m != _materials.end()) {
254 // 如果当前材料在此索引处结束
255 if (it_m->index_end == index_counter) {
256 ++it_m;
257 }
258 // 如果当前材料从该索引开始
259 if (it_m->index_start == index_counter) {
260 out << "\nusemtl " << it_m->name << std::endl;
261 }
262 }
263 // 使用 3 个连续的索引添加实际面由于空间已经改变,因此将面构建方向更改为顺时针。
264 out << "f " << *it; ++it;
265 const auto i_2 = *it; ++it;
266 const auto i_3 = *it; ++it;
267 out << " " << i_3 << " " << i_2 << std::endl;
268 index_counter += 3;
269 }
270 }
271
272 return out.str();
273 }
274
275 std::string Mesh::GeneratePLY() const {
276 if (!IsValid()) {
277 return "Invalid Mesh";
278 }
279 // 生成头
280 std::stringstream out;
281 return out.str();
282 }
283
284 const std::vector<Mesh::vertex_type> &Mesh::GetVertices() const {
285 return _vertices;
286 }
287
288 std::vector<Mesh::vertex_type> &Mesh::GetVertices() {
289 return _vertices;
290 }
291
292 size_t Mesh::GetVerticesNum() const {
293 return _vertices.size();
294 }
295
296 const std::vector<Mesh::normal_type> &Mesh::GetNormals() const {
297 return _normals;
298 }
299
300 const std::vector<Mesh::index_type> &Mesh::GetIndexes() const {
301 return _indexes;
302 }
303
304 std::vector<Mesh::index_type>& Mesh::GetIndexes() {
305 return _indexes;
306 }
307 size_t Mesh::GetIndexesNum() const {
308 return _indexes.size();
309 }
310
311 const std::vector<Mesh::uv_type> &Mesh::GetUVs() const {
312 return _uvs;
313 }
314
315 const std::vector<Mesh::material_type> &Mesh::GetMaterials() const {
316 return _materials;
317 }
318
320 return _vertices.size();
321 }
322
323 Mesh& Mesh::ConcatMesh(const Mesh& rhs, int num_vertices_to_link) {
324
325 if (!rhs.IsValid()){
326 return *this += rhs;
327 }
328 const size_t v_num = GetVerticesNum();
329 const size_t i_num = GetIndexesNum();
330
331 _vertices.insert(
332 _vertices.end(),
333 rhs.GetVertices().begin(),
334 rhs.GetVertices().end());
335
336 _normals.insert(
337 _normals.end(),
338 rhs.GetNormals().begin(),
339 rhs.GetNormals().end());
340
341 const size_t vertex_to_start_concating = v_num - num_vertices_to_link;
342 for( size_t i = 1; i < num_vertices_to_link; ++i ) {
343 _indexes.push_back( vertex_to_start_concating + i );
344 _indexes.push_back( vertex_to_start_concating + i + 1 );
345 _indexes.push_back( v_num + i );
346
347 _indexes.push_back( vertex_to_start_concating + i + 1);
348 _indexes.push_back( v_num + i + 1);
349 _indexes.push_back( v_num + i);
350 }
351
352 std::transform(
353 rhs.GetIndexes().begin(),
354 rhs.GetIndexes().end(),
355 std::back_inserter(_indexes),
356 [=](size_t index) {return index + v_num; });
357
358 _uvs.insert(
359 _uvs.end(),
360 rhs.GetUVs().begin(),
361 rhs.GetUVs().end());
362
363 std::transform(
364 rhs.GetMaterials().begin(),
365 rhs.GetMaterials().end(),
366 std::back_inserter(_materials),
367 [=](MeshMaterial mat) {
368 mat.index_start += i_num;
369 mat.index_end += i_num;
370 return mat;
371 });
372
373 return *this;
374 }
375
377 const size_t v_num = GetVerticesNum();
378 const size_t i_num = GetIndexesNum();
379
380 _vertices.insert(
381 _vertices.end(),
382 rhs.GetVertices().begin(),
383 rhs.GetVertices().end());
384
385 _normals.insert(
386 _normals.end(),
387 rhs.GetNormals().begin(),
388 rhs.GetNormals().end());
389
390 std::transform(
391 rhs.GetIndexes().begin(),
392 rhs.GetIndexes().end(),
393 std::back_inserter(_indexes),
394 [=](size_t index) {return index + v_num;});
395
396 _uvs.insert(
397 _uvs.end(),
398 rhs.GetUVs().begin(),
399 rhs.GetUVs().end());
400
401 std::transform(
402 rhs.GetMaterials().begin(),
403 rhs.GetMaterials().end(),
404 std::back_inserter(_materials),
405 [=](MeshMaterial mat) {
406 mat.index_start += i_num;
407 mat.index_end += i_num;
408 return mat;
409 });
410
411 return *this;
412 }
413
414 Mesh operator+(const Mesh &lhs, const Mesh &rhs) {
415 Mesh m = lhs;
416 return m += rhs;
417 }
418
419} // namespace geom
420} // namespace carla
#define DEBUG_ASSERT(predicate)
Definition Debug.h:68
网格数据容器、验证器和导出器。
Definition Mesh.h:43
void AddIndex(index_type index)
将索引附加到索引列表。
Definition Mesh.cpp:132
void AddVertex(vertex_type vertex)
将顶点附加到顶点列表。
Definition Mesh.cpp:120
std::vector< vertex_type > _vertices
Definition Mesh.h:229
void AddVertices(const std::vector< vertex_type > &vertices)
将顶点附加到顶点列表。
Definition Mesh.cpp:124
std::string GenerateOBJ() const
返回包含 OBJ 中编码的网格的字符串。单位为米。它位于虚幻空间中。
Definition Mesh.cpp:177
void AddUV(uv_type uv)
将一个顶点附加到顶点列表,它们将被读取 3 个中的 3 个。
Definition Mesh.cpp:136
Mesh & ConcatMesh(const Mesh &rhs, int num_vertices_to_link)
将两个网格合并为一个网格
Definition Mesh.cpp:323
std::vector< index_type > _indexes
Definition Mesh.h:233
const std::vector< uv_type > & GetUVs() const
Definition Mesh.cpp:311
const std::vector< index_type > & GetIndexes() const
Definition Mesh.cpp:300
std::string GeneratePLY() const
返回包含 PLY 中编码的网格的字符串。单位为米。
Definition Mesh.cpp:275
bool IsValid() const
检查网格是否有效。
Definition Mesh.cpp:20
void AddUVs(const std::vector< uv_type > &uv)
添加纹理映射坐标(Texture-Mapping Coordinates, UV)
Definition Mesh.cpp:140
std::string GenerateOBJForRecast() const
返回包含 OBJ 中编码的网格的字符串。单位为米。 此函数导出 OBJ 文件,供 Recast 库专门使用。更改构建面的方向和坐标空间。
Definition Mesh.cpp:233
size_t GetVerticesNum() const
Definition Mesh.cpp:292
void AddNormal(normal_type normal)
将法线附加到法线列表。
Definition Mesh.cpp:128
std::vector< normal_type > _normals
Definition Mesh.h:231
std::vector< material_type > _materials
Definition Mesh.h:237
void AddMaterial(const std::string &material_name)
开始将新材质应用到新添加的三角形。
Definition Mesh.cpp:144
void EndMaterial()
停止将材质应用到新添加的三角形。
Definition Mesh.cpp:160
size_t index_type
Definition Mesh.h:48
Mesh & operator+=(const Mesh &rhs)
将两个网格合并为一个网格
Definition Mesh.cpp:376
const std::vector< material_type > & GetMaterials() const
Definition Mesh.cpp:315
const std::vector< normal_type > & GetNormals() const
Definition Mesh.cpp:296
size_t GetLastVertexIndex() const
返回最后添加的顶点索引(顶点数)。
Definition Mesh.cpp:319
void AddTriangleFan(const std::vector< vertex_type > &vertices)
向网格添加三角形扇形,顶点顺序为逆时针。
Definition Mesh.cpp:107
std::vector< uv_type > _uvs
Definition Mesh.h:235
size_t GetIndexesNum() const
Definition Mesh.cpp:307
void AddTriangleStrip(const std::vector< vertex_type > &vertices)
向网格添加三角形带,顶点顺序为逆时针。
Definition Mesh.cpp:52
const std::vector< vertex_type > & GetVertices() const
Definition Mesh.cpp:284
定义两个嵌套的命名空间:carla和geom。
Mesh operator+(const Mesh &lhs, const Mesh &rhs)
Definition Mesh.cpp:414
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
引用其影响的网格的顶点索引的起点和终点的材质。
Definition Mesh.h:24