|
@@ -1169,6 +1169,7 @@ void Curve3D::_bake() const {
|
|
if (points.size() == 0) {
|
|
if (points.size() == 0) {
|
|
baked_point_cache.resize(0);
|
|
baked_point_cache.resize(0);
|
|
baked_tilt_cache.resize(0);
|
|
baked_tilt_cache.resize(0);
|
|
|
|
+ baked_up_vector_cache.resize(0);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1178,6 +1179,14 @@ void Curve3D::_bake() const {
|
|
baked_point_cache.set(0, points[0].pos);
|
|
baked_point_cache.set(0, points[0].pos);
|
|
baked_tilt_cache.resize(1);
|
|
baked_tilt_cache.resize(1);
|
|
baked_tilt_cache.set(0, points[0].tilt);
|
|
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;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1247,10 +1256,51 @@ void Curve3D::_bake() const {
|
|
baked_tilt_cache.resize(pointlist.size());
|
|
baked_tilt_cache.resize(pointlist.size());
|
|
PoolRealArray::Write wt = baked_tilt_cache.write();
|
|
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()) {
|
|
for (List<Plane>::Element *E = pointlist.front(); E; E = E->next()) {
|
|
|
|
|
|
w[idx] = E->get().normal;
|
|
w[idx] = E->get().normal;
|
|
wt[idx] = E->get().d;
|
|
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++;
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1343,6 +1393,53 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const {
|
|
return Math::lerp(r[idx], r[idx + 1], frac);
|
|
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 {
|
|
PoolVector3Array Curve3D::get_baked_points() const {
|
|
|
|
|
|
if (baked_cache_dirty)
|
|
if (baked_cache_dirty)
|
|
@@ -1359,6 +1456,14 @@ PoolRealArray Curve3D::get_baked_tilts() const {
|
|
return baked_tilt_cache;
|
|
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 {
|
|
Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
|
|
// Brute force method
|
|
// Brute force method
|
|
|
|
|
|
@@ -1452,6 +1557,18 @@ float Curve3D::get_bake_interval() const {
|
|
return bake_interval;
|
|
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 Curve3D::_get_data() const {
|
|
|
|
|
|
Dictionary dc;
|
|
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("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
|
|
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
|
|
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("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("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", "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_points"), &Curve3D::get_baked_points);
|
|
ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts);
|
|
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_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("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));
|
|
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::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_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() {
|
|
Curve3D::Curve3D() {
|
|
@@ -1586,4 +1710,5 @@ Curve3D::Curve3D() {
|
|
add_point(Vector3(0,2,0));
|
|
add_point(Vector3(0,2,0));
|
|
add_point(Vector3(0,3,5));*/
|
|
add_point(Vector3(0,3,5));*/
|
|
bake_interval = 0.2;
|
|
bake_interval = 0.2;
|
|
|
|
+ up_vector_enabled = true;
|
|
}
|
|
}
|