|
22 | 22 | Dictionary Terrain3DCollision::_get_shape_data(const Vector2i &p_position, const int p_size) { |
23 | 23 | IS_DATA_INIT_MESG("Terrain not initialized", Dictionary()); |
24 | 24 | const Terrain3DData *data = _terrain->get_data(); |
| 25 | + |
| 26 | + Ref<Terrain3DMaterial> material = _terrain->get_material(); |
| 27 | + bool is_flat_mode = material->get_world_background() == Terrain3DMaterial::WorldBackground::FLAT; |
| 28 | + const real_t ground_level = material->get("ground_level"); |
| 29 | + const real_t region_blend = material->get("region_blend"); |
| 30 | + const int region_map_size = Terrain3DData::REGION_MAP_SIZE; |
| 31 | + const PackedInt32Array region_map = data->get_region_map(); |
25 | 32 | int region_size = _terrain->get_region_size(); |
| 33 | + const real_t region_texel_size = 1.f / real_t(region_size); |
| 34 | + |
| 35 | + auto check_region = [&](const Vector2 &uv2) -> float { |
| 36 | + Vector2i pos = Vector2i(Math::floor(uv2.x), Math::floor(uv2.y)) + Vector2i(region_map_size / 2, region_map_size / 2); |
| 37 | + int layer_index = 0; |
| 38 | + if ((uint32_t)(pos.x | pos.y) < (uint32_t)region_map_size) { |
| 39 | + int v = region_map[pos.y * region_map_size + pos.x]; |
| 40 | + layer_index = Math::clamp(v - 1, -1, 0) + 1; |
| 41 | + } |
| 42 | + return real_t(layer_index); |
| 43 | + }; |
| 44 | + |
| 45 | + auto get_region_blend = [&](Vector2 uv2) -> float { |
| 46 | + // Floating point bias (must match shader) |
| 47 | + uv2 -= Vector2(0.5011f, 0.5011f); |
| 48 | + |
| 49 | + float a = check_region(uv2 + Vector2(0.0f, 1.0f)); |
| 50 | + float b = check_region(uv2 + Vector2(1.0f, 1.0f)); |
| 51 | + float c = check_region(uv2 + Vector2(1.0f, 0.0f)); |
| 52 | + float d = check_region(uv2 + Vector2(0.0f, 0.0f)); |
| 53 | + |
| 54 | + Vector2 blend_factor(2.0f + 126.0f * (1.0f - region_blend), 2.0f + 126.0f * (1.0f - region_blend)); |
| 55 | + Vector2 f(uv2.x - Math::floor(uv2.x), uv2.y - Math::floor(uv2.y)); |
| 56 | + Vector2 w(1.f / (1.f + Math::exp(blend_factor.x * Math::log((1.f - f.x) / f.x))), |
| 57 | + 1.f / (1.f + Math::exp(blend_factor.y * Math::log((1.f - f.y) / f.y)))); |
| 58 | + float blend = mix(mix(d, c, w.x), mix(a, b, w.x), w.y); |
| 59 | + |
| 60 | + return (1.f - blend) * 2.f; |
| 61 | + }; |
26 | 62 |
|
27 | 63 | int hshape_size = p_size + 1; // Calculate last vertex at end |
28 | 64 | PackedRealArray map_data = PackedRealArray(); |
@@ -99,6 +135,10 @@ Dictionary Terrain3DCollision::_get_shape_data(const Vector2i &p_position, const |
99 | 135 | height = (is_hole(cmap->get_pixel(region_size - 1, region_size - 1).r)) ? NAN : map->get_pixel(region_size - 1, region_size - 1).r; |
100 | 136 | } |
101 | 137 | } |
| 138 | + if (is_flat_mode) { |
| 139 | + Vector2 uv2 = Vector2(shape_pos) * region_texel_size; |
| 140 | + height = mix(height, ground_level, smoothstep(0.f, 1.f, get_region_blend(uv2))); |
| 141 | + } |
102 | 142 | map_data[index] = height; |
103 | 143 | if (!std::isnan(height)) { |
104 | 144 | min_height = MIN(min_height, height); |
|
0 commit comments