A 帧沿相机方向向前移动

Posted

技术标签:

【中文标题】A 帧沿相机方向向前移动【英文标题】:A-frame move forward in camera direction 【发布时间】:2018-07-21 09:58:20 【问题描述】:

我正在尝试在 A 帧中制作一个组件,该组件将使播放器/相机沿相机朝向的方向移动。它不应在 y 平面上的任何位置移动,只能在 x/y 平面上移动。 dom 中的当前设置是:

<a-entity>
    <a-camera></a-camera>
</a-entity>

我想将实体元素位置移动到当前相机方向上的 x 个单位,但它不应该在 y 平面上移动任何东西。我尝试了各种解决方案,但它们似乎在相机中引入了一些奇怪的变化。

【问题讨论】:

作为一个刚接触 VR 的人——WASD 控件已经在框架中执行此操作,我想重点是您希望独立于用户交互来执行此操作...? @KyleBaker WASD 控件不会将您移向相机方向 - 如果仅启用“w”,它们可以:) 【参考方案1】:

您可以通过多种方式处理此问题。

0) 向量

简单且可在大多数 3D 引擎中使用:

抓取相机的前向矢量/世界方向 乘以你想移动的距离 将其添加到您的位置向量中

a-frame 组件中的上述步骤可能如下所示:

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
  // define a custom component
  AFRAME.registerComponent("foo", 
    init: function() 
      // grab the camera
      var player = document.querySelector("a-camera")
      // create a direction vector
      var direction = new THREE.Vector3();

      window.addEventListener("keydown", (e) => 
        if (e.code === "KeyR") 
          // get the cameras world direction
          this.el.sceneEl.camera.getWorldDirection(direction);
          // multiply the direction by a "speed" factor
          direction.multiplyScalar(0.1)
          // get the current position
          var pos = player.getAttribute("position")
          // add the direction vector
          pos.add(direction)
          // set the new position
          player.setAttribute("position", pos);
          // !!! NOTE - it would be more efficient to do the
          // position change on the players THREE.Object:
          // `player.object3D.position.add(direction)`
          // but it would break "getAttribute("position")
        
      )
    
  )
</script>
<a-scene>
  <a-box position="-1 0.5 -3" rotation="0 45 0" foo color="#4CC3D9"></a-box>
  <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
  <a-cylinder position="1 0.75 -3" radius="0.5"  color="#FFC65D"></a-cylinder>
  <a-plane position="0 0 -4" rotation="-90 0 0"   color="#7BC8A4"></a-plane>
  <a-sky color="#ECECEC"></a-sky>
  <a-camera></a-camera>
</a-scene>

但是,您可能希望以更“数学式”的方式执行此操作:

1) 2D - 极坐标

将角度映射到 2D 空间是 polar coordinate system 的工作!

我们想根据相机旋转计算 x/y 坐标。坐标转换如下:

x = r * cos(a) y = r * sin(a)

其中“r”是步长,“a”是角度。


理论很无聊,让我们开始实践吧:
var angle = player.getAttribute("rotation") // grab angle
var x = 1 * Math.cos(angle.y * Math.PI / 180) // calculate shifts
var y = 1 * Math.sin(angle.y * Math.PI / 180)
var pos = player.getAttribute("position") // grab position
pos.x -= y; // update position
pos.z -= x;
player.setAttribute("position", pos);

这很简单 - 获取角度,计算偏移,然后设置新位置。

我们可以修改前面的例子:

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
  AFRAME.registerComponent("foo", 
    init: function() 
      var player = document.querySelector("a-camera")
      window.addEventListener("keydown", (e) => 
        if (e.code === "KeyR") 
          var angle = player.getAttribute("rotation")
          var x = 0.1 * Math.cos(angle.y * Math.PI / 180)
          var y = 0.1 * Math.sin(angle.y * Math.PI / 180)
          var pos = player.getAttribute("position")
          pos.x -= y;
          pos.z -= x;
          player.setAttribute("position", pos);
        
      )
    
  )
</script>
<a-scene>
  <a-box position="-1 0.5 -3" rotation="0 45 0" foo color="#4CC3D9"></a-box>
  <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
  <a-cylinder position="1 0.75 -3" radius="0.5"  color="#FFC65D"></a-cylinder>
  <a-plane position="0 0 -4" rotation="-90 0 0"   color="#7BC8A4"></a-plane>
  <a-sky color="#ECECEC"></a-sky>
  <a-camera></a-camera>
</a-scene>

2) 3D - 球坐标

毕竟,这是我们所说的 3D 空间。 概念是相同的 - 将摄像机角度转换为 x/y/z 坐标。这里的绝妙技巧是从spherical coordinate system 转换。三个维度使它有点困难,但最令人困惑的是——球面系统中的轴与clipspace 中的轴不同(由a-frame 使用) :

请记住,计算应类似于此 sn-p:

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
  // same component as 2D - just different calculations
  AFRAME.registerComponent("foo", 
    init: function() 
      var player = document.querySelector("a-camera")
      window.addEventListener("keydown", (e) => 
        if (e.code === "KeyR") 
          // get the player rotation
          var angle = player.getAttribute("rotation")
          // calculate the angles
          // the camera's theta == 0 is actually 90' in the clipspace
          let theta = (angle.x * Math.PI / 180) + Math.PI / 2 
          let fi = angle.y * Math.PI / 180
          let r = 0.1
          // calculate the position shifts
          let z = Math.sin(theta) * Math.cos(fi) * r
          let x = Math.sin(theta) * Math.sin(fi) * r
          let y = Math.cos(theta) * r

          // update the position
          var pos = player.getAttribute("position")
          pos.x -= x;
          pos.y -= y;
          pos.z -= z;
          player.setAttribute("position", pos);
        
      )
    
  )
</script>
<a-scene>
  <a-box position="-1 0.5 -3" rotation="0 45 0" foo color="#4CC3D9"></a-box>
  <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
  <a-cylinder position="1 0.75 -3" radius="0.5"  color="#FFC65D"></a-cylinder>
  <a-plane position="0 0 -4" rotation="-90 0 0"   color="#7BC8A4"></a-plane>
  <a-sky color="#ECECEC"></a-sky>
  <a-camera></a-camera>
</a-scene>

【讨论】:

@Kristofer 很高兴我能帮上忙,我在制造车辆时经常使用这些——比如机械师。 那你如何在 Y 轴上移动? (我知道 OP 没有要求它,但它可能会帮助很多人) @nook 让我知道它是否可以理解 哇,谢谢。我认为这是现在互联网上非常有价值的资源。 @nook 开始想多了,添加了一个更简单的选项

以上是关于A 帧沿相机方向向前移动的主要内容,如果未能解决你的问题,请参考以下文章

如何将“相机”移动到玩家所面对方向的左/右

OpenGL,第一人称相机翻译

需要一种方式让玩家朝着摄像机指向的方向移动。 (统一)

cesium 设置和移动camera相机(工具篇)

根据相机方向移动

玩家相对于相机方向的移动 C#