From 8c4432031e3d59c5bffe313d1e8bfde7bcedae66 Mon Sep 17 00:00:00 2001 From: Segey Lapin Date: Thu, 14 Oct 2021 13:42:21 +0300 Subject: [PATCH] Updated sdf code to work in C++ --- modules/world/road_grid.cpp | 71 ++++++++---- modules/world/road_grid.h | 2 +- modules/world/roads.cpp | 7 +- modules/world/world_generator.cpp | 174 ++---------------------------- modules/world/world_generator.h | 110 +++---------------- 5 files changed, 77 insertions(+), 287 deletions(-) diff --git a/modules/world/road_grid.cpp b/modules/world/road_grid.cpp index d9be4c9..5d5f05f 100644 --- a/modules/world/road_grid.cpp +++ b/modules/world/road_grid.cpp @@ -170,25 +170,30 @@ void RoadGrid::index_site(struct map_site *site) site->polygon_ind.resize(site->polygon.size()); /* slow as fuck */ for (i = 0; i < site->vertices.size(); i++) { - int idx = diagram_vertices.find(site->vertices[i]); + Vector2 v = site->vertices[i].snapped(Vector2(2.0f, 2.0f)); + int idx = diagram_vertices.find(v); if (idx < 0) { idx = diagram_vertices.size(); - diagram_vertices.push_back(site->vertices[i]); + diagram_vertices.push_back(v); } site->vertices_ind.write[i] = idx; } for (i = 0; i < site->polygon.size(); i++) { - int idx = diagram_vertices.find(site->polygon[i]); + Vector2 v = site->polygon[i].snapped(Vector2(2.0f, 2.0f)); + int idx = diagram_vertices.find(v); if (idx < 0) { idx = diagram_vertices.size(); - diagram_vertices.push_back(site->polygon[i]); + diagram_vertices.push_back(v); } site->polygon_ind.write[i] = idx; } site->hedges.resize(site->polygon.size()); + int count = 0; for (i = 0; i < site->polygon.size(); i++) { int idx1 = site->polygon_ind[i]; int idx2 = site->polygon_ind[(i + 1) % site->polygon.size()]; + if (idx1 == idx2) + continue; struct half_edge he; he.a = idx1; he.b = idx2; @@ -196,8 +201,9 @@ void RoadGrid::index_site(struct map_site *site) /* use length to decide */ he.depth = 6.0f; he.length = diagram_vertices[idx1].distance_to(diagram_vertices[idx2]); - site->hedges.write[i] = he; + site->hedges.write[count++] = he; } + site->hedges.resize(count); } void RoadGrid::process_diagram(const Dictionary &diagram) @@ -256,14 +262,14 @@ void RoadGrid::build(Ref curve, Ref noise) rnd->randomize(); printf("build_diagram\n"); // Dictionary diagram = build_diagram(8, 2 + (rnd->randi() % 2), 100, 100, 50); - Dictionary diagram = build_diagram(8, 2, 100, 100, 30); + Dictionary diagram = build_diagram(8, 2, 100, 100, 500); printf("build_diagram done\n"); printf("process_diagram\n"); process_diagram(diagram); printf("process_diagram done\n"); printf("%d %d\n", curve.is_valid(), noise.is_valid()); assert(curve.is_valid() && noise.is_valid()); - int i; + int i, j; if (curve.is_valid() && noise.is_valid()) { printf("building 3rd dimention\n"); diagram_vertex_heights.resize(diagram_vertices.size()); @@ -271,30 +277,49 @@ void RoadGrid::build(Ref curve, Ref noise) float n = noise->get_noise_2dv(diagram_vertices[i]); float t = (n + 1.0f) * 0.5f; float d = MAX(1.0f, curve->interpolate_baked(t)); + d = CLAMP(d, 1.0f, 30.0f); diagram_vertex_heights.write[i] = d; } - for (i = 0; i < map_hedges.size(); i++) { - int x1 = map_hedges[i]->a; - int x2 = map_hedges[i]->b; - float xd = diagram_vertices[x1].distance_squared_to(diagram_vertices[x2]); - float dh = fabsf(diagram_vertex_heights[x2] - diagram_vertex_heights[x1]); - if (fabsf(dh / xd) > 0.02f) - diagram_vertex_heights.write[x2] = diagram_vertex_heights[x1] + dh / fabsf(dh) * 0.02f * xd; + for (j = 0; j < 3; j++) { + for (i = 0; i < map_hedges.size(); i++) { + int x1 = map_hedges[i]->a; + int x2 = map_hedges[i]->b; + float xd = map_hedges[i]->length; + float dh = fabsf(diagram_vertex_heights[x2] - diagram_vertex_heights[x1]); + if (fabsf(dh / xd) > 0.01f) + diagram_vertex_heights.write[x2] = diagram_vertex_heights[x1] + dh / fabsf(dh) * 0.01f * xd; + } +#if 0 + for (i = 0; i < diagram_vertices.size(); i++) + diagram_vertex_heights.write[i] = Math::stepify(diagram_vertex_heights.write[i], 4.0f); + for (i = 0; i < diagram_vertices.size(); i++) + diagram_vertex_heights.write[i] = 2.0; +#endif } printf("building 3rd dimention done\n"); } } -Vector2 RoadGrid::get_influence(int x, int y) const +Vector2 RoadGrid::get_influence(int x, int y, float radius) const { - static int mind = 1000000; - static int maxd = 0; + int rd = (int)(radius / grid_width) + 1; List hlist; - if (hedge_grid.has(x / grid_width) && hedge_grid[x / grid_width].has(y / grid_height)) - hlist = hedge_grid[x / grid_width][y / grid_height]; + List::Element *e; + int i = 0, j = 0; + for (i = -rd; i < rd + 1; i++) + for (j = -rd; j < rd + 1; j++) { + List tmp; + if (hedge_grid.has(x / grid_width + i) && hedge_grid[x / grid_width + i].has(y / grid_height + j)) { + tmp = hedge_grid[x / grid_width + i][y / grid_height + j]; + for (e = tmp.front(); e; e = e->next()) { + struct half_edge *d = e->get(); + hlist.push_back(d); + } + } + + } if (hlist.size() == 0) return Vector2(); - List::Element *e; for (e = hlist.front(); e; e = e->next()) { struct half_edge *he = e->get(); Vector2 a = diagram_vertices[he->a]; @@ -303,7 +328,7 @@ Vector2 RoadGrid::get_influence(int x, int y) const Vector2 seg[] = {a, b}; Vector2 pt = Geometry::get_closest_point_to_segment_2d(p, seg); float d = pt.distance_squared_to(p); - if (d < MAX(96.0f * 96.0f, he->depth * he->depth) + 96.0f * 96.0f) { + if (d < radius * radius) { Vector2 ret; ret.x = 1.0f; assert(diagram_vertex_heights.size() > he->a); @@ -315,7 +340,7 @@ Vector2 RoadGrid::get_influence(int x, int y) const float m1 = pt.distance_to(a) / l; float m2 = CLAMP(1.0f - m1, 0.0f, 1.0f); float h = h1 * (1.0f - m1) + h2 * (1.0f - m2); - ret.y = h - 0.5f; + ret.y = h - 2.5f; return ret; } } @@ -325,7 +350,7 @@ Vector2 RoadGrid::get_influence(int x, int y) const void RoadGrid::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_debug", "drawable", "size_x", "size_y"), &RoadGrid::draw_debug); - ClassDB::bind_method(D_METHOD("get_influence", "x", "y"), &RoadGrid::get_influence); + ClassDB::bind_method(D_METHOD("get_influence", "x", "y", "radius"), &RoadGrid::get_influence); ClassDB::bind_method(D_METHOD("build", "curve", "noise"), &RoadGrid::build); } diff --git a/modules/world/road_grid.h b/modules/world/road_grid.h index 906ac12..3204f99 100644 --- a/modules/world/road_grid.h +++ b/modules/world/road_grid.h @@ -190,7 +190,7 @@ protected: public: void build(Ref curve, Ref noise); void draw_debug(Node *drawable, int size_x, int size_y) const; - Vector2 get_influence(int x, int y) const; + Vector2 get_influence(int x, int y, float radius) const; RoadGrid(); ~RoadGrid(); }; diff --git a/modules/world/roads.cpp b/modules/world/roads.cpp index 040c1cc..280660a 100644 --- a/modules/world/roads.cpp +++ b/modules/world/roads.cpp @@ -614,10 +614,11 @@ float RoadsData::get_sdf(int x, int y, int z) if (!curve.is_valid() || !noise.is_valid()) return (float)y; float n = curve->interpolate_baked(0.5f + noise->get_noise_2d(x, z) * 0.5f); - Vector2 ifl = rg->get_influence(x, z); + n = CLAMP(n, -1000.0f, 1000.0f); + Vector2 ifl = rg->get_influence(x, z, 32.0f); if (ifl.x > 0.0f) { - if (n <= ifl.y + 2.0f) - return (float)y - ifl.y; + if (n <= ifl.y - 0.5f) + return (float)y - ifl.y - 0.6f; else return (float)y - ifl.y; } diff --git a/modules/world/world_generator.cpp b/modules/world/world_generator.cpp index 2885279..99b8acf 100644 --- a/modules/world/world_generator.cpp +++ b/modules/world/world_generator.cpp @@ -1,105 +1,24 @@ #include +#include +#include "roads.h" #include "world_map_data.h" #include "world_generator.h" WorldGenerator::WorldGenerator() { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - // Have one by default in editor - _noise.instance(); - _mount_noise.instance(); - } -#endif } -void WorldGenerator::set_noise(Ref noise) { - _noise = noise; -} - -Ref WorldGenerator::get_noise() const { - return _noise; -} - -void WorldGenerator::set_mount_noise(Ref noise) { - _mount_noise = noise; -} - -Ref WorldGenerator::get_mount_noise() const { - return _mount_noise; -} float WorldGenerator::height_func(int x, int y, int z) { - float mh = _noise->get_noise_2d((float)x * main_multiplier, (float)z * main_multiplier); - float mth = _mount_noise->get_noise_2d((float)x * mount_multiplier, (float)z * mount_multiplier); - float dmt = 15.0f; - float d1 = initial_spawn_radius + 33.5f * mth; - float h1 = initial_spawn_height + 0.03f * mth; - float d2 = d1 + 20.0f + 0.05 * mth; - float h2 = _range.start + 0.15f * mth; - Vector3 pos((float)x, (float)y, (float)z); - float d = pos.distance_squared_to(initial_spawn); - float factor = (d1 * d1 + 1.0f) / (d + 1.0f); - float th = (d < d1 * d1) ? h1 : h1 * factor + h2 * (1.0f - factor); - float fh = th; - float iheight = CLAMP(fh, _range.start, initial_spawn_height) / _range.height; - float oheight = (mh + mth * 0.01 + 0.1 * mth * CLAMP(y - mount_offset, 0.0f, dmt) / dmt); - float rt = CLAMP(d2 * d2 / (d + 1.0f), 0.0f, 1.0f); - return 0.5f + 0.5f * (iheight * rt + oheight * (1.0f - rt)); -} - -void WorldGenerator::set_mount_offset(float offt) -{ - mount_offset = offt; -} - -float WorldGenerator::get_mount_offset() const -{ - return mount_offset; -} - -void WorldGenerator::set_main_multiplier(float mult) -{ - main_multiplier = mult; -} - -float WorldGenerator::get_main_multiplier() const -{ - return main_multiplier; -} - -void WorldGenerator::set_initial_spawn_height(float height) -{ - initial_spawn_height = height; -} - -float WorldGenerator::get_initial_spawn_height() const -{ - return initial_spawn_height; -} - -void WorldGenerator::set_density_map(Ref map) -{ - density_map = map; -} - -Ref WorldGenerator::get_density_map() const -{ - return density_map; + float sdf = RoadsData::get_singleton()->get_sdf(x, y, z); + return sdf; } VoxelGenerator::Result WorldGenerator::generate_block(VoxelBlockRequest &input) { - ERR_FAIL_COND_V(_noise.is_null(), Result()); -#ifdef WORLD_MAP_TESTS - WorldMapData *wmd = WorldMapData::get_singleton(); - if (!wmd->tests_run) { - wmd->unit_test(); - wmd->tests_run = true; - } -#endif Result result; + real_t time_before = OS::get_singleton()->get_ticks_usec(), total; VoxelBufferInternal &out_buffer = input.voxel_buffer; result = WorldGenerator::generate( out_buffer, @@ -107,96 +26,19 @@ VoxelGenerator::Result WorldGenerator::generate_block(VoxelBlockRequest &input) input.origin_in_voxels, input.lod); out_buffer.compress_uniform_channels(); + total = OS::get_singleton()->get_ticks_usec() - time_before; + printf("generate_block: %f\n", total); return result; } void WorldGenerator::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_noise", "noise"), &WorldGenerator::set_noise); - ClassDB::bind_method(D_METHOD("get_noise"), &WorldGenerator::get_noise); - - ClassDB::bind_method(D_METHOD("set_mount_noise", "noise"), &WorldGenerator::set_mount_noise); - ClassDB::bind_method(D_METHOD("get_mount_noise"), &WorldGenerator::get_mount_noise); - - ClassDB::bind_method(D_METHOD("set_channel", "channel"), &WorldGenerator::set_channel); - ClassDB::bind_method(D_METHOD("get_channel"), &WorldGenerator::get_channel); - - ClassDB::bind_method(D_METHOD("set_height_start", "start"), &WorldGenerator::set_height_start); - ClassDB::bind_method(D_METHOD("get_height_start"), &WorldGenerator::get_height_start); - - ClassDB::bind_method(D_METHOD("set_mount_offset", "offt"), &WorldGenerator::set_mount_offset); - ClassDB::bind_method(D_METHOD("get_mount_offset"), &WorldGenerator::get_mount_offset); - - ClassDB::bind_method(D_METHOD("set_main_multiplier", "mult"), &WorldGenerator::set_main_multiplier); - ClassDB::bind_method(D_METHOD("get_main_multiplier"), &WorldGenerator::get_main_multiplier); - - ClassDB::bind_method(D_METHOD("set_initial_spawn_height", "height"), &WorldGenerator::set_initial_spawn_height); - ClassDB::bind_method(D_METHOD("get_initial_spawn_height"), &WorldGenerator::get_initial_spawn_height); - - ClassDB::bind_method(D_METHOD("set_initial_spawn_radius", "radius"), &WorldGenerator::set_initial_spawn_radius); - ClassDB::bind_method(D_METHOD("get_initial_spawn_radius"), &WorldGenerator::get_initial_spawn_radius); - - ClassDB::bind_method(D_METHOD("set_height_range", "range"), &WorldGenerator::set_height_range); - ClassDB::bind_method(D_METHOD("get_height_range"), &WorldGenerator::get_height_range); - ClassDB::bind_method(D_METHOD("set_iso_scale", "scale"), &WorldGenerator::set_iso_scale); ClassDB::bind_method(D_METHOD("get_iso_scale"), &WorldGenerator::get_iso_scale); - - ClassDB::bind_method(D_METHOD("set_density_map", "density_map"), &WorldGenerator::set_density_map); - ClassDB::bind_method(D_METHOD("get_density_map"), &WorldGenerator::get_density_map); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mount_noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_mount_noise", "get_mount_noise"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "mount_offset"), "set_mount_offset", "get_mount_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "main_multiplier"), "set_main_multiplier", "get_main_multiplier"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "initial_spawn_height"), "set_initial_spawn_height", "get_initial_spawn_height"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "initial_spawn_radius"), "set_initial_spawn_radius", "get_initial_spawn_radius"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "channel", PROPERTY_HINT_ENUM, VoxelBuffer::CHANNEL_ID_HINT_STRING), "set_channel", "get_channel"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height_start"), "set_height_start", "get_height_start"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height_range"), "set_height_range", "get_height_range"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "density_map", PROPERTY_HINT_RESOURCE_TYPE, "DensityMap"), "set_density_map", "get_density_map"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "iso_scale"), "set_iso_scale", "get_iso_scale"); } -void WorldGenerator::set_channel(VoxelBuffer::ChannelId channel) { - ERR_FAIL_INDEX(channel, VoxelBuffer::MAX_CHANNELS); - if (_channel != channel) { - _channel = channel; - emit_changed(); - } -} - -VoxelBuffer::ChannelId WorldGenerator::get_channel() const { - return _channel; -} int WorldGenerator::get_used_channels_mask() const { - return (1 << _channel); -} - -void WorldGenerator::set_height_start(float start) { - _range.start = start; -} - -float WorldGenerator::get_height_start() const { - return _range.start; -} - -void WorldGenerator::set_height_range(float range) { - _range.height = range; -} - -float WorldGenerator::get_height_range() const { - return _range.height; -} - -void WorldGenerator::set_initial_spawn_radius(float radius) -{ - initial_spawn_radius = radius; -} - -float WorldGenerator::get_initial_spawn_radius() const -{ - return initial_spawn_radius; + return (1 << VoxelBuffer::CHANNEL_SDF); } void WorldGenerator::set_iso_scale(float iso_scale) { diff --git a/modules/world/world_generator.h b/modules/world/world_generator.h index 468f5ed..ba13511 100644 --- a/modules/world/world_generator.h +++ b/modules/world/world_generator.h @@ -2,9 +2,6 @@ #define VOXEL_GENERATOR_NOISE_2D_H #include -#include - -#include "density_map.h" class WorldGenerator : public VoxelGenerator { GDCLASS(WorldGenerator, VoxelGenerator) @@ -12,38 +9,10 @@ class WorldGenerator : public VoxelGenerator { public: WorldGenerator(); - void set_noise(Ref noise); - Ref get_noise() const; - - void set_mount_noise(Ref noise); - Ref get_mount_noise() const; - - void set_channel(VoxelBuffer::ChannelId channel); - VoxelBuffer::ChannelId get_channel() const; int get_used_channels_mask() const override; - void set_height_start(float start); - float get_height_start() const; - - void set_height_range(float range); - float get_height_range() const; - - void set_mount_offset(float offt); - float get_mount_offset() const; - - void set_main_multiplier(float mult); - float get_main_multiplier() const; - - void set_initial_spawn_height(float height); - float get_initial_spawn_height() const; - - void set_initial_spawn_radius(float radius); - float get_initial_spawn_radius() const; - void set_iso_scale(float iso_scale); float get_iso_scale() const; - void set_density_map(Ref map); - Ref get_density_map() const; Result generate_block(VoxelBlockRequest &input) override; float height_func(int x, int y, int z); @@ -54,94 +23,47 @@ protected: template Result generate(VoxelBufferInternal &out_buffer, Height_F height_func, Vector3i origin, int lod) { - const int channel = _channel; + const int channel = VoxelBuffer::CHANNEL_SDF; const Vector3i bs = out_buffer.get_size(); - bool use_sdf = channel == VoxelBuffer::CHANNEL_SDF; - if (origin.y > get_height_start() + get_height_range()) { + /* TODO: get via RoadsData */ + if (origin.y > 300.0f) { // The bottom of the block is above the highest ground can go (default is air) Result result; result.max_lod_hint = true; return result; } - if (origin.y + (bs.y << lod) < get_height_start()) { + if (origin.y + (bs.y << lod) < -1000.0f) { // The top of the block is below the lowest ground can go - out_buffer.clear_channel(_channel, use_sdf ? 0 : _matter_type); + out_buffer.clear_channel(channel, 0); Result result; result.max_lod_hint = true; return result; } const int stride = 1 << lod; + int gz = origin.z; + for (int z = 0; z < bs.z; ++z, gz += stride) { - if (use_sdf) { + int gx = origin.x; + for (int x = 0; x < bs.x; ++x, gx += stride) { - int gz = origin.z; - for (int z = 0; z < bs.z; ++z, gz += stride) { + int gy = origin.y; + for (int y = 0; y < bs.y; ++y, gy += stride) { + float sdf = height_func(gx, gy, gz); + out_buffer.set_voxel_f(sdf * _iso_scale, x, y, z, channel); + } - int gx = origin.x; - for (int x = 0; x < bs.x; ++x, gx += stride) { + } // for x + } // for z - int gy = origin.y; - for (int y = 0; y < bs.y; ++y, gy += stride) { - float h = _range.xform(height_func(gx, gy, gz)); - float sdf = _iso_scale * (gy - h); - out_buffer.set_voxel_f(sdf, x, y, z, channel); - } - - } // for x - } // for z - - } else { - // Blocky - - int gz = origin.z; - for (int z = 0; z < bs.z; ++z, gz += stride) { - - int gx = origin.x; - for (int x = 0; x < bs.x; ++x, gx += stride) { - - // Output is blocky, so we can go for just one sample - float h = _range.xform(height_func(gx, origin.y, gz)); - h -= origin.y; - int ih = int(h); - if (ih > 0) { - if (ih > bs.y) { - ih = bs.y; - } - out_buffer.fill_area(_matter_type, Vector3i(x, 0, z), Vector3i(x + 1, ih, z + 1), channel); - } - - } // for x - } // for z - } // use_sdf return Result(); } private: - Ref _noise, _mount_noise; - - struct Range { - float start = -250; - float height = 500; - - inline float xform(float x) const { - return x * height + start; - } - }; - float mount_offset = 50.0f; - float main_multiplier = 0.1f; - Vector3 initial_spawn; - float initial_spawn_radius = 150.0f; - float initial_spawn_height = 20.0f; - - VoxelBuffer::ChannelId _channel = VoxelBuffer::CHANNEL_SDF; int _matter_type = 1; - Range _range; float _iso_scale = 0.1; - float mount_multiplier = 1.5f; - Ref density_map; }; #endif // VOXEL_GENERATOR_NOISE_2D_H