feat: WIP improved turns on path modifier

This commit is contained in:
Sara Gerretsen 2026-03-01 23:01:08 +01:00
parent f057254396
commit 9ea66df220
3 changed files with 46 additions and 27 deletions

View file

@ -262,7 +262,7 @@ void TerrainModifierPath::_notification(int what) {
} }
} }
float TerrainModifierPath::evaluate_line(Vector3 a, bool a_end, Vector3 b, bool b_end, Vector2 world_coordinate, float &out_dot, float &out_distance) { float TerrainModifierPath::evaluate_line(Vector3 a, bool a_end, Vector3 b, bool b_end, Vector2 world_coordinate, float &out_dot, float &out_distance, float &out_percentage) {
Vector2 a2{ a.x, a.z }, b2{ b.x, b.z }; Vector2 a2{ a.x, a.z }, b2{ b.x, b.z };
Vector2 const relative_coordinate{ world_coordinate - a2 }; Vector2 const relative_coordinate{ world_coordinate - a2 };
Vector2 const difference2{ b2 - a2 }; Vector2 const difference2{ b2 - a2 };
@ -272,10 +272,11 @@ float TerrainModifierPath::evaluate_line(Vector3 a, bool a_end, Vector3 b, bool
Vector2 const right{ -difference.z, difference.x }; Vector2 const right{ -difference.z, difference.x };
out_dot = right.normalized().dot(relative_coordinate); out_dot = right.normalized().dot(relative_coordinate);
out_distance = world_coordinate.distance_to({ closest_on_line.x, closest_on_line.z }); out_distance = world_coordinate.distance_to({ closest_on_line.x, closest_on_line.z });
if (a_end) { out_percentage = w;
if (!a_end) {
w = w > 0 ? w : 0; w = w > 0 ? w : 0;
} }
if (b_end) { if (!b_end) {
w = w < 1 ? w : 1; w = w < 1 ? w : 1;
} }
return a.y + (b.y - a.y) * w; return a.y + (b.y - a.y) * w;
@ -287,30 +288,45 @@ float TerrainModifierPath::evaluate_at(Vector2 world_coordinate, float before) {
this->lock.unlock_shared(); this->lock.unlock_shared();
return before; return before;
} }
float const max_distance{ this->curve_left->get_max_domain() > this->curve_right->get_max_domain() ? this->curve_left->get_max_domain() : this->curve_right->get_max_domain() }; float out_score{ 0.f };
float out_score{ -INFINITY }; float out_delta{ 0.f };
float out_height{ 0 };
long const count{ this->closed ? this->points.size() : this->points.size() - 1 }; long const count{ this->closed ? this->points.size() : this->points.size() - 1 };
for (int i{ 0 }; i < count; i++) { for (int i{ 0 }; i < count; i++) {
float dot, distance; Vector3 const ipos{ this->points[i] };
float const height{ evaluate_line(this->points[i], !this->closed && i == 0, this->points[Math::wrapi(i + 1, 0, this->points.size())], !this->closed && i == count - 1, world_coordinate, dot, distance) }; float dot, distance, percentage;
bool const is_start{ !this->closed && i == 0 }, is_end{ !this->closed && i == count - 1 };
float const height{ evaluate_line(ipos, is_start, this->points[Math::wrapi(i + 1, 0, this->points.size())], is_end, world_coordinate, dot, distance, percentage) };
float const left{ this->curve_left->sample(distance) }; float const left{ this->curve_left->sample(distance) };
float const right{ this->curve_right->sample(distance) }; float const right{ this->curve_right->sample(distance) };
float const ndot{ dot / distance }; float const ndot{ dot / distance };
float separation{ ndot / 2.f + 0.5f }; float separation{ ndot / 2.f + 0.5f };
if (closed || (i > 0 && i < count - 1)) { float turn{ ndot };
Vector3 const right_direction{ (this->points[Math::wrapi(i + 1, 0, this->points.size())] - ipos).cross({ 0, 1, 0 }) };
if (!is_end && percentage >= 1.f) {
turn = (this->points[Math::wrapi(i + 2, 0, this->points.size())] - ipos).dot(right_direction);
separation = turn <= 0 ? 0 : 1;
} else if (!is_start && percentage <= 0.f) {
turn = (this->points[Math::wrapi(i - 1, 0, this->points.size())] - ipos).dot(right_direction);
separation = turn <= 0 ? 0 : 1;
} else if (!is_start && !is_end) {
separation = Math::round(separation); separation = Math::round(separation);
} }
float const weight{ left * (1 - separation) + right * separation }; if (turn / turn == dot / dot) {
float const blended_height{ Math::lerp(before, height, weight) }; float const weight{ left * (1 - separation) + right * separation };
float const score{ weight - (1 - Math::abs(ndot)) * 2.f - (distance / max_distance) }; float const blended_height{ Math::lerp(before, height, weight) };
if (score > out_score) { float const delta{ blended_height - before };
out_score = score; float const score{ weight };
out_height = blended_height; if (score > out_score) {
out_score = score;
out_delta = delta * score;
}
} }
} }
this->lock.unlock_shared(); this->lock.unlock_shared();
return out_height; if (out_score == 0.f) {
return before;
}
return before + (out_delta / out_score);
} }
void TerrainModifierPath::path_changed() { void TerrainModifierPath::path_changed() {

View file

@ -86,7 +86,7 @@ class TerrainModifierPath : public TerrainModifier {
protected: protected:
void _notification(int what); void _notification(int what);
float evaluate_line(Vector3 a, bool a_end, Vector3 b, bool b_end, Vector2 world_coordinate, float &out_dot, float &out_distance); float evaluate_line(Vector3 a, bool a_end, Vector3 b, bool b_end, Vector2 world_coordinate, float &out_dot, float &out_distance, float &out_percentage);
public: public:
float evaluate_at(Vector2 world_coordinate, float before) override; float evaluate_at(Vector2 world_coordinate, float before) override;

View file

@ -14,8 +14,8 @@ sky = SubResource("Sky_w3uoq")
[sub_resource type="Curve" id="Curve_kbmr5"] [sub_resource type="Curve" id="Curve_kbmr5"]
_limits = [0.0, 1.0, 0.0, 100.0] _limits = [0.0, 1.0, 0.0, 100.0]
_data = [Vector2(0, 1), 0.0, -0.0015643721, 0, 0, Vector2(60.370926, 0.60930693), -0.018071167, -0.018071167, 0, 0, Vector2(100, 0), 0.0, 0.0, 0, 0] _data = [Vector2(0, 1), 0.0, -0.030682996, 0, 0, Vector2(100, 0), 0.0, 0.0, 0, 0]
point_count = 3 point_count = 2
[sub_resource type="Curve" id="Curve_w3uoq"] [sub_resource type="Curve" id="Curve_w3uoq"]
_limits = [0.0, 1.0, 0.0, 101.07341] _limits = [0.0, 1.0, 0.0, 101.07341]
@ -40,30 +40,33 @@ chunk_size = 100
thread_count = 5 thread_count = 5
[node name="TerrainModifierPath" type="TerrainModifierPath" parent="Terrain" unique_id=462259542] [node name="TerrainModifierPath" type="TerrainModifierPath" parent="Terrain" unique_id=462259542]
transform = Transform3D(2.7896824, 0, 0, 0, 1, 0, 0, 0, 3.9856973, 188.70874, 151.32993, 528.5824) transform = Transform3D(1.9138145, 0, 0, 0, 0.6860331, 0, 0, 0, 2.7343204, 190.712, 125.888245, 634.1432)
curve_left = SubResource("Curve_kbmr5") curve_left = SubResource("Curve_kbmr5")
curve_right = SubResource("Curve_w3uoq") curve_right = SubResource("Curve_w3uoq")
[node name="TerrainModifierPathPoint" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=1975236067] [node name="TerrainModifierPathPoint" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=1975236067]
transform = Transform3D(0.9999999, 0, 0, 0, 1, 0, 0, 0, 0.9999999, -6.678116, -33.99875, -74.15768) transform = Transform3D(0.9999999, 0, 0, 0, 1, 0, 0, 0, 0.99999976, -5.4521523, -33.998764, -98.341095)
[node name="TerrainModifierPathPoint5" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=2007122252] [node name="TerrainModifierPathPoint5" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=2007122252]
transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 41.63815, 4.6532288, -38.86402) transform = Transform3D(0.9999999, 0, 0, 0, 1, 0, 0, 0, 0.9999999, 33.986214, 4.6532135, -47.78543)
[node name="TerrainModifierPathPoint2" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=88875414] [node name="TerrainModifierPathPoint2" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=88875414]
transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 4.2666435, -27.249336, 5.506424) transform = Transform3D(0.9999999, 0, 0, 0, 1, 0, 0, 0, 0.9999999, -45.605103, -77.62694, -7.8362274)
[node name="TerrainModifierPathPoint3" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=910243114] [node name="TerrainModifierPathPoint3" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=910243114]
transform = Transform3D(-0.08673841, 0, 0.9962309, 0, 1, 0, -0.9962308, 0, -0.08673839, 77.83667, 84.083954, 12.383522) transform = Transform3D(-0.08673841, 0, 0.9962309, 0, 1, 0, -0.99623066, 0, -0.0867384, 51.146767, 185.18083, 46.93416)
[node name="TerrainModifierPathPoint4" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=738726374] [node name="TerrainModifierPathPoint4" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=738726374]
transform = Transform3D(-0.08673839, 0, 0.9962309, 0, 1, 0, -0.9962308, 0, -0.08673841, 124.05687, -50.373947, -21.531578) transform = Transform3D(-0.5568029, 0, 0.8306443, 0, 1, 0, -0.83064425, 0, -0.556803, 181.23196, -50.373947, -56.57155)
[node name="TerrainModifierPathPoint6" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=868243973] [node name="TerrainModifierPathPoint6" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=868243973]
transform = Transform3D(-0.08673839, 0, 0.9962309, 0, 1, 0, -0.99623066, 0, -0.08673841, 163.78015, -50.373917, 24.09636) transform = Transform3D(-0.5568028, 0, 0.8306443, 0, 1, 0, -0.830644, 0, -0.55680287, 206.74478, -50.373917, 13.438446)
[node name="TerrainModifierPathPoint7" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=601656436] [node name="TerrainModifierPathPoint7" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=601656436]
transform = Transform3D(-0.08673839, 0, 0.9962309, 0, 1, 0, -0.99623054, 0, -0.08673841, 106.59272, 12.878235, 75.88286) transform = Transform3D(-0.5568028, 0, 0.8306443, 0, 1, 0, -0.8306439, 0, -0.55680287, 192.3706, 12.87825, 78.11276)
[node name="TerrainModifierPathPoint8" type="TerrainModifierPathPoint" parent="Terrain/TerrainModifierPath" unique_id=300006660]
transform = Transform3D(-0.5568028, 0, 0.8306443, 0, 1, 0, -0.8306439, 0, -0.55680287, 289.17203, 36.37845, 54.197342)
[node name="TerrainModifierDistance8" type="TerrainModifierDistance" parent="Terrain" unique_id=1993490768] [node name="TerrainModifierDistance8" type="TerrainModifierDistance" parent="Terrain" unique_id=1993490768]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 784.91595, 251.11382, 135.92102) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 784.91595, 251.11382, 135.92102)