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 const relative_coordinate{ world_coordinate - 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 };
out_dot = right.normalized().dot(relative_coordinate);
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;
}
if (b_end) {
if (!b_end) {
w = w < 1 ? w : 1;
}
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();
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{ -INFINITY };
float out_height{ 0 };
float out_score{ 0.f };
float out_delta{ 0.f };
long const count{ this->closed ? this->points.size() : this->points.size() - 1 };
for (int i{ 0 }; i < count; i++) {
float dot, distance;
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) };
Vector3 const ipos{ this->points[i] };
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 right{ this->curve_right->sample(distance) };
float const ndot{ dot / distance };
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);
}
float const weight{ left * (1 - separation) + right * separation };
float const blended_height{ Math::lerp(before, height, weight) };
float const score{ weight - (1 - Math::abs(ndot)) * 2.f - (distance / max_distance) };
if (score > out_score) {
out_score = score;
out_height = blended_height;
if (turn / turn == dot / dot) {
float const weight{ left * (1 - separation) + right * separation };
float const blended_height{ Math::lerp(before, height, weight) };
float const delta{ blended_height - before };
float const score{ weight };
if (score > out_score) {
out_score = score;
out_delta = delta * score;
}
}
}
this->lock.unlock_shared();
return out_height;
if (out_score == 0.f) {
return before;
}
return before + (out_delta / out_score);
}
void TerrainModifierPath::path_changed() {

View file

@ -86,7 +86,7 @@ class TerrainModifierPath : public TerrainModifier {
protected:
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:
float evaluate_at(Vector2 world_coordinate, float before) override;