Trackball in Unity

Alessandro Oddo

Integrare una Trackball in Unity

Nel precedente post del nostro blog "Perchè usare Unity per i propri progetti 3d
ho scritto le basi per capire i concetti fondamentali per iniziare a lavorare in 
Unity.

In questo post invece inizierò a spiegare qualcosa di più specifico, ma fondamentale per ogni progetto 3D:
 Come muovere e ruotare una camera. 

Spiegherò come realizzare una camera che funzioni come trackball, cioè 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.

CREA NUOVO PROGETTO

Partiamo dalla creazione di un nuovo progetto, ci ritroveremo con definita solamente una fonte di luce e una Main Camera.
- Aggiungiamo 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
img.1 Aggiunta di un cubo alla scena.
Come è possibile vedere nel  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
img.2 Selezione della camera.
PROPRIETÀ 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.
IL CUBO COME PUNTO DI OSSERVAZIONE
Per far si che il nostro cubo diventi il nostro punto di osservazione
- Creiamo un ulteriore
 GameObject, chiamiamolo Orbit 
- 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.



RUOTARE UTILIZZANDO IL MOUSE 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.
E poi dobbiamo:
- 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 spostamento del punto di osservazione, banalmente si può aggiungere una funzione che modifichi la posizione di Orbit.


CONCLUSIONI

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.


PROGETTO È SCARICABILE QUI SOTTO! 
 Il progetto è scaricabile al seguente indirizzo: https://static@static.netfarm.it/blog/camera_unity_blog.zip