准确的捏合缩放

5
我正在尝试在Unity3D/C#中创建一个准确的相机捏合缩放。它必须基于地形上的物理点。下面的图片展示了我想要实现的效果。
相机是空物体的子对象,该空物体会缩放(在0到1之间缩放)以“缩放”,这样就不会影响相机的透视。
因此,我想到的方法是每个手指都必须使用一条射线投射来获取A和B点以及相机父对象的当前缩放比例。
例如: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();
        }
    }
2个回答

6

介绍

最近我也需要解决同样的问题,并开始采用与您相同的方法,即将其视为用户正在与场景进行交互,我们需要找出他们的手指在场景中的位置以及它们如何移动,然后反转这些动作以在摄像机中反映它们。

然而,我们真正想要实现的目标要简单得多。我们只需让用户感觉到他们捏住的屏幕区域随着收缩的比例而改变大小。

目标

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

  • 目标:当用户收缩时,捏住的区域应该看起来缩小了。
  • 约束:我们不想改变任何对象的比例尺度。
  • 约束:我们的摄像机是透视摄像机。
  • 约束:我们不想改变摄像机的视野。
  • 约束:我们的解决方案应该是独立于分辨率/设备的。

考虑到所有这些,并且知道使用透视摄像机时,当物体越靠近时它们的比例尺度越大,而当它们越远时它们的比例尺度越小,似乎唯一的解决方案是将摄像机从场景中向内/外移动以缩放用户所看到的内容。

解决方案

为了使焦点处的场景看起来更大,我们需要调整摄像机的位置,使其在焦点处的视锥截面等效更小。

下面是一个更好的解释:

solution

图像的上半部分是我们想要实现的“幻觉”,即使用户扩展的区域在屏幕上变大两倍。图像的下半部分是我们需要移动摄像机以使视锥截面呈现该效果的方法。

然后问题就变成了我需要移动多远的相机才能实现所需的横截面

对此,我们可以利用视锥体的高度 h 与距离 d 之间的关系,当摄像机的视野角度(以角度为单位)为θ时。

trig

由于我们约束的视野角度θ是恒定的,因此我们可以看到 h d 成线性比例关系。

linearly proportional

这一点很有用,因为它意味着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个手指触摸时,存储屏幕位置和相关的世界位置。
  • 缩放时,移动相机以使世界位置返回到相同的屏幕位置。

1

This is a small example:

        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的第二个视频中,该教程对此进行了解释。

谢谢您,我看了这些视频,但是我正在使用透视相机和父级缩放来进行“缩放”。 - 4t0m1c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接