Ver código fonte

add interpolation aframe component for smooth movement

Nikolay Suslov 7 anos atrás
pai
commit
103034dd8b

+ 2 - 1
public/aframe/index.vwf.yaml

@@ -62,12 +62,13 @@ children:
           position: [2, -1.25, 0]
           color: "#2167a5"
           depth: 1
+          interpolation: "50ms"
         methods:
           run:
             body: |
               var time = vwf.now;
               this.position = [this.position[0], this.position[1], Math.sin(time)]
-              this.future( 0.05 ).run();  // schedule the next step
+              this.future( 0.01 ).run();  // schedule the next step
   sky:
     extends: http://vwf.example.com/aframe/asky.vwf
     properties:

+ 6 - 1
support/client/lib/vwf.js

@@ -323,6 +323,9 @@
                     "vwf/model/blockly/msg/js/en": {
                         deps: [ "vwf/model/blockly/blockly_compressed" ]
                     },
+                     "vwf/model/aframe/addon/aframe-interpolation": {
+                        deps: [ "vwf/model/aframe/aframe-v0.5.0" ]
+                    },
                 }
             };
 
@@ -370,7 +373,8 @@
                 { library: "vwf/model/ohm", active: true },
 
                   { library: "vwf/model/aframe", 
-                    linkedLibraries: [ "vwf/model/aframe/aframe-v0.5.0" ], 
+                    linkedLibraries: [ "vwf/model/aframe/aframe-v0.5.0",
+                    "vwf/model/aframe/addon/aframe-interpolation" ], 
                     active: false 
                 },
 
@@ -419,6 +423,7 @@
 
                  { library: "vwf/view/aframe", active: false },
                 { library: "vwf/model/aframe/aframe-v0.5.0", active: false },
+                { library: "vwf/model/aframe/addon/aframe-interpolation", active: false },
 
                 { library: "vwf/view/kineticjs", active: false },
                 { library: "vwf/view/mil-sym", active: false },

+ 9 - 0
support/client/lib/vwf/model/aframe.js

@@ -204,6 +204,10 @@ define(["module", "vwf/model", "vwf/utility"], function (module, model, utility)
                     
                     switch ( propertyName ) { 
 
+                            case "interpolation":
+                                aframeObject.setAttribute('interpolation', { duration: propertyValue});
+                                    break;
+
                          case "position":
                                     aframeObject.setAttribute('position', { x: propertyValue[0], y: propertyValue[1], z: propertyValue[2] });
                                     break;
@@ -477,6 +481,11 @@ define(["module", "vwf/model", "vwf/utility"], function (module, model, utility)
                 if ( value === undefined && isAEntityDefinition( node.prototypes ) ) {
                     
                     switch ( propertyName ) { 
+
+                         case "interpolation":
+                               value = aframeObject.getAttribute('interpolation');
+                                    break;
+
                         case "position":
                                 var pos = aframeObject.getAttribute('position');
                                 if ( pos !== undefined ){ 

+ 153 - 0
support/client/lib/vwf/model/aframe/addon/aframe-interpolation.js

@@ -0,0 +1,153 @@
+/* globals AFRAME, performance, THREE */
+
+if (typeof AFRAME === 'undefined') {
+  throw new Error('Component attempted to register before AFRAME was available.');
+}
+
+function getMillis () {
+  return new Date().getTime();
+}
+
+function PositionInterpolator (timestep, entity) {
+  var time = getMillis();
+  var previous;
+  var next;
+
+  entity.el.addEventListener('componentchanged', function (event) {
+    if (getTime() < 0.5) {
+      // fixme - ignore multiple calls
+      return;
+    }
+
+    if (event.detail.name === 'position') {
+      if (!previous) {
+        previous = new THREE.Vector3();
+        next = new THREE.Vector3();
+      }
+
+      time = getMillis();
+      previous.copy(next);
+      next.copy(event.detail.newData);
+    }
+  });
+
+  function getTime () {
+    return (getMillis() - time) / timestep;
+  }
+
+  this.active = function () {
+    return previous && next && (getTime() < 1.0);
+  };
+
+  var v = new THREE.Vector3();
+
+  this.get = function () {
+    return v.lerpVectors(previous, next, getTime());
+  };
+}
+
+function radians(degrees) {
+  return degrees * Math.PI / 180.0;
+}
+
+function RotationInterpolator (timestep, entity) {
+  var time = getMillis();
+  var previous;
+  var next;
+
+  entity.el.addEventListener('componentchanged', function (event) {
+    if (getTime() < 0.5) {
+      // fixme - ignore multiple calls
+      return;
+    }
+
+    if (event.detail.name === 'rotation') {
+      if (!previous) {
+        previous = new THREE.Quaternion();
+        next = new THREE.Quaternion();
+      }
+
+      time = getMillis();
+      previous.copy(next);
+      next.setFromEuler(new THREE.Euler(
+        radians(event.detail.newData.x),
+        radians(event.detail.newData.y),
+        radians(event.detail.newData.z)
+      ));
+    }
+  });
+
+  function getTime () {
+    return (getMillis() - time) / timestep;
+  }
+
+  this.active = function () {
+    return previous && next && (getTime() < 1.0);
+  };
+
+  var e = new THREE.Euler();
+  var q = new THREE.Quaternion();
+  this.get = function () {
+    THREE.Quaternion.slerp(previous, next, q, getTime());
+    return e.setFromQuaternion(q);
+  };
+}
+
+/**
+ * Interpolate component for A-Frame.
+ */
+AFRAME.registerComponent('interpolation', {
+  schema: {
+    duration: { default: 200 }
+  },
+
+  /**
+   * Called once when component is attached. Generally for initial setup.
+   */
+  init: function () {
+  },
+
+  /**
+   * Called when component is attached and when component data changes.
+   * Generally modifies the entity based on the data.
+   */
+  update: function (oldData) {
+    if (!this.interpolation) {
+      var timestep = parseInt(this.data.duration, 10);
+
+      this.positionInterpolator = new PositionInterpolator(timestep, this);
+      this.rotationInterpolator = new RotationInterpolator(timestep, this);
+    }
+  },
+
+  /**
+   * Called when a component is removed (e.g., via removeAttribute).
+   * Generally undoes all modifications to the entity.
+   */
+  remove: function () { },
+
+  /**
+   * Called on each scene tick.
+   */
+  tick: function (t) {
+    if (this.positionInterpolator && this.positionInterpolator.active()) {
+      this.el.object3D.position.copy(this.positionInterpolator.get());
+    }
+
+    if (this.rotationInterpolator && this.rotationInterpolator.active()) {
+      this.el.object3D.rotation.copy(this.rotationInterpolator.get());
+    }
+  },
+
+  /**
+   * Called when entity pauses.
+   * Use to stop or remove any dynamic or background behavior such as events.
+   */
+  pause: function () { },
+
+  /**
+   * Called when entity resumes.
+   * Use to continue or add any dynamic or background behavior such as events.
+   */
+  play: function () { },
+});

+ 13 - 3
support/client/lib/vwf/view/aframe.js

@@ -115,15 +115,25 @@ define(["module", "vwf/view", "jquery", "jquery-ui"], function (module, view, $)
         var newNode = {
             "id": nodeName,
             "uri": nodeName,
-            "extends": "http://vwf.example.com/aframe/abox.vwf",
+            "extends": "http://vwf.example.com/aframe/aentity.vwf",
             "properties": {
-                "color": nodeColor,
-                "position": [0, 0, 0]
+                "position": [0, 0, 0],
+                "interpolation": "50ms"
             },
             "methods": {
             },
             "scripts": [],
             "children": {
+                "avatarBodyNode": {
+                    "extends": "http://vwf.example.com/aframe/abox.vwf",
+                    "properties": {
+                    "color": nodeColor,
+                    "position": [0, 0, 0.5]
+            },
+            "methods": {
+            },
+            "scripts": [],
+                },
                 "avatarNameNode": {
                     "extends": "http://vwf.example.com/aframe/atext.vwf",
                     "properties": {

+ 2 - 1
support/proxy/vwf.example.com/aframe/aentity.vwf.yaml

@@ -12,4 +12,5 @@ properties:
   clickable:
   src:
   repeat:
-  fog:
+  fog:
+  interpolation: