Come implementare una semplice camera che funzioni da trackball in Unity

in Unity

Alessandro Oddo

 

Nel precedente tutorial ho dato le basi per capire i concetti fondamentali per iniziare a lavorare in Unity. Con questo articolo iniziamo a spiegare qualcosa di più specifico ma fondamentale per ogni progetto 3D, ovvero come muovere e ruotare una camera. 
Spiegherò come realizzare una camera che funzioni come trackball, ovvero una camera che ruota e si sposta intorno ad un punto di osservazione, utile per i progetti CAD dove si devono visualizzare scenari su larga scala.

Partiamo dalla creazione di un nuovo progetto, ci ritroveremo con definita solamente una fonte di luce e una Main Camera. Andiamo ad aggiungere un semplice cubo alla nostra scena, sul pannello di sinistra bisogna cliccare con il tasto destro, andare nel sottomenu 3D object e selezionare cube. Questo cubo sarà l'oggetto intorno a cui la nostra camera dovrà ruotare, allontanarsi e avvicinarsi.
Aggiunta di un cubo alla scena
Aggiunta di un cubo alla scena.
Come è possibile vedere dal tab Game, la Main Camera adesso mostra in primo piano il nostro oggetto 3D al centro della scena, selezionandola dal treeview di sinistra consiglio di "giocare" un po' con le sue proprietà per vedere gli effetti che hanno sulla scena visualizzata.
Selezione della camera
Selezione della camera.
Elenco solo le principali proprietà della camera che possiamo facilmente modificare dal pannello di destra:

> Position: per cambiare la posizione.

> Rotation: cambia l'angolazione della camera e quindi la direzione di puntamento.

> Clear Flag: si occupa di cosa visualizzare come sfondo della scena stessa, di base viene mostrato un'orizzonte azzurro ma cambiando i parametri lo sfondo può essere un colore uniforme a scelta o semplicemente nero (trasparente).

> Culling Mask: questo parametro è molto utile quando si utilizzano più oggetti di tipo Camera, decide infatti cosa viene effettivamente renderizzato  dalla camera e cosa viene "scartato", di default viene renderizzato tutto ma togliendo il layer "Default" si può vedere come il cubo immediatamente scompare.

> Projection: la camera può essere Perspective (principalmente per i progetti 3D) o Orthograpic (per quelli 2D), la Perspective con Field of View 60 gradi va benissimo per questo progetto.

> Clipping Planes: decide la distanza minima e massima per cui viene renderizzato effettivamente un oggetto, un oggetto troppo vicino alla camera o troppo lontano non vengono renderizzati per velocizzare la scena.

Ai fini di questo tutorial possiamo lasciare i parametri specifici della camera immutati.

Per far si che il nostro cubo diventi il nostro punto di osservazione creiamo un ulteriore GameObject, chiamiamolo Orbit e rendiamo la nostra camera suo children (dovrete avere una situazione come da immagine).

Camera attaccata ad un oggetto chiamato Orbit
Camera attaccata ad un oggetto chiamato Orbit
La configurazione così creata permette facilmente di ruotare la camera intorno agli assi X e Y, per ruotarla basta modificare il parametro rotation dell'oggetto Orbit, vi consiglio di fare qualche prova dal pannello per avere idea del suo funzionamento. Questa configurazione permette anche un facile zoom sull punto di osservazione, in questo caso deve essere modificato il parametro scale della stessa quantità su tutte e tre le direzioni.

Queste operazioni sull'oggetto Orbit devono essere scriptate per poter essere eseguite tramite il mouse. Aggiungiamo quindi uno script all'oggetto Orbit, io l'ho chiamato CameraManager.
Aggiunta di uno script
Aggiunta di uno script.
Lo script dovrà eseguire una serie di operazioni durante ogni singolo frame per effettuare rotazione e zoom, perciò è necessario che le operazioni vengano svolte all'interno del metodo Update di CameraManager deputato a questo. CameraManager necessita di reperire informazioni sullo stato della Main Camera e per questo la prima cosa da fare è aggiungere una variabile pubblica mainCamera da linkare all'omonimo GameObject.


public class CameraManager : MonoBehaviour
{   
    public Camera mainCamera;   
    private void Start()
    {      
         
     }   
    void Update()
    {  
     
    }
}

Definita nello script, la camera deve essere linkata da pannello come da immagine.
 
Link main camera
Link main camera.
Come seconda operazione dobbiamo semplicemente eliminare il metodo Start perchè inutile ai fini di questo esempio. Andiamo ora ad implementare lo zoom tramite rotella, per farlo creo una funzione chiamata da ZoomCamera che acquisisca il fattore di rotazione della rotella e lo applichi allo scale all'oggetto Orbit a cui è collegato.


public class CameraManager : MonoBehaviour
{   
    public Camera mainCamera;   
    void Update()   
    {       
        ZoomCamera();   
    }   
    void ZoomCamera()   
    {       
        float scrollFactor = Input.GetAxis("Mouse ScrollWheel");
        if (scrollFactor != 0)       
        {           
            transform.localScale = transform.localScale * (1f - scrollFactor);       
        }   
    }    
}



Mettendo in Run il progetto potrete vedere lo zoom in azione ruotando la rotella.

Adesso non rimane che implementare la rotazione, dobbiamo creare un metodo RotateCamera che se ne occupi.

 
public class CameraManager : MonoBehaviour
{   
    public Camera mainCamera;   
    public float rotationSpeed = 8f;   
    void Update()   
    {       
        RotateCamera();
        ZoomCamera();   
    }   
    void ZoomCamera(){...}  
    
    private void RotateCamera()   
    {       
        if (Input.GetMouseButton(1))           
            {                         
                float xRotation = rotationSpeed * Input.GetAxis("Mouse X");
                float yRotation = rotationSpeed * Input.GetAxis("Mouse Y");
                float xAngle = transform.eulerAngles.x%360f;
                float newAngle = ((xAngle + yRotation));
                
                if (Math.Cos(newAngle/360)<=0f)                   
                yRotation = 0;                              
        
                var angle =
                    new Vector3(transform.eulerAngles.x + yRotation, transform.eulerAngles.y + xRotation, 0);               
                    transform.SetPositionAndRotation(transform.position,Quaternion.Euler(angle.x,angle.y,0));           
        }   
    }    
}


Il metodo RotateCamera così implementato si attiva solo alla pressione del tasto destro del mouse, la velocità di rotazione è regolata dal valore di rotationSpeed. Come si può notare il metodo controlla che l'angolazione lungo X sia tra ±90 per evitare di avere la camera sottosopra rispetto al piano dello scenario.

Premere Run per controllare il funzionamento della rotazione e dello zoom implementati.

Partendo da questo script base è possibile aggiungere una serie di controlli sulla distanza massima della camera, sul massimo zoom etc... che sono specifici del proprio progetto. Se si ha necessità di implementare lo sospostamento del punto di osservazione banalmente si può aggiungere una funzione che modifichi la posizione di Orbit.

Abbiamo visto quindi come implementare una camera che funzioni da trackball su Unity, il "trucco" sta quindi nel rendere la camera figlia di un oggetto che si occuperà della sua rotazione e della sua posizione, mantenendo, senza bisogno di funzioni particolari, il puntamento della camera stessa.

 Il progetto è scaricabile al seguente indirizzo: https://static@static.netfarm.it/blog/camera_unity_blog.zip