Pinch to zoom in a specific location

I have implemented a code for mouse zoom in/out using mouse scroll wheel. The camera zooms in at the position of the mouse pointer. It uses Ray of the mouse pointer to get the position. But I am not sure how to do the same for touch. As in using pinch to zoom in/out in touchscreen devices. Since there is no mouse pointer, what is the correct way to achieve this?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CameraController : MonoBehaviour
{
    private Vector3 mouseWorldPosStart;
    private float zoomScale = 10.0f;
    private float maxFieldOfView = 160.0f;
    private float minFieldOfView = 5.0f;

    //What I have done so far for touch
    int prevtouchCount;
    float firstDistance;
    float originalZoom;
    float currentZoom;

    // Start is called before the first frame update
    void Start()
    {
       
    }

    // Update is called once per frame
    void Update()
    {
        if(Mouse.current.leftButton.wasPressedThisFrame){
            mouseWorldPosStart = GetPerspectivePos();
        }

        Zoom(Mouse.current.scroll.ReadValue().normalized.y / 10);

       //Below code is for touch
       //Touch 
        if (Touch.activeFingers.Count == 2) {
            // get touches as above

            Touch touch1 = Touch.activeFingers[0].currentTouch;
            Touch touch2 = Touch.activeFingers[1].currentTouch;

            float distance = Vector2.Distance (touch1.screenPosition, touch2.screenPosition);

            // record reference finger distance only at the moment
            //  you have 2 fingers and you didn't the frame before
            if (prevtouchCount != 2) {
                firstDistance = distance;
                originalZoom = Camera.main.fieldOfView;
            }

            // now take the ratio of current distance to firstDistance and
            // adjust zoom from originalZoom
            float ratio = distance / firstDistance;

            currentZoom = originalZoom / ratio;

        }

        // for comparing next frame
        prevtouchCount = Touch.activeFingers.Count;
    }


    private void Zoom(float zoomDiff){

        if(zoomDiff > 0){
            mouseWorldPosStart = GetPerspectivePos();
            Camera.main.fieldOfView = Mathf.Clamp(Camera.main.fieldOfView - zoomDiff * zoomScale, minFieldOfView, maxFieldOfView);
            Vector3 mouseWorldPosDiff = mouseWorldPosStart - GetPerspectivePos();
            transform.position += mouseWorldPosDiff;
        } else if(zoomDiff < 0){
            Camera.main.fieldOfView = Mathf.Clamp(Camera.main.fieldOfView, minFieldOfView, maxFieldOfView);
            Camera.main.fieldOfView += 1;

        }
    }

    public Vector3 GetPerspectivePos(){
        Ray ray = Camera.main.ScreenPointToRay (Mouse.current.position.ReadValue());
        Plane plane = new Plane(transform.forward, 0.0f);
        float dist;
        plane.Raycast(ray, out dist);
        return ray.GetPoint(dist);
    }
}

I usually use the centroid of the touches, eg, add their positions together and divide by how many touches there are.

In fact, by default Unity “simulates” the mouse as this position when on a multi-touch screen. Try it! Just print out the mouse position and try different touches on the device.

1 Like