1

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);
    }
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
ronara
  • 336
  • 11
  • 26
  • Did you ever find an answer to this question? You posted a bounty for this then abandoned it even after an answer was posted, and didn't provide feedback on the answer. – Ruzihm Mar 16 '22 at 17:52

1 Answers1

0

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
    }
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • I was testing on PC with mouse and a transform as one of the fingers, so let me know if I missed something turning it back into multitouch – Ruzihm Mar 04 '22 at 18:07