Newer
Older
AegisforEcosystem / next / AR.js-3.4.0 / three.js / src / threex / threex-arsmoothedcontrols.js
@KAOKA Daisuke KAOKA Daisuke on 31 May 2022 5 KB into AR.js
import ArBaseControls from "./threex-arbasecontrols";

/**
 * - lerp position/quaternino/scale
 * - minDelayDetected
 * - minDelayUndetected
 * @param {[type]} object3d   [description]
 * @param {[type]} parameters [description]
 */
const ArSmoothedControls = function (object3d, parameters) {
  var _this = this;

  ArBaseControls.call(this, object3d);

  // copy parameters
  this.object3d.visible = false;

  this._lastLerpStepAt = null;
  this._visibleStartedAt = null;
  this._unvisibleStartedAt = null;

  // handle default parameters
  parameters = parameters || {};
  this.parameters = {
    // lerp coeficient for the position - between [0,1] - default to 1
    lerpPosition: 0.8,
    // lerp coeficient for the quaternion - between [0,1] - default to 1
    lerpQuaternion: 0.2,
    // lerp coeficient for the scale - between [0,1] - default to 1
    lerpScale: 0.7,
    // delay for lerp fixed steps - in seconds - default to 1/120
    lerpStepDelay: 1 / 60,
    // minimum delay the sub-control must be visible before this controls become visible - default to 0 seconds
    minVisibleDelay: 0.0,
    // minimum delay the sub-control must be unvisible before this controls become unvisible - default to 0 seconds
    minUnvisibleDelay: 0.2,
  };

  //////////////////////////////////////////////////////////////////////////////
  //		setParameters
  //////////////////////////////////////////////////////////////////////////////
  setParameters(parameters);
  function setParameters(parameters) {
    if (parameters === undefined) return;
    for (var key in parameters) {
      var newValue = parameters[key];

      if (newValue === undefined) {
        console.warn(
          "ArSmoothedControls: '" + key + "' parameter is undefined."
        );
        continue;
      }

      var currentValue = _this.parameters[key];

      if (currentValue === undefined) {
        console.warn(
          "ArSmoothedControls: '" +
            key +
            "' is not a property of this material."
        );
        continue;
      }

      _this.parameters[key] = newValue;
    }
  }
};

ArSmoothedControls.prototype = Object.create(ArBaseControls.prototype);
ArSmoothedControls.prototype.constructor = ArSmoothedControls;

//////////////////////////////////////////////////////////////////////////////
//		update function
//////////////////////////////////////////////////////////////////////////////

ArSmoothedControls.prototype.update = function (targetObject3d) {
  var object3d = this.object3d;
  var parameters = this.parameters;
  var wasVisible = object3d.visible;
  var present = performance.now() / 1000;

  //////////////////////////////////////////////////////////////////////////////
  //		handle object3d.visible with minVisibleDelay/minUnvisibleDelay
  //////////////////////////////////////////////////////////////////////////////
  if (targetObject3d.visible === false) this._visibleStartedAt = null;
  if (targetObject3d.visible === true) this._unvisibleStartedAt = null;

  if (targetObject3d.visible === true && this._visibleStartedAt === null)
    this._visibleStartedAt = present;
  if (targetObject3d.visible === false && this._unvisibleStartedAt === null)
    this._unvisibleStartedAt = present;

  if (wasVisible === false && targetObject3d.visible === true) {
    var visibleFor = present - this._visibleStartedAt;
    if (visibleFor >= this.parameters.minVisibleDelay) {
      object3d.visible = true;
      snapDirectlyToTarget();
    }
    // console.log('visibleFor', visibleFor)
  }

  if (wasVisible === true && targetObject3d.visible === false) {
    var unvisibleFor = present - this._unvisibleStartedAt;
    if (unvisibleFor >= this.parameters.minUnvisibleDelay) {
      object3d.visible = false;
    }
  }

  //////////////////////////////////////////////////////////////////////////////
  //		apply lerp on positon/quaternion/scale
  //////////////////////////////////////////////////////////////////////////////

  // apply lerp steps - require fix time steps to behave the same no matter the fps
  if (this._lastLerpStepAt === null) {
    applyOneSlerpStep();
    this._lastLerpStepAt = present;
  } else {
    var nStepsToDo = Math.floor(
      (present - this._lastLerpStepAt) / this.parameters.lerpStepDelay
    );
    for (var i = 0; i < nStepsToDo; i++) {
      applyOneSlerpStep();
      this._lastLerpStepAt += this.parameters.lerpStepDelay;
    }
  }

  // disable the lerp by directly copying targetObject3d position/quaternion/scale
  if (false) {
    snapDirectlyToTarget();
  }

  // update the matrix
  this.object3d.updateMatrix();

  //////////////////////////////////////////////////////////////////////////////
  //		honor becameVisible/becameUnVisible event
  //////////////////////////////////////////////////////////////////////////////
  // honor becameVisible event
  if (wasVisible === false && object3d.visible === true) {
    this.dispatchEvent({ type: "becameVisible" });
  }
  // honor becameUnVisible event
  if (wasVisible === true && object3d.visible === false) {
    this.dispatchEvent({ type: "becameUnVisible" });
  }
  return;

  function snapDirectlyToTarget() {
    object3d.position.copy(targetObject3d.position);
    object3d.quaternion.copy(targetObject3d.quaternion);
    object3d.scale.copy(targetObject3d.scale);
  }

  function applyOneSlerpStep() {
    object3d.position.lerp(targetObject3d.position, parameters.lerpPosition);
    object3d.quaternion.slerp(
      targetObject3d.quaternion,
      parameters.lerpQuaternion
    );
    object3d.scale.lerp(targetObject3d.scale, parameters.lerpScale);
  }
};

export default ArSmoothedControls;