aframe-interpolation.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /* globals AFRAME, performance, THREE */
  2. if (typeof AFRAME === 'undefined') {
  3. throw new Error('Component attempted to register before AFRAME was available.');
  4. }
  5. function getMillis () {
  6. return new Date().getTime();
  7. }
  8. function PositionInterpolator (timestep, entity) {
  9. var time = getMillis();
  10. var previous;
  11. var next;
  12. entity.el.addEventListener('componentchanged', function (event) {
  13. if (getTime() < 0.5) {
  14. // fixme - ignore multiple calls
  15. return;
  16. }
  17. if (event.detail.name === 'position') {
  18. if (!previous) {
  19. previous = new THREE.Vector3();
  20. next = new THREE.Vector3();
  21. }
  22. time = getMillis();
  23. previous.copy(next);
  24. next.copy(event.detail.newData);
  25. }
  26. });
  27. function getTime () {
  28. return (getMillis() - time) / timestep;
  29. }
  30. this.active = function () {
  31. return previous && next && (getTime() < 1.0);
  32. };
  33. var v = new THREE.Vector3();
  34. this.get = function () {
  35. return v.lerpVectors(previous, next, getTime());
  36. };
  37. }
  38. function radians(degrees) {
  39. return degrees * Math.PI / 180.0;
  40. }
  41. function RotationInterpolator (timestep, entity) {
  42. var time = getMillis();
  43. var previous;
  44. var next;
  45. entity.el.addEventListener('componentchanged', function (event) {
  46. if (getTime() < 0.5) {
  47. // fixme - ignore multiple calls
  48. return;
  49. }
  50. if (event.detail.name === 'rotation') {
  51. if (!previous) {
  52. previous = new THREE.Quaternion();
  53. next = new THREE.Quaternion();
  54. }
  55. time = getMillis();
  56. previous.copy(next);
  57. next.setFromEuler(new THREE.Euler(
  58. radians(event.detail.newData.x),
  59. radians(event.detail.newData.y),
  60. radians(event.detail.newData.z)
  61. ));
  62. }
  63. });
  64. function getTime () {
  65. return (getMillis() - time) / timestep;
  66. }
  67. this.active = function () {
  68. return previous && next && (getTime() < 1.0);
  69. };
  70. var e = new THREE.Euler();
  71. var q = new THREE.Quaternion();
  72. this.get = function () {
  73. THREE.Quaternion.slerp(previous, next, q, getTime());
  74. return e.setFromQuaternion(q);
  75. };
  76. }
  77. /**
  78. * Interpolate component for A-Frame.
  79. */
  80. AFRAME.registerComponent('interpolation', {
  81. schema: {
  82. duration: { default: 200 }
  83. },
  84. /**
  85. * Called once when component is attached. Generally for initial setup.
  86. */
  87. init: function () {
  88. },
  89. /**
  90. * Called when component is attached and when component data changes.
  91. * Generally modifies the entity based on the data.
  92. */
  93. update: function (oldData) {
  94. if (!this.interpolation) {
  95. var timestep = parseInt(this.data.duration, 10);
  96. this.positionInterpolator = new PositionInterpolator(timestep, this);
  97. this.rotationInterpolator = new RotationInterpolator(timestep, this);
  98. }
  99. },
  100. /**
  101. * Called when a component is removed (e.g., via removeAttribute).
  102. * Generally undoes all modifications to the entity.
  103. */
  104. remove: function () { },
  105. /**
  106. * Called on each scene tick.
  107. */
  108. tick: function (t) {
  109. if (this.positionInterpolator && this.positionInterpolator.active()) {
  110. this.el.object3D.position.copy(this.positionInterpolator.get());
  111. }
  112. if (this.rotationInterpolator && this.rotationInterpolator.active()) {
  113. this.el.object3D.rotation.copy(this.rotationInterpolator.get());
  114. }
  115. },
  116. /**
  117. * Called when entity pauses.
  118. * Use to stop or remove any dynamic or background behavior such as events.
  119. */
  120. pause: function () { },
  121. /**
  122. * Called when entity resumes.
  123. * Use to continue or add any dynamic or background behavior such as events.
  124. */
  125. play: function () { },
  126. });