2
\$\begingroup\$

I'm not fluent in English so I apologize in advance. I have found a source code in order to pan camera by touch - here it is:

public class CameraHandler : MonoBehaviour {

    private static readonly float PanSpeed = 20f;
    private static readonly float ZoomSpeedTouch = 0.1f;
    private static readonly float ZoomSpeedMouse = 0.5f;
    
    private static readonly float[] BoundsX = new float[]{-10f, 5f};
    private static readonly float[] BoundsZ = new float[]{-18f, -4f};
    private static readonly float[] ZoomBounds = new float[]{10f, 85f};
    
    private Camera cam;
    
    private Vector3 lastPanPosition;
    private int panFingerId; // Touch mode only
    
    private bool wasZoomingLastFrame; // Touch mode only
    private Vector2[] lastZoomPositions; // Touch mode only

    void Awake() {
        cam = GetComponent<Camera>();
    }
    
    void Update() {
        if (Input.touchSupported && Application.platform != RuntimePlatform.WebGLPlayer) {
            HandleTouch();
        } else {
            HandleMouse();
        }
    }
    
    void HandleTouch() {
        switch(Input.touchCount) {
    
        case 1: // Panning
            wasZoomingLastFrame = false;
            
            // If the touch began, capture its position and its finger ID.
            // Otherwise, if the finger ID of the touch doesn't match, skip it.
            Touch touch = Input.GetTouch(0);
            if (touch.phase == TouchPhase.Began) {
                lastPanPosition = touch.position;
                panFingerId = touch.fingerId;
            } else if (touch.fingerId == panFingerId && touch.phase == TouchPhase.Moved) {
                PanCamera(touch.position);
            }
            break;
    
        case 2: // Zooming
            Vector2[] newPositions = new Vector2[]{Input.GetTouch(0).position, Input.GetTouch(1).position};
            if (!wasZoomingLastFrame) {
                lastZoomPositions = newPositions;
                wasZoomingLastFrame = true;
            } else {
                // Zoom based on the distance between the new positions compared to the 
                // distance between the previous positions.
                float newDistance = Vector2.Distance(newPositions[0], newPositions[1]);
                float oldDistance = Vector2.Distance(lastZoomPositions[0], lastZoomPositions[1]);
                float offset = newDistance - oldDistance;
    
                ZoomCamera(offset, ZoomSpeedTouch);
    
                lastZoomPositions = newPositions;
            }
            break;
            
        default: 
            wasZoomingLastFrame = false;
            break;
        }
    }
    
    void HandleMouse() {
        // On mouse down, capture it's position.
        // Otherwise, if the mouse is still down, pan the camera.
        if (Input.GetMouseButtonDown(0)) {
            lastPanPosition = Input.mousePosition;
        } else if (Input.GetMouseButton(0)) {
            PanCamera(Input.mousePosition);
        }
    
        // Check for scrolling to zoom the camera
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        ZoomCamera(scroll, ZoomSpeedMouse);
    }
    
    void PanCamera(Vector3 newPanPosition) {
        // Determine how much to move the camera
        Vector3 offset = cam.ScreenToViewportPoint(lastPanPosition - newPanPosition);
        Vector3 move = new Vector3(offset.x * PanSpeed, 0, offset.y * PanSpeed);
        
        // Perform the movement
        transform.Translate(move, Space.World);  
        
        // Ensure the camera remains within bounds.
        Vector3 pos = transform.position;
        pos.x = Mathf.Clamp(transform.position.x, BoundsX[0], BoundsX[1]);
        pos.z = Mathf.Clamp(transform.position.z, BoundsZ[0], BoundsZ[1]);
        transform.position = pos;
    
        // Cache the position
        lastPanPosition = newPanPosition;
    }
    
    void ZoomCamera(float offset, float speed) {
        if (offset == 0) {
            return;
        }
    
        cam.fieldOfView = Mathf.Clamp(cam.fieldOfView - (offset * speed), ZoomBounds[0], ZoomBounds[1]);
    }
}

But my main problem is this two line of code :

Vector3 offset = cam.ScreenToViewportPoint(lastPanPosition - newPanPosition);
Vector3 move = new Vector3(offset.x * PanSpeed, 0, offset.y * PanSpeed);

What is this exactly? I mean, what science is behind this? Mathematics? If so, what kind of math? Vector projection? I don't need to know what ScreenToViewport is, I want to know what kind of science should I learn to do this by myself.

\$\endgroup\$
2
\$\begingroup\$
Vector3 offset = cam.ScreenToViewportPoint(lastPanPosition - newPanPosition);
Vector3 move = new Vector3(offset.x * PanSpeed, 0, offset.y * PanSpeed);

What is this exactly? I mean, what science is behind this? Mathematics? If so, what kind of math? Vector projection?

This is linear algebra, also informally called "vector math".

lastPanPosition - newPanPosition is a vector subtraction.

ScreenToViewportPoint is scaling, possibly via a matrix multiplication like this:

$$\vec v_\text{out} = \begin{bmatrix} \frac 1 {\text{screen width in pixels}} & 0\\ 0 & \frac 1 {\text{screen height in pixels}} \end{bmatrix}\vec v_\text{in} $$

Vector3 move = new Vector3(offset.x * PanSpeed, 0, offset.y * PanSpeed); is a scalar multiplication, and a projection, which we could also express as a matrix multiplication:

$$\vec {\text{move}} = \text{pan speed} \begin{bmatrix} 1 &0& 0\\ 0 &0& 0\\ 0 &1& 0 \end{bmatrix}\vec {\text{offset}} $$

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .