通过单击重置按钮重置相机旋转

Reset camera rotation by clicking reset button

我想做一个按钮。如果我单击该按钮,它将按原样重置每个位置。比如你进入VR。进入后你会看到一些图像在你面前。但有时由于运动,前面的场景会转到其他位置。如果你想再次看到它,你需要重新加载它。所以我想制作一个按钮来重置每个位置。我怎样才能做到这一点?

<a-camera position="2 0 15" sound__click="src: #click-sound; on: click; positional: false;" id="listener">
  <a-cursor raycaster="objects: .clickable" 
            fuse-timeout="2000"
            material="color: #F4D03F; shader: flat" 
            opacity="0.9">
  </a-cursor>

</a-camera>



<a-gui-button resetOrientation
          id="resetOrientation"
          class="clickable"              
          position="0.184 -10 -0.032"
          width="2.5" height="0.75"
          key-code="59"
          value="Reset"
          font-family="Helvetica"
          background-color="#A04000"

      >
      </a-gui-button>

这是html代码。这是我的 javaScript

AFRAME.registerComponent('resetOrientation', {
init: function () {
var button = document.querySelector("#resetOrientation");
var cameraPosition = document.querySelector("#listener");
var resetRotation = { x: 0, y: 0, z: 0 };
button.addEventListener('click', function () {
  var old = cameraPosition.getAttribute('rotation');
  console.log(old);
  var adjustedRotation = {
    x: adjustedRotation.x - old.x,
    y: adjustedRotation.y - old.y,
    z: adjustedRotation.z - old.z
  }
  cameraPosition.setAttribute("rotation", adjustedPosition);
   });
}
});

我该如何解决这个问题?

如果您尝试调整相机本身,那么当用户移动 phone 时它会立即被覆盖。

相反,您可以做的是将除相机之外的所有实体包裹在一个实体中,然后应用与相机当前旋转相反的旋转。您可能还想仅在 y 轴上应用它,但这取决于您。

var invRot = document.querySelector("#listener").getAttribute('rotation');
invRot.y = -invRot.y;
document.querySelector("#world").setAttribute("position", invRot);

在此示例中,world 实体将包含您的所有内容,而不是相机。

我们有一个用于 Supermedium 的 recenter 组件。

而不是 un-rotating 相机,我们将整个场景包裹在一个实体中,然后旋转它。因为在尝试读取 VR 中的相机旋转并尝试取消设置时有些混乱,因为整个矩阵的东西,因为 three.js 处理 VR 相机姿势。与 SteamVR 也有疯狂的不一致……所以我们在那里做了一些特别的事情。迭戈在这个问题上花了几天时间:

/**
 * Pivot the scene when user enters VR to face the links.
 */
AFRAME.registerComponent('recenter', {
  schema: {
    target: {default: ''}
  },

  init: function () {
    var sceneEl = this.el.sceneEl;
    this.matrix = new THREE.Matrix4();
    this.frustum = new THREE.Frustum();
    this.rotationOffset = 0;
    this.euler = new THREE.Euler();
    this.euler.order = 'YXZ';
    this.menuPosition = new THREE.Vector3();
    this.recenter = this.recenter.bind(this);
    this.checkInViewAfterRecenter = this.checkInViewAfterRecenter.bind(this);
    this.target = document.querySelector(this.data.target);

    // Delay to make sure we have a valid pose.
    sceneEl.addEventListener('enter-vr', () => setTimeout(this.recenter, 100));
    // User can also recenter the menu manually.
    sceneEl.addEventListener('menudown', this.recenter);
    sceneEl.addEventListener('thumbstickdown', this.recenter);
    window.addEventListener('vrdisplaypresentchange', this.recenter);
  },

  recenter: function () {
    var euler = this.euler;
    euler.setFromRotationMatrix(this.el.sceneEl.camera.el.object3D.matrixWorld, 'YXZ');
    this.el.object3D.rotation.y = euler.y + this.rotationOffset;
    // Check if the menu is in camera frustum in next tick after a frame has rendered.
    setTimeout(this.checkInViewAfterRecenter, 0);
  },

  /*
   * Sometimes the quaternion returns the yaw in the [-180, 180] range.
   * Check if the menu is in the camera frustum after recenter it to
   * decide if we apply an offset or not.
   */
  checkInViewAfterRecenter: (function () {
    var bottomVec3 = new THREE.Vector3();
    var topVec3 = new THREE.Vector3();

    return function () {
      var camera = this.el.sceneEl.camera;
      var frustum = this.frustum;
      var menuPosition = this.menuPosition;

      camera.updateMatrix();
      camera.updateMatrixWorld();
      frustum.setFromMatrix(this.matrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));

      // Check if menu position (and its bounds) are within the frustum.
      // Check bounds in case looking angled up or down, rather than menu central.
      menuPosition.setFromMatrixPosition(this.target.object3D.matrixWorld);
      bottomVec3.copy(menuPosition).y -= 3;
      topVec3.copy(menuPosition).y += 3;

      if (frustum.containsPoint(menuPosition) ||
          frustum.containsPoint(bottomVec3) ||
          frustum.containsPoint(topVec3)) { return; }

      this.rotationOffset = this.rotationOffset === 0 ? Math.PI : 0;
      // Recenter again with the new offset.
      this.recenter();
    };
  })(),

  remove: function () {
    this.el.sceneEl.removeEventListener('enter-vr', this.recenter);
  }
});

在HTML中:

 <a-entity id="scenePivot" recenter="target: #frontObject">
    <a-entity id="frontObject" data-description="When resetting, this object will be checked to see if user is facing it or not to confirm the reset."
  </a-entity>

  <a-camera></a-camera>

我不太清楚这是否是个好习惯,但对我来说这很有效:

var camera = document.querySelector("a-camera");

    camera.components["look-controls"].pitchObject.rotation.x = newX;
    camera.components["look-controls"].yawObject.rotation.y = newY;