Path: blob/master/scene/resources/3d/height_map_shape_3d.cpp
9898 views
/**************************************************************************/1/* height_map_shape_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "height_map_shape_3d.h"3132#include "core/io/image.h"33#include "scene/resources/mesh.h"34#include "servers/physics_server_3d.h"3536Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {37Vector<Vector3> points;3839if ((map_width != 0) && (map_depth != 0)) {40// This will be slow for large maps...41// also we'll have to figure out how well bullet centers this shape...4243Vector2 size(map_width - 1, map_depth - 1);44Vector2 start = size * -0.5;4546const real_t *r = map_data.ptr();4748// reserve some memory for our points..49points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + ((map_width - 1) * (map_depth - 1) * 2));5051// now set our points52int r_offset = 0;53int w_offset = 0;54for (int d = 0; d < map_depth; d++) {55Vector3 height(start.x, 0.0, start.y);5657for (int w = 0; w < map_width; w++) {58height.y = r[r_offset++];5960if (w != map_width - 1) {61points.write[w_offset++] = height;62points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);63}6465if (d != map_depth - 1) {66points.write[w_offset++] = height;67points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);68}6970if ((w != map_width - 1) && (d != map_depth - 1)) {71points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);72points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);73}7475height.x += 1.0;76}7778start.y += 1.0;79}80}8182return points;83}8485Ref<ArrayMesh> HeightMapShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {86Vector<Vector3> verts;87Vector<Color> colors;88Vector<int> indices;8990// This will be slow for large maps...9192if ((map_width != 0) && (map_depth != 0)) {93Vector2 size = Vector2(map_width - 1, map_depth - 1) * -0.5;94const real_t *r = map_data.ptr();9596for (int d = 0; d <= map_depth - 2; d++) {97const int this_row_offset = map_width * d;98const int next_row_offset = this_row_offset + map_width;99100for (int w = 0; w <= map_width - 2; w++) {101const float height_tl = r[next_row_offset + w];102const float height_bl = r[this_row_offset + w];103const float height_br = r[this_row_offset + w + 1];104const float height_tr = r[next_row_offset + w + 1];105106const int index_offset = verts.size();107108verts.push_back(Vector3(size.x + w, height_tl, size.y + d + 1));109verts.push_back(Vector3(size.x + w, height_bl, size.y + d));110verts.push_back(Vector3(size.x + w + 1, height_br, size.y + d));111verts.push_back(Vector3(size.x + w + 1, height_tr, size.y + d + 1));112113colors.push_back(p_modulate);114colors.push_back(p_modulate);115colors.push_back(p_modulate);116colors.push_back(p_modulate);117118indices.push_back(index_offset);119indices.push_back(index_offset + 1);120indices.push_back(index_offset + 2);121indices.push_back(index_offset);122indices.push_back(index_offset + 2);123indices.push_back(index_offset + 3);124}125}126}127128Ref<ArrayMesh> mesh = memnew(ArrayMesh);129Array a;130a.resize(Mesh::ARRAY_MAX);131a[RS::ARRAY_VERTEX] = verts;132a[RS::ARRAY_COLOR] = colors;133a[RS::ARRAY_INDEX] = indices;134mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);135136return mesh;137}138139real_t HeightMapShape3D::get_enclosing_radius() const {140return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();141}142143void HeightMapShape3D::_update_shape() {144Dictionary d;145d["width"] = map_width;146d["depth"] = map_depth;147d["heights"] = map_data;148d["min_height"] = min_height;149d["max_height"] = max_height;150PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);151Shape3D::_update_shape();152}153154void HeightMapShape3D::set_map_width(int p_new) {155if (p_new < 1) {156// ignore157} else if (map_width != p_new) {158int was_size = map_width * map_depth;159map_width = p_new;160161int new_size = map_width * map_depth;162map_data.resize(map_width * map_depth);163164real_t *w = map_data.ptrw();165while (was_size < new_size) {166w[was_size++] = 0.0;167}168169_update_shape();170emit_changed();171}172}173174int HeightMapShape3D::get_map_width() const {175return map_width;176}177178void HeightMapShape3D::set_map_depth(int p_new) {179if (p_new < 1) {180// ignore181} else if (map_depth != p_new) {182int was_size = map_width * map_depth;183map_depth = p_new;184185int new_size = map_width * map_depth;186map_data.resize(new_size);187188real_t *w = map_data.ptrw();189while (was_size < new_size) {190w[was_size++] = 0.0;191}192193_update_shape();194emit_changed();195}196}197198int HeightMapShape3D::get_map_depth() const {199return map_depth;200}201202void HeightMapShape3D::set_map_data(Vector<real_t> p_new) {203int size = (map_width * map_depth);204if (p_new.size() != size) {205// fail206return;207}208209// copy210real_t *w = map_data.ptrw();211const real_t *r = p_new.ptr();212for (int i = 0; i < size; i++) {213real_t val = r[i];214w[i] = val;215if (i == 0) {216min_height = val;217max_height = val;218} else {219if (min_height > val) {220min_height = val;221}222223if (max_height < val) {224max_height = val;225}226}227}228229_update_shape();230emit_changed();231}232233Vector<real_t> HeightMapShape3D::get_map_data() const {234return map_data;235}236237real_t HeightMapShape3D::get_min_height() const {238return min_height;239}240241real_t HeightMapShape3D::get_max_height() const {242return max_height;243}244245void HeightMapShape3D::update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max) {246ERR_FAIL_COND_MSG(p_image.is_null(), "Heightmap update image requires a valid Image reference.");247ERR_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).");248ERR_FAIL_COND_MSG(p_image->get_width() < 2, "Heightmap update image requires a minimum Image width of 2.");249ERR_FAIL_COND_MSG(p_image->get_height() < 2, "Heightmap update image requires a minimum Image height of 2.");250ERR_FAIL_COND_MSG(p_height_min > p_height_max, "Heightmap update image requires height_max to be greater than height_min.");251252map_width = p_image->get_width();253map_depth = p_image->get_height();254map_data.resize(map_width * map_depth);255256real_t new_min_height = FLT_MAX;257real_t new_max_height = -FLT_MAX;258259float remap_height_min = float(p_height_min);260float remap_height_max = float(p_height_max);261262real_t *map_data_ptrw = map_data.ptrw();263264switch (p_image->get_format()) {265case Image::FORMAT_RF: {266const float *image_data_ptr = (float *)p_image->get_data().ptr();267268for (int i = 0; i < map_data.size(); i++) {269float pixel_value = image_data_ptr[i];270271DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);272273real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);274275if (height_value < new_min_height) {276new_min_height = height_value;277}278if (height_value > new_max_height) {279new_max_height = height_value;280}281282map_data_ptrw[i] = height_value;283}284285} break;286287case Image::FORMAT_RH: {288const uint16_t *image_data_ptr = (uint16_t *)p_image->get_data().ptr();289290for (int i = 0; i < map_data.size(); i++) {291float pixel_value = Math::half_to_float(image_data_ptr[i]);292293DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);294295real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);296297if (height_value < new_min_height) {298new_min_height = height_value;299}300if (height_value > new_max_height) {301new_max_height = height_value;302}303304map_data_ptrw[i] = height_value;305}306307} break;308309case Image::FORMAT_R8: {310const uint8_t *image_data_ptr = (uint8_t *)p_image->get_data().ptr();311312for (int i = 0; i < map_data.size(); i++) {313float pixel_value = float(image_data_ptr[i] / 255.0);314315DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);316317real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);318319if (height_value < new_min_height) {320new_min_height = height_value;321}322if (height_value > new_max_height) {323new_max_height = height_value;324}325326map_data_ptrw[i] = height_value;327}328329} break;330331default: {332return;333}334}335336min_height = new_min_height;337max_height = new_max_height;338339_update_shape();340emit_changed();341}342343void HeightMapShape3D::_bind_methods() {344ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width);345ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width);346ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape3D::set_map_depth);347ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape3D::get_map_depth);348ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape3D::set_map_data);349ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape3D::get_map_data);350ClassDB::bind_method(D_METHOD("get_min_height"), &HeightMapShape3D::get_min_height);351ClassDB::bind_method(D_METHOD("get_max_height"), &HeightMapShape3D::get_max_height);352353ClassDB::bind_method(D_METHOD("update_map_data_from_image", "image", "height_min", "height_max"), &HeightMapShape3D::update_map_data_from_image);354355ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_map_width", "get_map_width");356ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_map_depth", "get_map_depth");357ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");358}359360HeightMapShape3D::HeightMapShape3D() :361Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) {362map_data.resize(map_width * map_depth);363real_t *w = map_data.ptrw();364w[0] = 0.0;365w[1] = 0.0;366w[2] = 0.0;367w[3] = 0.0;368369_update_shape();370}371372373