Skip to content

Commit 4f04ede

Browse files
committed
Implement flat mode blending collision matching
1 parent cd944a4 commit 4f04ede

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

src/terrain_3d_collision.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,43 @@
2222
Dictionary Terrain3DCollision::_get_shape_data(const Vector2i &p_position, const int p_size) {
2323
IS_DATA_INIT_MESG("Terrain not initialized", Dictionary());
2424
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();
2532
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+
};
2662

2763
int hshape_size = p_size + 1; // Calculate last vertex at end
2864
PackedRealArray map_data = PackedRealArray();
@@ -99,6 +135,10 @@ Dictionary Terrain3DCollision::_get_shape_data(const Vector2i &p_position, const
99135
height = (is_hole(cmap->get_pixel(region_size - 1, region_size - 1).r)) ? NAN : map->get_pixel(region_size - 1, region_size - 1).r;
100136
}
101137
}
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+
}
102142
map_data[index] = height;
103143
if (!std::isnan(height)) {
104144
min_height = MIN(min_height, height);

0 commit comments

Comments
 (0)