|
@@ -30,6 +30,7 @@
|
|
|
|
|
|
#include "height_map_shape_3d.h"
|
|
|
|
|
|
+#include "core/io/image.h"
|
|
|
#include "servers/physics_server_3d.h"
|
|
|
|
|
|
Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
|
|
@@ -187,6 +188,104 @@ real_t HeightMapShape3D::get_max_height() const {
|
|
|
return max_height;
|
|
|
}
|
|
|
|
|
|
+void HeightMapShape3D::update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max) {
|
|
|
+ ERR_FAIL_COND_MSG(p_image.is_null(), "Heightmap update image requires a valid Image reference.");
|
|
|
+ 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).");
|
|
|
+ ERR_FAIL_COND_MSG(p_image->get_width() < 2, "Heightmap update image requires a minimum Image width of 2.");
|
|
|
+ ERR_FAIL_COND_MSG(p_image->get_height() < 2, "Heightmap update image requires a minimum Image height of 2.");
|
|
|
+ ERR_FAIL_COND_MSG(p_height_min > p_height_max, "Heightmap update image requires height_max to be greater than height_min.");
|
|
|
+
|
|
|
+ map_width = p_image->get_width();
|
|
|
+ map_depth = p_image->get_height();
|
|
|
+ map_data.resize(map_width * map_depth);
|
|
|
+
|
|
|
+ real_t new_min_height = FLT_MAX;
|
|
|
+ real_t new_max_height = -FLT_MAX;
|
|
|
+
|
|
|
+ float remap_height_min = float(p_height_min);
|
|
|
+ float remap_height_max = float(p_height_max);
|
|
|
+
|
|
|
+ real_t *map_data_ptrw = map_data.ptrw();
|
|
|
+
|
|
|
+ switch (p_image->get_format()) {
|
|
|
+ case Image::FORMAT_RF: {
|
|
|
+ const float *image_data_ptr = (float *)p_image->get_data().ptr();
|
|
|
+
|
|
|
+ for (int i = 0; i < map_data.size(); i++) {
|
|
|
+ float pixel_value = image_data_ptr[i];
|
|
|
+
|
|
|
+ DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
|
|
|
+
|
|
|
+ real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
|
|
|
+
|
|
|
+ if (height_value < new_min_height) {
|
|
|
+ new_min_height = height_value;
|
|
|
+ }
|
|
|
+ if (height_value > new_max_height) {
|
|
|
+ new_max_height = height_value;
|
|
|
+ }
|
|
|
+
|
|
|
+ map_data_ptrw[i] = height_value;
|
|
|
+ }
|
|
|
+
|
|
|
+ } break;
|
|
|
+
|
|
|
+ case Image::FORMAT_RH: {
|
|
|
+ const uint16_t *image_data_ptr = (uint16_t *)p_image->get_data().ptr();
|
|
|
+
|
|
|
+ for (int i = 0; i < map_data.size(); i++) {
|
|
|
+ float pixel_value = Math::half_to_float(image_data_ptr[i]);
|
|
|
+
|
|
|
+ DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
|
|
|
+
|
|
|
+ real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
|
|
|
+
|
|
|
+ if (height_value < new_min_height) {
|
|
|
+ new_min_height = height_value;
|
|
|
+ }
|
|
|
+ if (height_value > new_max_height) {
|
|
|
+ new_max_height = height_value;
|
|
|
+ }
|
|
|
+
|
|
|
+ map_data_ptrw[i] = height_value;
|
|
|
+ }
|
|
|
+
|
|
|
+ } break;
|
|
|
+
|
|
|
+ case Image::FORMAT_R8: {
|
|
|
+ const uint8_t *image_data_ptr = (uint8_t *)p_image->get_data().ptr();
|
|
|
+
|
|
|
+ for (int i = 0; i < map_data.size(); i++) {
|
|
|
+ float pixel_value = float(image_data_ptr[i] / 255.0);
|
|
|
+
|
|
|
+ DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
|
|
|
+
|
|
|
+ real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
|
|
|
+
|
|
|
+ if (height_value < new_min_height) {
|
|
|
+ new_min_height = height_value;
|
|
|
+ }
|
|
|
+ if (height_value > new_max_height) {
|
|
|
+ new_max_height = height_value;
|
|
|
+ }
|
|
|
+
|
|
|
+ map_data_ptrw[i] = height_value;
|
|
|
+ }
|
|
|
+
|
|
|
+ } break;
|
|
|
+
|
|
|
+ default: {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ min_height = new_min_height;
|
|
|
+ max_height = new_max_height;
|
|
|
+
|
|
|
+ _update_shape();
|
|
|
+ emit_changed();
|
|
|
+}
|
|
|
+
|
|
|
void HeightMapShape3D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width);
|
|
|
ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width);
|
|
@@ -197,6 +296,8 @@ void HeightMapShape3D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("get_min_height"), &HeightMapShape3D::get_min_height);
|
|
|
ClassDB::bind_method(D_METHOD("get_max_height"), &HeightMapShape3D::get_max_height);
|
|
|
|
|
|
+ ClassDB::bind_method(D_METHOD("update_map_data_from_image", "image", "height_min", "height_max"), &HeightMapShape3D::update_map_data_from_image);
|
|
|
+
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_width", "get_map_width");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_depth", "get_map_depth");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");
|