summaryrefslogtreecommitdiff
path: root/scene/resources/animation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/animation.cpp')
-rw-r--r--scene/resources/animation.cpp283
1 files changed, 158 insertions, 125 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 5561b5ef90..80993c7eaf 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1716,189 +1716,222 @@ void Animation::clear() {
}
-void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
- ERR_FAIL_INDEX(p_idx,tracks.size());
- ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
- TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
- for(int i=1;i<tt->transforms.size()-1;i++) {
- TKey<TransformKey> &t0 = tt->transforms[i-1];
- TKey<TransformKey> &t1 = tt->transforms[i];
- TKey<TransformKey> &t2 = tt->transforms[i+1];
+bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
- real_t c = (t1.time-t0.time)/(t2.time-t0.time);
- real_t t[3]={-1,-1,-1};
- { //translation
+ real_t c = (t1.time-t0.time)/(t2.time-t0.time);
+ real_t t[3]={-1,-1,-1};
- const Vector3 &v0=t0.value.loc;
- const Vector3 &v1=t1.value.loc;
- const Vector3 &v2=t2.value.loc;
+ { //translation
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.loc;
+ const Vector3 &v1=t1.value.loc;
+ const Vector3 &v2=t2.value.loc;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false;
+ }
- if (d>pd.length()*p_alowed_linear_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[0] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
- }
- { //rotation
+ t[0] = (d1-d0)/(d2-d0);
+ }
+ }
- const Quat &q0=t0.value.rot;
- const Quat &q1=t1.value.rot;
- const Quat &q2=t2.value.rot;
+ { //rotation
- //localize both to rotation from q0
+ const Quat &q0=t0.value.rot;
+ const Quat &q1=t1.value.rot;
+ const Quat &q2=t2.value.rot;
- if ((q0-q2).length() < CMP_EPSILON) {
+ //localize both to rotation from q0
- if ((q0-q1).length() > CMP_EPSILON)
- continue;
+ if ((q0-q2).length() < CMP_EPSILON) {
- } else {
+ if ((q0-q1).length() > CMP_EPSILON)
+ return false;
+ } else {
- Quat r02 = (q0.inverse() * q2).normalized();
- Quat r01 = (q0.inverse() * q1).normalized();
- Vector3 v02,v01;
- real_t a02,a01;
+ Quat r02 = (q0.inverse() * q2).normalized();
+ Quat r01 = (q0.inverse() * q1).normalized();
- r02.get_axis_and_angle(v02,a02);
- r01.get_axis_and_angle(v01,a01);
+ Vector3 v02,v01;
+ real_t a02,a01;
- if (Math::abs(a02)>p_max_optimizable_angle)
- continue;
+ r02.get_axis_and_angle(v02,a02);
+ r01.get_axis_and_angle(v01,a01);
- if (v01.dot(v02)<0) {
- //make sure both rotations go the same way to compare
- v02=-v02;
- a02=-a02;
- }
+ if (Math::abs(a02)>p_max_optimizable_angle)
+ return false;
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
- if (err_01>p_alowed_angular_err) {
- //not rotating in the same axis
- continue;
- }
+ if (v01.dot(v02)<0) {
+ //make sure both rotations go the same way to compare
+ v02=-v02;
+ a02=-a02;
+ }
- if (a01*a02 < 0 ) {
- //not rotating in the same direction
- continue;
- }
+ real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
+ if (err_01>p_alowed_angular_err) {
+ //not rotating in the same axis
+ return false;
+ }
- real_t tr = a01/a02;
- if (tr<0 || tr>1)
- continue; //rotating too much or too less
+ if (a01*a02 < 0 ) {
+ //not rotating in the same direction
+ return false;
+ }
- t[1]=tr;
+ real_t tr = a01/a02;
+ if (tr<0 || tr>1)
+ return false; //rotating too much or too less
- }
+ t[1]=tr;
}
- { //scale
+ }
- const Vector3 &v0=t0.value.scale;
- const Vector3 &v1=t1.value.scale;
- const Vector3 &v2=t2.value.scale;
+ { //scale
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.scale;
+ const Vector3 &v1=t1.value.scale;
+ const Vector3 &v2=t2.value.scale;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false; //beyond segment range
+ }
- if (d>pd.length()*p_alowed_linear_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[2] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
+
+ t[2] = (d1-d0)/(d2-d0);
}
+ }
- bool erase=false;
- if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
+ bool erase=false;
+ if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
- erase=true;
- } else {
+ erase=true;
+ } else {
- erase=true;
- real_t lt=-1;
- for(int j=0;j<3;j++) {
- //search for t on first, one must be it
- if (t[j]!=-1) {
- lt=t[j]; //official t
- //validate rest
- for(int k=j+1;k<3;k++) {
- if (t[k]==-1)
- continue;
-
- if (Math::abs(lt-t[k])>p_alowed_linear_err) {
- erase=false;
- break;
- }
+ erase=true;
+ real_t lt=-1;
+ for(int j=0;j<3;j++) {
+ //search for t on first, one must be it
+ if (t[j]!=-1) {
+ lt=t[j]; //official t
+ //validate rest
+ for(int k=j+1;k<3;k++) {
+ if (t[k]==-1)
+ continue;
+
+ if (Math::abs(lt-t[k])>p_alowed_linear_err) {
+ erase=false;
+ break;
}
- break;
}
+ break;
}
+ }
- ERR_CONTINUE( lt==-1 );
+ ERR_FAIL_COND_V( lt==-1,false );
- if (erase) {
+ if (erase) {
- if (Math::abs(lt-c)>p_alowed_linear_err) {
- //todo, evaluate changing the transition if this fails?
- //this could be done as a second pass and would be
- //able to optimize more
- erase=false;
- } else {
+ if (Math::abs(lt-c)>p_alowed_linear_err) {
+ //todo, evaluate changing the transition if this fails?
+ //this could be done as a second pass and would be
+ //able to optimize more
+ erase=false;
+ } else {
- //print_line(itos(i)+"because of interp");
- }
+ //print_line(itos(i)+"because of interp");
}
+ }
+
+ }
+
+
+ return erase;
+
+
+}
+
+void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
+
+ ERR_FAIL_INDEX(p_idx,tracks.size());
+ ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
+ TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
+ bool prev_erased=false;
+ TKey<TransformKey> first_erased;
+
+ for(int i=1;i<tt->transforms.size()-1;i++) {
+
+ TKey<TransformKey> &t0 = tt->transforms[i-1];
+ TKey<TransformKey> &t1 = tt->transforms[i];
+ TKey<TransformKey> &t2 = tt->transforms[i+1];
+
+ bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle);
+
+
+ if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle)) {
+ //avoid error to go beyond first erased key
+ erase=false;
}
+
if (erase) {
+
+ if (!prev_erased) {
+ first_erased=t1;
+ prev_erased=true;
+ }
+
tt->transforms.remove(i);
i--;
+
+ } else {
+ prev_erased=false;
}