pinch zoom not moving to the correct location

169 Views Asked by At

I'm trying to implement pinch zoom, the zoom is working but it always zooming to the centre of the RectTransform, I tried to calculate the centre between the fingers and move to that point with DOAnchorPos but it takes me out of the RectTransform

here is how I calculate the centre and tried to move to it:

Vector3 center = (touchZero + touchOne) / 2f;
content.DOAnchorPos(center, 0.3f);

And here is the zoom that works:

public class PinchZoom : MonoBehaviour
{
    public RectTransform content;

    private void Update()
    {
        if (Input.touchCount != 2) return;

        var touchZero = Input.GetTouch(0);
        var touchOne = Input.GetTouch(1);

        var touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
        var touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

        var prevMagnitude = (touchZeroPrevPos - touchOnePrevPos).magnitude;
        var currentMagnitude = (touchZero.position - touchOne.position).magnitude;

        var difference = prevMagnitude - currentMagnitude;

        var localScale1 = content.localScale;
        var scale = localScale1;
        var localScale = scale;
        var zoomX = Mathf.Clamp(localScale.x - difference * 0.01f, 0.9f, 7f);
        var zoomY = Mathf.Clamp(localScale.y - difference * 0.01f, 0.9f, 7f);
        content.DOScale(new Vector3(zoomX, zoomY, 1f), 0.1f);
    }
}
1

There are 1 best solutions below

1
On

I found code in this question by ArtS but it didn't quite work for me if I used a perspective camera. With some substantial tweaks I think it works pretty well:

public class ZoomController: MonoBehaviour
{
    public float zoomSpeedPinch = 0.001f;
    public float zoomMin = 0.1f;
    public float zoomMax = 1f;

    Camera mainCam;

    public RectTransform content;

    private void Awake()
    {
        mainCam = Camera.main;
    }

    private void LateUpdate()
    {
        Zoom();
    }

    void Zoom()
    {
        if (Input.touchCount != 2) return;

        float scaleChange = 0f;
        Vector2 midPoint = Vector2.zero;

        var touchZero = Input.GetTouch(0);
        var touchOne = Input.GetTouch(1);

        var touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
        var touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

        float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
        float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

        float deltaMagnitudeDiff = touchDeltaMag - prevTouchDeltaMag;
        scaleChange = deltaMagnitudeDiff * zoomSpeedPinch;
        midPoint = (touchOne.position + touchZero.position) / 2f;

        if (scaleChange != 0)
        {
            var scaleX = transform.localScale.x;
            scaleX += scaleChange;
            scaleX = Mathf.Clamp(scaleX, zoomMin, zoomMax);
            var size = content.rect.size;
            size.Scale(content.localScale);

            var clickPlane = new Plane(mainCam.transform.forward, transform.position);
            var camRay = mainCam.ScreenPointToRay(midPoint);
            clickPlane.Raycast(camRay,out var dist);
            var p1 = camRay.GetPoint(dist);

            var p2 = transform.InverseTransformPoint(p1); 
            var pivotP = content.pivot * content.rect.size; 
            var p3 = (Vector2)p2 + pivotP; 
            var newPivot = p3 / content.rect.size;
            content.SetPivot(newPivot);

            transform.localScale = new Vector3(scaleX, scaleX, transform.localScale.z);
        }
    }

}

public static class RectTransformExtension
{
    /// <summary>
    /// Set pivot without changing the position of the element
    /// </summary>
    public static void SetPivot(this RectTransform rectTransform, Vector2 pivot)
    {
        Vector3 deltaPosition = rectTransform.pivot - pivot;    // get change in pivot
        deltaPosition.Scale(rectTransform.rect.size);           // apply sizing
        deltaPosition.Scale(rectTransform.localScale);          // apply scaling
        deltaPosition = rectTransform.rotation * deltaPosition; // apply rotation

        rectTransform.pivot = pivot;                            // change the pivot
        rectTransform.localPosition -= deltaPosition;           // reverse the position change
    }
}