【问题标题】:Accurate Pinch Zoom精确的捏缩放
【发布时间】:2015-05-20 12:39:50
【问题描述】:

我试图弄清楚如何在 Unity3D/C# 中为我的相机创建精确的捏缩放。它必须基于地形上的物理点。下图说明了我想要达到的效果。

Camera 是 null 的子代,可缩放(在 0,1 和 1 之间)以“缩放”,以免干扰相机的视角。

所以到目前为止我想出的是,每个手指都必须使用光线投射来获取 A 和 B 点以及相机父级的当前比例。

EG: A (10,0,2), B (14,0,4), S (0.8,0.8,0.8) >> A (10,0,2), B (14,0,4) , S (0.3,0.3,0.3)

手指的位置会改变,但通过改变比例,hit.point 值应该保持不变。

奖励:作为奖励,最好让相机放大到手指之间的一点,而不仅仅是中心。

非常感谢您的帮助或参考。

编辑: 到目前为止,我已经在下面提出了这个,但这并不符合我想要的方式。它结合了我上面的一些想法,我认为问题在于它不应该是 /1000,而是一个包含当前比例的方程式。

if (Input.touchCount == 2) {
        if (!CamZoom) {
            CamZoom = true;
            var rayA = Camera.main.ScreenPointToRay (Input.GetTouch (0).position);
            var rayB = Camera.main.ScreenPointToRay (Input.GetTouch (1).position);
            int layerMask = (1 << 8);
            if (Physics.Raycast (rayA, out hit, 1500, layerMask)) {
                PrevA = new Vector3 (hit.point.x, 0, hit.point.z);
                Debug.Log ("PrevA: " + PrevA);
            }
            if (Physics.Raycast (rayB, out hit, 1500, layerMask)) {
                PrevB = new Vector3 (hit.point.x, 0, hit.point.z);
                Debug.Log ("PrevB: " + PrevB);
            }
            PrevDis = Vector3.Distance (PrevB, PrevA);
            Debug.Log ("PrevDis: " + PrevDis);
            PrevScaleV = new Vector3 (PrevScale, PrevScale, PrevScale);
            PrevScale = this.transform.localScale.x;
            Debug.Log ("PrevScale: " + PrevScale);
        }
        if (CamZoom) {
            var rayA = Camera.main.ScreenPointToRay (Input.GetTouch (0).position);
            var rayB = Camera.main.ScreenPointToRay (Input.GetTouch (1).position);
            int layerMask = (1 << 8);
            if (Physics.Raycast (rayA, out hit, 1500, layerMask)) {
                NewA = new Vector3 (hit.point.x, 0, hit.point.z);
            }
            if (Physics.Raycast (rayB, out hit, 1500, layerMask)) {
                NewB = new Vector3 (hit.point.x, 0, hit.point.z);
            }
            DeltaDis = PrevDis - (Vector3.Distance (NewB, NewA));
            Debug.Log ("Delta: " + DeltaDis);
            NewScale = PrevScale + (DeltaDis / 1000);
            Debug.Log ("NewScale: " + NewScale);
            NewScaleV = new Vector3 (NewScale, NewScale, NewScale);
            this.transform.localScale = Vector3.Lerp(PrevScaleV,NewScaleV,Time.deltaTime);
            PrevScaleV = NewScaleV;
            CamAngle();
        }
    }

【问题讨论】:

    标签: c# unity3d camera multi-touch pinchzoom


    【解决方案1】:

    简介

    我最近不得不解决同样的问题,并开始使用与您相同的方法,即认为用户正在与场景进行交互,我们需要弄清楚他们的手指在场景中的位置以及它们是如何移动的,然后反转这些动作以将它们反映在我们的相机中。

    但是,我们真正想要实现的目标要简单得多。我们只是想让用户感觉他们正在捏合的屏幕区域的大小随着他们捏合的变化而变化。

    目标

    首先让我们总结一下我们的目标和约束:

    • 目标:当用户捏合时,捏合的区域应按比例缩放以匹配捏合。
    • 约束:我们不想改变任何对象的比例。
    • 约束:我们的相机是透视相机。
    • 约束:我们不想改变相机的视野。
    • 约束:我们的解决方案应该独立于分辨率/设备。

    考虑到所有这些,并且考虑到我们知道使用透视相机时,当对象更接近更小时,它们会显得更大当他们进一步时,似乎缩放用户所看到的唯一解决方案是将相机移入/移出场景。

    解决方案

    为了使场景在我们的焦点处看起来更大,我们需要定位相机,以便在焦点处相机截头体的横截面等效地更小。

    这里有一个图表可以更好地解释:

    图像的上半部分是我们想要实现的“幻觉”,即让用户在屏幕上扩大两倍大的区域。图像的下半部分是我们需要如何移动相机来定位平截头体,从而给人一种印象。

    然后问题就变成了我应该将相机移动多远才能达到所需的横截面

    为此,当相机的视场角(度)为 θ.

    由于我们的视野角 θ 在我们约定的约束条件下是恒定的,我们可以看到 hd 是线性成比例的。

    知道这一点很有用,因为这意味着 h 的任何乘法/除法都同样反映在 d 中。这意味着我们可以直接将乘数应用于距离,无需额外计算将高度转换为距离!

    实施

    所以我们终于找到了代码。

    首先,我们将用户期望的大小变化作为他们之前手指之间距离的倍数:

    Touch touch0 = Input.GetTouch(0);
    Touch touch1 = Input.GetTouch(1);
    Vector2 prevTouchPosition0 = touch0.position - touch0.deltaPosition;
    Vector2 prevTouchPosition1 = touch1.position - touch1.deltaPosition;
    float touchDistance = (touch1.position - touch0.position).magnitude;
    float prevTouchDistance = (prevTouchPosition1 - prevTouchPosition1).magnitude;
    float touchChangeMultiplier = touchDistance / prevTouchDistance;
    

    现在我们知道用户想要缩放他们正在捏的区域的程度,我们可以将相机距焦点的距离缩放相反的量。

    焦点是相机的前向光线与您正在放大的物体的交点。为了一个简单的例子,我将使用原点作为我的焦点。

    Vector3 focalPoint = Vector3.zero;
    Vector3 direction = camera.transform.position - focalPoint;
    float newDistance = direction.magnitude / touchChangeMultiplier;
    camera.transform.position = newDistance * direction.normalized;
    camera.transform.LookAt(focalPoint);
    

    仅此而已。

    奖金

    这个答案已经很长了。因此,简要回答您有关使相机聚焦在您捏合的位置的问题:

    • 当您第一次检测到两指触摸时,存储屏幕位置和相关的世界位置。
    • 缩放时,移动相机以将世界位置放回相同的屏幕位置。

    【讨论】:

      【解决方案2】:

      这是一个小例子:

              if (_Touches.Length == 2)
              {
                  Vector2 _CameraViewsize = new Vector2(_Camera.pixelWidth, _Camera.pixelHeight);
      
                  Touch _TouchOne = _Touches[0];
                  Touch _TouchTwo = _Touches[1];
      
                  Vector2 _TouchOnePrevPos = _TouchOne.position - _TouchOne.deltaPosition;
                  Vector2 _TouchTwoPrevPos = _TouchTwo.position - _TouchTwo.deltaPosition;
      
                  float _PrevTouchDeltaMag = (_TouchOnePrevPos - _TouchTwoPrevPos).magnitude;
                  float _TouchDeltaMag = (_TouchOne.position - _TouchTwo.position).magnitude;
      
                  float _DeltaMagDiff = _PrevTouchDeltaMag - _TouchDeltaMag;
      
                  _Camera.transform.position += _Camera.transform.TransformDirection((_TouchOnePrevPos + _TouchTwoPrevPos - _CameraViewsize) * _Camera.orthographicSize / _CameraViewsize.y);
      
                  _Camera.orthographicSize += _DeltaMagDiff * _OrthoZoomSpeed;
                  _Camera.orthographicSize = Mathf.Clamp(_Camera.orthographicSize, _MinZoom, _MaxZoom) - 0.001f;
      
                  _Camera.transform.position -= _Camera.transform.TransformDirection((_TouchOne.position + _TouchTwo.position - _CameraViewsize) * _Camera.orthographicSize / _CameraViewsize.y);
      
              }
      

      this教程的第二个视频中解释了它

      【讨论】:

      • 谢谢,我检查了视频,但我使用透视相机和“缩放”的父级比例
      猜你喜欢
      • 2013-12-16
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      • 2016-01-15
      • 2012-12-04
      相关资源
      最近更新 更多