feat: improved path modifier mesh generation
This commit is contained in:
parent
31a9986066
commit
73ddf09b98
2 changed files with 38 additions and 24 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue