Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
9903 views
1
/**************************************************************************/
2
/* navigation_mesh_source_geometry_data_3d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "navigation_mesh_source_geometry_data_3d.h"
32
33
void NavigationMeshSourceGeometryData3D::set_vertices(const Vector<float> &p_vertices) {
34
RWLockWrite write_lock(geometry_rwlock);
35
vertices = p_vertices;
36
bounds_dirty = true;
37
}
38
39
const Vector<float> &NavigationMeshSourceGeometryData3D::get_vertices() const {
40
RWLockRead read_lock(geometry_rwlock);
41
return vertices;
42
}
43
44
void NavigationMeshSourceGeometryData3D::set_indices(const Vector<int> &p_indices) {
45
ERR_FAIL_COND(vertices.size() < p_indices.size());
46
RWLockWrite write_lock(geometry_rwlock);
47
indices = p_indices;
48
bounds_dirty = true;
49
}
50
51
const Vector<int> &NavigationMeshSourceGeometryData3D::get_indices() const {
52
RWLockRead read_lock(geometry_rwlock);
53
return indices;
54
}
55
56
void NavigationMeshSourceGeometryData3D::append_arrays(const Vector<float> &p_vertices, const Vector<int> &p_indices) {
57
RWLockWrite write_lock(geometry_rwlock);
58
59
const int64_t number_of_vertices_before_merge = vertices.size();
60
const int64_t number_of_indices_before_merge = indices.size();
61
62
vertices.append_array(p_vertices);
63
indices.append_array(p_indices);
64
65
for (int64_t i = number_of_indices_before_merge; i < indices.size(); i++) {
66
indices.set(i, indices[i] + number_of_vertices_before_merge / 3);
67
}
68
bounds_dirty = true;
69
}
70
71
bool NavigationMeshSourceGeometryData3D::has_data() {
72
RWLockRead read_lock(geometry_rwlock);
73
return vertices.size() && indices.size();
74
}
75
76
void NavigationMeshSourceGeometryData3D::clear() {
77
RWLockWrite write_lock(geometry_rwlock);
78
vertices.clear();
79
indices.clear();
80
_projected_obstructions.clear();
81
bounds_dirty = true;
82
}
83
84
void NavigationMeshSourceGeometryData3D::clear_projected_obstructions() {
85
RWLockWrite write_lock(geometry_rwlock);
86
_projected_obstructions.clear();
87
bounds_dirty = true;
88
}
89
90
void NavigationMeshSourceGeometryData3D::_add_vertex(const Vector3 &p_vec3) {
91
vertices.push_back(p_vec3.x);
92
vertices.push_back(p_vec3.y);
93
vertices.push_back(p_vec3.z);
94
}
95
96
void NavigationMeshSourceGeometryData3D::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
97
int current_vertex_count;
98
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
99
current_vertex_count = vertices.size() / 3;
100
101
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
102
continue;
103
}
104
105
int index_count = 0;
106
if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
107
index_count = p_mesh->surface_get_array_index_len(i);
108
} else {
109
index_count = p_mesh->surface_get_array_len(i);
110
}
111
112
ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));
113
114
int face_count = index_count / 3;
115
116
Array a = p_mesh->surface_get_arrays(i);
117
ERR_CONTINUE(a.is_empty() || (a.size() != Mesh::ARRAY_MAX));
118
119
Vector<Vector3> mesh_vertices = a[Mesh::ARRAY_VERTEX];
120
ERR_CONTINUE(mesh_vertices.is_empty());
121
const Vector3 *vr = mesh_vertices.ptr();
122
123
if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
124
Vector<int> mesh_indices = a[Mesh::ARRAY_INDEX];
125
ERR_CONTINUE(mesh_indices.is_empty() || (mesh_indices.size() != index_count));
126
const int *ir = mesh_indices.ptr();
127
128
for (int j = 0; j < mesh_vertices.size(); j++) {
129
_add_vertex(p_xform.xform(vr[j]));
130
}
131
132
for (int j = 0; j < face_count; j++) {
133
// CCW
134
indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
135
indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
136
indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
137
}
138
} else {
139
ERR_CONTINUE(mesh_vertices.size() != index_count);
140
face_count = mesh_vertices.size() / 3;
141
for (int j = 0; j < face_count; j++) {
142
_add_vertex(p_xform.xform(vr[j * 3 + 0]));
143
_add_vertex(p_xform.xform(vr[j * 3 + 2]));
144
_add_vertex(p_xform.xform(vr[j * 3 + 1]));
145
146
indices.push_back(current_vertex_count + (j * 3 + 0));
147
indices.push_back(current_vertex_count + (j * 3 + 1));
148
indices.push_back(current_vertex_count + (j * 3 + 2));
149
}
150
}
151
}
152
}
153
154
void NavigationMeshSourceGeometryData3D::_add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {
155
ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);
156
157
Vector<Vector3> mesh_vertices = p_mesh_array[Mesh::ARRAY_VERTEX];
158
ERR_FAIL_COND(mesh_vertices.is_empty());
159
const Vector3 *vr = mesh_vertices.ptr();
160
161
Vector<int> mesh_indices = p_mesh_array[Mesh::ARRAY_INDEX];
162
ERR_FAIL_COND(mesh_indices.is_empty());
163
const int *ir = mesh_indices.ptr();
164
165
const int face_count = mesh_indices.size() / 3;
166
const int current_vertex_count = vertices.size() / 3;
167
168
for (int j = 0; j < mesh_vertices.size(); j++) {
169
_add_vertex(p_xform.xform(vr[j]));
170
}
171
172
for (int j = 0; j < face_count; j++) {
173
// CCW
174
indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
175
indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
176
indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
177
}
178
}
179
180
void NavigationMeshSourceGeometryData3D::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {
181
ERR_FAIL_COND(p_faces.is_empty());
182
ERR_FAIL_COND(p_faces.size() % 3 != 0);
183
int face_count = p_faces.size() / 3;
184
int current_vertex_count = vertices.size() / 3;
185
186
for (int j = 0; j < face_count; j++) {
187
_add_vertex(p_xform.xform(p_faces[j * 3 + 0]));
188
_add_vertex(p_xform.xform(p_faces[j * 3 + 1]));
189
_add_vertex(p_xform.xform(p_faces[j * 3 + 2]));
190
191
indices.push_back(current_vertex_count + (j * 3 + 0));
192
indices.push_back(current_vertex_count + (j * 3 + 2));
193
indices.push_back(current_vertex_count + (j * 3 + 1));
194
}
195
}
196
197
void NavigationMeshSourceGeometryData3D::add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
198
ERR_FAIL_COND(p_mesh.is_null());
199
200
#ifdef DEBUG_ENABLED
201
if (!Engine::get_singleton()->is_editor_hint()) {
202
WARN_PRINT_ONCE("Source geometry parsing for navigation mesh baking had to parse RenderingServer meshes at runtime.\n\
203
This poses a significant performance issues as visual meshes store geometry data on the GPU and transferring this data back to the CPU blocks the rendering.\n\
204
For runtime (re)baking navigation meshes use and parse collision shapes as source geometry or create geometry data procedurally in scripts.");
205
}
206
#endif
207
208
_add_mesh(p_mesh, root_node_transform * p_xform);
209
}
210
211
void NavigationMeshSourceGeometryData3D::add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {
212
ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);
213
RWLockWrite write_lock(geometry_rwlock);
214
_add_mesh_array(p_mesh_array, root_node_transform * p_xform);
215
bounds_dirty = true;
216
}
217
218
void NavigationMeshSourceGeometryData3D::add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {
219
ERR_FAIL_COND(p_faces.size() % 3 != 0);
220
RWLockWrite write_lock(geometry_rwlock);
221
_add_faces(p_faces, root_node_transform * p_xform);
222
bounds_dirty = true;
223
}
224
225
void NavigationMeshSourceGeometryData3D::merge(const Ref<NavigationMeshSourceGeometryData3D> &p_other_geometry) {
226
ERR_FAIL_COND(p_other_geometry.is_null());
227
228
Vector<float> other_vertices;
229
Vector<int> other_indices;
230
Vector<ProjectedObstruction> other_projected_obstructions;
231
232
p_other_geometry->get_data(other_vertices, other_indices, other_projected_obstructions);
233
234
RWLockWrite write_lock(geometry_rwlock);
235
const int64_t number_of_vertices_before_merge = vertices.size();
236
const int64_t number_of_indices_before_merge = indices.size();
237
238
vertices.append_array(other_vertices);
239
indices.append_array(other_indices);
240
241
for (int64_t i = number_of_indices_before_merge; i < indices.size(); i++) {
242
indices.set(i, indices[i] + number_of_vertices_before_merge / 3);
243
}
244
245
_projected_obstructions.append_array(other_projected_obstructions);
246
bounds_dirty = true;
247
}
248
249
void NavigationMeshSourceGeometryData3D::add_projected_obstruction(const Vector<Vector3> &p_vertices, float p_elevation, float p_height, bool p_carve) {
250
ERR_FAIL_COND(p_vertices.size() < 3);
251
ERR_FAIL_COND(p_height < 0.0);
252
253
ProjectedObstruction projected_obstruction;
254
projected_obstruction.vertices.resize(p_vertices.size() * 3);
255
projected_obstruction.elevation = p_elevation;
256
projected_obstruction.height = p_height;
257
projected_obstruction.carve = p_carve;
258
259
float *obstruction_vertices_ptrw = projected_obstruction.vertices.ptrw();
260
261
int vertex_index = 0;
262
for (const Vector3 &vertex : p_vertices) {
263
obstruction_vertices_ptrw[vertex_index++] = vertex.x;
264
obstruction_vertices_ptrw[vertex_index++] = vertex.y;
265
obstruction_vertices_ptrw[vertex_index++] = vertex.z;
266
}
267
268
RWLockWrite write_lock(geometry_rwlock);
269
_projected_obstructions.push_back(projected_obstruction);
270
bounds_dirty = true;
271
}
272
273
void NavigationMeshSourceGeometryData3D::set_projected_obstructions(const Array &p_array) {
274
clear_projected_obstructions();
275
276
for (int i = 0; i < p_array.size(); i++) {
277
Dictionary data = p_array[i];
278
ERR_FAIL_COND(!data.has("version"));
279
280
uint32_t po_version = data["version"];
281
282
if (po_version == 1) {
283
ERR_FAIL_COND(!data.has("vertices"));
284
ERR_FAIL_COND(!data.has("elevation"));
285
ERR_FAIL_COND(!data.has("height"));
286
ERR_FAIL_COND(!data.has("carve"));
287
}
288
289
ProjectedObstruction projected_obstruction;
290
projected_obstruction.vertices = Vector<float>(data["vertices"]);
291
projected_obstruction.elevation = data["elevation"];
292
projected_obstruction.height = data["height"];
293
projected_obstruction.carve = data["carve"];
294
295
RWLockWrite write_lock(geometry_rwlock);
296
_projected_obstructions.push_back(projected_obstruction);
297
bounds_dirty = true;
298
}
299
}
300
301
Vector<NavigationMeshSourceGeometryData3D::ProjectedObstruction> NavigationMeshSourceGeometryData3D::_get_projected_obstructions() const {
302
RWLockRead read_lock(geometry_rwlock);
303
return _projected_obstructions;
304
}
305
306
Array NavigationMeshSourceGeometryData3D::get_projected_obstructions() const {
307
RWLockRead read_lock(geometry_rwlock);
308
309
Array ret;
310
ret.resize(_projected_obstructions.size());
311
312
for (int i = 0; i < _projected_obstructions.size(); i++) {
313
const ProjectedObstruction &projected_obstruction = _projected_obstructions[i];
314
315
Dictionary data;
316
data["version"] = (int)ProjectedObstruction::VERSION;
317
data["vertices"] = projected_obstruction.vertices;
318
data["elevation"] = projected_obstruction.elevation;
319
data["height"] = projected_obstruction.height;
320
data["carve"] = projected_obstruction.carve;
321
322
ret[i] = data;
323
}
324
325
return ret;
326
}
327
328
bool NavigationMeshSourceGeometryData3D::_set(const StringName &p_name, const Variant &p_value) {
329
if (p_name == "projected_obstructions") {
330
set_projected_obstructions(p_value);
331
return true;
332
}
333
return false;
334
}
335
336
bool NavigationMeshSourceGeometryData3D::_get(const StringName &p_name, Variant &r_ret) const {
337
if (p_name == "projected_obstructions") {
338
r_ret = get_projected_obstructions();
339
return true;
340
}
341
return false;
342
}
343
344
void NavigationMeshSourceGeometryData3D::set_data(const Vector<float> &p_vertices, const Vector<int> &p_indices, Vector<ProjectedObstruction> &p_projected_obstructions) {
345
RWLockWrite write_lock(geometry_rwlock);
346
vertices = p_vertices;
347
indices = p_indices;
348
_projected_obstructions = p_projected_obstructions;
349
bounds_dirty = true;
350
}
351
352
void NavigationMeshSourceGeometryData3D::get_data(Vector<float> &r_vertices, Vector<int> &r_indices, Vector<ProjectedObstruction> &r_projected_obstructions) {
353
RWLockRead read_lock(geometry_rwlock);
354
r_vertices = vertices;
355
r_indices = indices;
356
r_projected_obstructions = _projected_obstructions;
357
}
358
359
AABB NavigationMeshSourceGeometryData3D::get_bounds() {
360
geometry_rwlock.read_lock();
361
362
if (bounds_dirty) {
363
geometry_rwlock.read_unlock();
364
RWLockWrite write_lock(geometry_rwlock);
365
366
bounds_dirty = false;
367
bounds = AABB();
368
bool first_vertex = true;
369
370
for (int i = 0; i < vertices.size() / 3; i++) {
371
const Vector3 vertex = Vector3(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
372
if (first_vertex) {
373
first_vertex = false;
374
bounds.position = vertex;
375
} else {
376
bounds.expand_to(vertex);
377
}
378
}
379
for (const ProjectedObstruction &projected_obstruction : _projected_obstructions) {
380
for (int i = 0; i < projected_obstruction.vertices.size() / 3; i++) {
381
const Vector3 vertex = Vector3(projected_obstruction.vertices[i * 3], projected_obstruction.vertices[i * 3 + 1], projected_obstruction.vertices[i * 3 + 2]);
382
if (first_vertex) {
383
first_vertex = false;
384
bounds.position = vertex;
385
} else {
386
bounds.expand_to(vertex);
387
}
388
}
389
}
390
} else {
391
geometry_rwlock.read_unlock();
392
}
393
394
RWLockRead read_lock(geometry_rwlock);
395
return bounds;
396
}
397
398
void NavigationMeshSourceGeometryData3D::_bind_methods() {
399
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMeshSourceGeometryData3D::set_vertices);
400
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMeshSourceGeometryData3D::get_vertices);
401
402
ClassDB::bind_method(D_METHOD("set_indices", "indices"), &NavigationMeshSourceGeometryData3D::set_indices);
403
ClassDB::bind_method(D_METHOD("get_indices"), &NavigationMeshSourceGeometryData3D::get_indices);
404
405
ClassDB::bind_method(D_METHOD("append_arrays", "vertices", "indices"), &NavigationMeshSourceGeometryData3D::append_arrays);
406
407
ClassDB::bind_method(D_METHOD("clear"), &NavigationMeshSourceGeometryData3D::clear);
408
ClassDB::bind_method(D_METHOD("has_data"), &NavigationMeshSourceGeometryData3D::has_data);
409
410
ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh);
411
ClassDB::bind_method(D_METHOD("add_mesh_array", "mesh_array", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh_array);
412
ClassDB::bind_method(D_METHOD("add_faces", "faces", "xform"), &NavigationMeshSourceGeometryData3D::add_faces);
413
ClassDB::bind_method(D_METHOD("merge", "other_geometry"), &NavigationMeshSourceGeometryData3D::merge);
414
415
ClassDB::bind_method(D_METHOD("add_projected_obstruction", "vertices", "elevation", "height", "carve"), &NavigationMeshSourceGeometryData3D::add_projected_obstruction);
416
ClassDB::bind_method(D_METHOD("clear_projected_obstructions"), &NavigationMeshSourceGeometryData3D::clear_projected_obstructions);
417
ClassDB::bind_method(D_METHOD("set_projected_obstructions", "projected_obstructions"), &NavigationMeshSourceGeometryData3D::set_projected_obstructions);
418
ClassDB::bind_method(D_METHOD("get_projected_obstructions"), &NavigationMeshSourceGeometryData3D::get_projected_obstructions);
419
420
ClassDB::bind_method(D_METHOD("get_bounds"), &NavigationMeshSourceGeometryData3D::get_bounds);
421
422
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
423
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_indices", "get_indices");
424
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "projected_obstructions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_projected_obstructions", "get_projected_obstructions");
425
}
426
427