Up vector implementation and OrientedPathFollow.

This commit is contained in:
danilo2205 2018-05-18 19:14:25 -03:00
parent 228b09bafb
commit dc639d334a
9 changed files with 469 additions and 1 deletions

View file

@ -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;
}