summaryrefslogtreecommitdiff
path: root/scene/resources/curve.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/curve.cpp')
-rw-r--r--scene/resources/curve.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 4ec1e8973d..7f902fc982 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -1169,6 +1169,7 @@ void Curve3D::_bake() const {
if (points.size() == 0) {
baked_point_cache.resize(0);
baked_tilt_cache.resize(0);
+ baked_up_vector_cache.resize(0);
return;
}
@@ -1178,6 +1179,14 @@ void Curve3D::_bake() const {
baked_point_cache.set(0, points[0].pos);
baked_tilt_cache.resize(1);
baked_tilt_cache.set(0, points[0].tilt);
+
+ if (up_vector_enabled) {
+
+ baked_up_vector_cache.resize(1);
+ baked_up_vector_cache.set(0, Vector3(0, 1, 0));
+ } else
+ baked_up_vector_cache.resize(0);
+
return;
}
@@ -1247,10 +1256,51 @@ void Curve3D::_bake() const {
baked_tilt_cache.resize(pointlist.size());
PoolRealArray::Write wt = baked_tilt_cache.write();
+ baked_up_vector_cache.resize(up_vector_enabled ? pointlist.size() : 0);
+ PoolVector3Array::Write up_write = baked_up_vector_cache.write();
+
+ Vector3 sideways;
+ Vector3 up;
+ Vector3 forward;
+
+ Vector3 prev_sideways = Vector3(1, 0, 0);
+ Vector3 prev_up = Vector3(0, 1, 0);
+ Vector3 prev_forward = Vector3(0, 0, 1);
+
for (List<Plane>::Element *E = pointlist.front(); E; E = E->next()) {
w[idx] = E->get().normal;
wt[idx] = E->get().d;
+
+ if (!up_vector_enabled) {
+ idx++;
+ continue;
+ }
+
+ forward = idx > 0 ? (w[idx] - w[idx - 1]).normalized() : prev_forward;
+
+ float y_dot = prev_up.dot(forward);
+
+ if (y_dot > (1.0f - CMP_EPSILON)) {
+ sideways = prev_sideways;
+ up = -prev_forward;
+ } else if (y_dot < -(1.0f - CMP_EPSILON)) {
+ sideways = prev_sideways;
+ up = prev_forward;
+ } else {
+ sideways = prev_up.cross(forward).normalized();
+ up = forward.cross(sideways).normalized();
+ }
+
+ if (idx == 1)
+ up_write[0] = up;
+
+ up_write[idx] = up;
+
+ prev_sideways = sideways;
+ prev_up = up;
+ prev_forward = forward;
+
idx++;
}
}
@@ -1343,6 +1393,53 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const {
return Math::lerp(r[idx], r[idx + 1], frac);
}
+Vector3 Curve3D::interpolate_baked_up_vector(float p_offset, bool p_apply_tilt) const {
+
+ if (baked_cache_dirty)
+ _bake();
+
+ //validate//
+ // curve may not have baked up vectors
+ int count = baked_up_vector_cache.size();
+ if (count == 0) {
+ ERR_EXPLAIN("No up vectors in Curve3D");
+ ERR_FAIL_COND_V(count == 0, Vector3(0, 1, 0));
+ }
+
+ if (count == 1)
+ return baked_up_vector_cache.get(0);
+
+ PoolVector3Array::Read r = baked_up_vector_cache.read();
+ PoolVector3Array::Read rp = baked_point_cache.read();
+ PoolRealArray::Read rt = baked_tilt_cache.read();
+
+ float offset = CLAMP(p_offset, 0.0f, baked_max_ofs);
+
+ int idx = Math::floor((double)offset / (double)bake_interval);
+ float frac = Math::fmod(offset, bake_interval) / bake_interval;
+
+ if (idx == count - 1)
+ return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
+
+ Vector3 forward = (rp[idx + 1] - rp[idx]).normalized();
+ Vector3 up = r[idx];
+ Vector3 up1 = r[idx + 1];
+
+ if (p_apply_tilt) {
+ up.rotate(forward, rt[idx]);
+ up1.rotate(idx + 2 >= count ? forward : (rp[idx + 2] - rp[idx + 1]).normalized(), rt[idx + 1]);
+ }
+
+ Vector3 axis = up.cross(up1);
+
+ if (axis.length_squared() < CMP_EPSILON2)
+ axis = forward;
+ else
+ axis.normalize();
+
+ return up.rotated(axis, up.angle_to(up1) * frac);
+}
+
PoolVector3Array Curve3D::get_baked_points() const {
if (baked_cache_dirty)
@@ -1359,6 +1456,14 @@ PoolRealArray Curve3D::get_baked_tilts() const {
return baked_tilt_cache;
}
+PoolVector3Array Curve3D::get_baked_up_vectors() const {
+
+ if (baked_cache_dirty)
+ _bake();
+
+ return baked_up_vector_cache;
+}
+
Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
// Brute force method
@@ -1452,6 +1557,18 @@ float Curve3D::get_bake_interval() const {
return bake_interval;
}
+void Curve3D::set_up_vector_enabled(bool p_enable) {
+
+ up_vector_enabled = p_enable;
+ baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+bool Curve3D::is_up_vector_enabled() const {
+
+ return up_vector_enabled;
+}
+
Dictionary Curve3D::_get_data() const {
Dictionary dc;
@@ -1563,11 +1680,15 @@ void Curve3D::_bind_methods() {
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
+ ClassDB::bind_method(D_METHOD("set_up_vector_enabled", "enable"), &Curve3D::set_up_vector_enabled);
+ ClassDB::bind_method(D_METHOD("is_up_vector_enabled"), &Curve3D::is_up_vector_enabled);
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length);
ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("interpolate_baked_up_vector", "offset", "apply_tilt"), &Curve3D::interpolate_baked_up_vector, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts);
+ ClassDB::bind_method(D_METHOD("get_baked_up_vectors"), &Curve3D::get_baked_up_vectors);
ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve3D::get_closest_point);
ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve3D::get_closest_offset);
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4));
@@ -1577,6 +1698,9 @@ void Curve3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
+
+ ADD_GROUP("Up Vector", "up_vector_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled");
}
Curve3D::Curve3D() {
@@ -1586,4 +1710,5 @@ Curve3D::Curve3D() {
add_point(Vector3(0,2,0));
add_point(Vector3(0,3,5));*/
bake_interval = 0.2;
+ up_vector_enabled = true;
}