feat: improved path modifier mesh generation

This commit is contained in:
Sara Gerretsen 2026-02-27 23:06:06 +01:00
parent 31a9986066
commit 73ddf09b98
2 changed files with 38 additions and 24 deletions

View file

@ -262,21 +262,23 @@ void TerrainModifierPath::_notification(int what) {
}
}
float TerrainModifierPath::evaluate_line(Vector3 a, Vector3 b, 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) {
Vector2 a2{ a.x, a.z }, b2{ b.x, b.z };
Vector2 const relative_coordinate{ world_coordinate - a2 };
Vector2 const difference2{ b2 - a2 };
float const w{ difference2.normalized().dot(relative_coordinate) / difference2.length() };
float w{ difference2.normalized().dot(relative_coordinate) / difference2.length() };
Vector3 const difference{ b - a };
Vector3 const closest_on_line{ a + difference * (w > 0 ? (w < 1 ? w : 1) : 0) };
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.y > b.y) {
return a.y + (b.y - a.y) * (w > 0 ? w : 0);
} else {
return a.y + (b.y - a.y) * (w < 1 ? w : 1);
if (a_end) {
w = w > 0 ? w : 0;
}
if (b_end) {
w = w < 1 ? w : 1;
}
return a.y + (b.y - a.y) * w;
}
float TerrainModifierPath::evaluate_at(Vector2 world_coordinate, float before) {
@ -285,23 +287,26 @@ 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 };
for (int i{ 0 }; i < this->points.size(); i++) {
if (this->closed || i < this->points.size() - 1) {
float dot, distance;
float height{ evaluate_line(this->points[i], this->points[Math::wrapi(i + 1, 0, this->points.size())], world_coordinate, dot, distance) };
float left{ this->curve_left->sample(distance) };
float right{ this->curve_right->sample(distance) };
float ndot{ dot / distance };
float separation{ ndot / 2.f + 0.5f };
float weight{ left * (1 - separation) + right * separation };
float blended_height{ Math::lerp(before, height, weight) };
float score{ weight - (Math::abs(ndot) == 1) * 100000.f };
if (score > out_score) {
out_score = score;
out_height = blended_height;
}
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) };
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)) {
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;
}
}
this->lock.unlock_shared();
@ -311,11 +316,20 @@ float TerrainModifierPath::evaluate_at(Vector2 world_coordinate, float before) {
void TerrainModifierPath::path_changed() {
this->lock.lock_exclusive();
this->points.clear();
this->min_height = INFINITY;
this->max_height = -INFINITY;
Vector3 last{ INFINITY, INFINITY, INFINITY };
for (Variant var : get_children()) {
if (TerrainModifierPathPoint * point{ cast_to<TerrainModifierPathPoint>(var) }) {
if (var != last) {
this->points.push_back(point->get_global_position());
Vector3 position{ point->get_global_position() };
if (position != last) {
this->points.push_back(position);
if (position.y > this->max_height) {
this->max_height = position.y;
}
if (position.y < this->min_height) {
this->min_height = position.y;
}
}
}
last = var;

View file

@ -86,7 +86,7 @@ class TerrainModifierPath : public TerrainModifier {
protected:
void _notification(int what);
float evaluate_line(Vector3 a, Vector3 b, 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);
public:
float evaluate_at(Vector2 world_coordinate, float before) override;