Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/3d/height_map_shape_3d.cpp
9898 views
1
/**************************************************************************/
2
/* height_map_shape_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 "height_map_shape_3d.h"
32
33
#include "core/io/image.h"
34
#include "scene/resources/mesh.h"
35
#include "servers/physics_server_3d.h"
36
37
Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
38
Vector<Vector3> points;
39
40
if ((map_width != 0) && (map_depth != 0)) {
41
// This will be slow for large maps...
42
// also we'll have to figure out how well bullet centers this shape...
43
44
Vector2 size(map_width - 1, map_depth - 1);
45
Vector2 start = size * -0.5;
46
47
const real_t *r = map_data.ptr();
48
49
// reserve some memory for our points..
50
points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + ((map_width - 1) * (map_depth - 1) * 2));
51
52
// now set our points
53
int r_offset = 0;
54
int w_offset = 0;
55
for (int d = 0; d < map_depth; d++) {
56
Vector3 height(start.x, 0.0, start.y);
57
58
for (int w = 0; w < map_width; w++) {
59
height.y = r[r_offset++];
60
61
if (w != map_width - 1) {
62
points.write[w_offset++] = height;
63
points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
64
}
65
66
if (d != map_depth - 1) {
67
points.write[w_offset++] = height;
68
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
69
}
70
71
if ((w != map_width - 1) && (d != map_depth - 1)) {
72
points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
73
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
74
}
75
76
height.x += 1.0;
77
}
78
79
start.y += 1.0;
80
}
81
}
82
83
return points;
84
}
85
86
Ref<ArrayMesh> HeightMapShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
87
Vector<Vector3> verts;
88
Vector<Color> colors;
89
Vector<int> indices;
90
91
// This will be slow for large maps...
92
93
if ((map_width != 0) && (map_depth != 0)) {
94
Vector2 size = Vector2(map_width - 1, map_depth - 1) * -0.5;
95
const real_t *r = map_data.ptr();
96
97
for (int d = 0; d <= map_depth - 2; d++) {
98
const int this_row_offset = map_width * d;
99
const int next_row_offset = this_row_offset + map_width;
100
101
for (int w = 0; w <= map_width - 2; w++) {
102
const float height_tl = r[next_row_offset + w];
103
const float height_bl = r[this_row_offset + w];
104
const float height_br = r[this_row_offset + w + 1];
105
const float height_tr = r[next_row_offset + w + 1];
106
107
const int index_offset = verts.size();
108
109
verts.push_back(Vector3(size.x + w, height_tl, size.y + d + 1));
110
verts.push_back(Vector3(size.x + w, height_bl, size.y + d));
111
verts.push_back(Vector3(size.x + w + 1, height_br, size.y + d));
112
verts.push_back(Vector3(size.x + w + 1, height_tr, size.y + d + 1));
113
114
colors.push_back(p_modulate);
115
colors.push_back(p_modulate);
116
colors.push_back(p_modulate);
117
colors.push_back(p_modulate);
118
119
indices.push_back(index_offset);
120
indices.push_back(index_offset + 1);
121
indices.push_back(index_offset + 2);
122
indices.push_back(index_offset);
123
indices.push_back(index_offset + 2);
124
indices.push_back(index_offset + 3);
125
}
126
}
127
}
128
129
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
130
Array a;
131
a.resize(Mesh::ARRAY_MAX);
132
a[RS::ARRAY_VERTEX] = verts;
133
a[RS::ARRAY_COLOR] = colors;
134
a[RS::ARRAY_INDEX] = indices;
135
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
136
137
return mesh;
138
}
139
140
real_t HeightMapShape3D::get_enclosing_radius() const {
141
return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
142
}
143
144
void HeightMapShape3D::_update_shape() {
145
Dictionary d;
146
d["width"] = map_width;
147
d["depth"] = map_depth;
148
d["heights"] = map_data;
149
d["min_height"] = min_height;
150
d["max_height"] = max_height;
151
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
152
Shape3D::_update_shape();
153
}
154
155
void HeightMapShape3D::set_map_width(int p_new) {
156
if (p_new < 1) {
157
// ignore
158
} else if (map_width != p_new) {
159
int was_size = map_width * map_depth;
160
map_width = p_new;
161
162
int new_size = map_width * map_depth;
163
map_data.resize(map_width * map_depth);
164
165
real_t *w = map_data.ptrw();
166
while (was_size < new_size) {
167
w[was_size++] = 0.0;
168
}
169
170
_update_shape();
171
emit_changed();
172
}
173
}
174
175
int HeightMapShape3D::get_map_width() const {
176
return map_width;
177
}
178
179
void HeightMapShape3D::set_map_depth(int p_new) {
180
if (p_new < 1) {
181
// ignore
182
} else if (map_depth != p_new) {
183
int was_size = map_width * map_depth;
184
map_depth = p_new;
185
186
int new_size = map_width * map_depth;
187
map_data.resize(new_size);
188
189
real_t *w = map_data.ptrw();
190
while (was_size < new_size) {
191
w[was_size++] = 0.0;
192
}
193
194
_update_shape();
195
emit_changed();
196
}
197
}
198
199
int HeightMapShape3D::get_map_depth() const {
200
return map_depth;
201
}
202
203
void HeightMapShape3D::set_map_data(Vector<real_t> p_new) {
204
int size = (map_width * map_depth);
205
if (p_new.size() != size) {
206
// fail
207
return;
208
}
209
210
// copy
211
real_t *w = map_data.ptrw();
212
const real_t *r = p_new.ptr();
213
for (int i = 0; i < size; i++) {
214
real_t val = r[i];
215
w[i] = val;
216
if (i == 0) {
217
min_height = val;
218
max_height = val;
219
} else {
220
if (min_height > val) {
221
min_height = val;
222
}
223
224
if (max_height < val) {
225
max_height = val;
226
}
227
}
228
}
229
230
_update_shape();
231
emit_changed();
232
}
233
234
Vector<real_t> HeightMapShape3D::get_map_data() const {
235
return map_data;
236
}
237
238
real_t HeightMapShape3D::get_min_height() const {
239
return min_height;
240
}
241
242
real_t HeightMapShape3D::get_max_height() const {
243
return max_height;
244
}
245
246
void HeightMapShape3D::update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max) {
247
ERR_FAIL_COND_MSG(p_image.is_null(), "Heightmap update image requires a valid Image reference.");
248
ERR_FAIL_COND_MSG(p_image->get_format() != Image::FORMAT_RF && p_image->get_format() != Image::FORMAT_RH && p_image->get_format() != Image::FORMAT_R8, "Heightmap update image requires Image in format FORMAT_RF (32 bit), FORMAT_RH (16 bit), or FORMAT_R8 (8 bit).");
249
ERR_FAIL_COND_MSG(p_image->get_width() < 2, "Heightmap update image requires a minimum Image width of 2.");
250
ERR_FAIL_COND_MSG(p_image->get_height() < 2, "Heightmap update image requires a minimum Image height of 2.");
251
ERR_FAIL_COND_MSG(p_height_min > p_height_max, "Heightmap update image requires height_max to be greater than height_min.");
252
253
map_width = p_image->get_width();
254
map_depth = p_image->get_height();
255
map_data.resize(map_width * map_depth);
256
257
real_t new_min_height = FLT_MAX;
258
real_t new_max_height = -FLT_MAX;
259
260
float remap_height_min = float(p_height_min);
261
float remap_height_max = float(p_height_max);
262
263
real_t *map_data_ptrw = map_data.ptrw();
264
265
switch (p_image->get_format()) {
266
case Image::FORMAT_RF: {
267
const float *image_data_ptr = (float *)p_image->get_data().ptr();
268
269
for (int i = 0; i < map_data.size(); i++) {
270
float pixel_value = image_data_ptr[i];
271
272
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
273
274
real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
275
276
if (height_value < new_min_height) {
277
new_min_height = height_value;
278
}
279
if (height_value > new_max_height) {
280
new_max_height = height_value;
281
}
282
283
map_data_ptrw[i] = height_value;
284
}
285
286
} break;
287
288
case Image::FORMAT_RH: {
289
const uint16_t *image_data_ptr = (uint16_t *)p_image->get_data().ptr();
290
291
for (int i = 0; i < map_data.size(); i++) {
292
float pixel_value = Math::half_to_float(image_data_ptr[i]);
293
294
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
295
296
real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
297
298
if (height_value < new_min_height) {
299
new_min_height = height_value;
300
}
301
if (height_value > new_max_height) {
302
new_max_height = height_value;
303
}
304
305
map_data_ptrw[i] = height_value;
306
}
307
308
} break;
309
310
case Image::FORMAT_R8: {
311
const uint8_t *image_data_ptr = (uint8_t *)p_image->get_data().ptr();
312
313
for (int i = 0; i < map_data.size(); i++) {
314
float pixel_value = float(image_data_ptr[i] / 255.0);
315
316
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
317
318
real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
319
320
if (height_value < new_min_height) {
321
new_min_height = height_value;
322
}
323
if (height_value > new_max_height) {
324
new_max_height = height_value;
325
}
326
327
map_data_ptrw[i] = height_value;
328
}
329
330
} break;
331
332
default: {
333
return;
334
}
335
}
336
337
min_height = new_min_height;
338
max_height = new_max_height;
339
340
_update_shape();
341
emit_changed();
342
}
343
344
void HeightMapShape3D::_bind_methods() {
345
ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width);
346
ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width);
347
ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape3D::set_map_depth);
348
ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape3D::get_map_depth);
349
ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape3D::set_map_data);
350
ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape3D::get_map_data);
351
ClassDB::bind_method(D_METHOD("get_min_height"), &HeightMapShape3D::get_min_height);
352
ClassDB::bind_method(D_METHOD("get_max_height"), &HeightMapShape3D::get_max_height);
353
354
ClassDB::bind_method(D_METHOD("update_map_data_from_image", "image", "height_min", "height_max"), &HeightMapShape3D::update_map_data_from_image);
355
356
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_map_width", "get_map_width");
357
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_map_depth", "get_map_depth");
358
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");
359
}
360
361
HeightMapShape3D::HeightMapShape3D() :
362
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) {
363
map_data.resize(map_width * map_depth);
364
real_t *w = map_data.ptrw();
365
w[0] = 0.0;
366
w[1] = 0.0;
367
w[2] = 0.0;
368
w[3] = 0.0;
369
370
_update_shape();
371
}
372
373