You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

10 KiB

Capitolo 7: Il Sistema Camera

Cos'è una Camera Virtuale?

Una camera virtuale è il "punto di vista" da cui osserviamo la scena 3D. È come una videocamera nel mondo virtuale che determina cosa vediamo e da che angolazione.

Componenti della Camera

Posizione (Eye)

Dove si trova la camera nello spazio 3D:

camera_position = (distance, height, distance)
# Esempio: (800, 450, 800)

Target (Center)

Dove guarda la camera:

look_at_point = (0, 0, 0)  # Centro della scena

Up Vector

Quale direzione è "su" per la camera:

up_vector = (0, 1, 0)  # Y+ è "su"

Visualizzazione

        Up (0,1,0)
         ↑
         │
         │
    Eye ●─────→ Center
   (800,450,800)   (0,0,0)

Vista Isometrica

Cosa la Rende Isometrica?

La camera è posizionata a 45 gradi sia orizzontalmente che verticalmente:

Vista dall'alto:
         N
         ↑
    Camera
   W ←  ●  → E     Camera a 45° tra N e E
         ↓
         S

Vista laterale:
         ↑
        45°
   Camera ●
          ╲
           ╲ 45°
            ↘
          Terreno

Posizione Isometrica

# Distanza dalla scena
distance = 800.0

# Camera posizionata a (distance, height, distance)
# Questo crea l'angolo di 45° perfetto
camera_pos = (distance, height, distance)
look_at = (0, 0, 0)

Perché funziona?

     Z
     ↑
     │
     │  distance
     ├──────────●  Camera
     │         ╱
     │    45° ╱
     │       ╱ distance
     O──────┴──────→ X

L'angolo tra X e Z è 45° quando le coordinate X e Z sono uguali!

Proiezione Prospettica

Field of View (FOV)

L'angolo di visione della camera:

fov = 45  # gradi

FOV piccolo (30°):        FOV grande (90°):
                             \___
                                ___
                                   ___
                                      ___
  Camera                    Camera
  Vista stretta            Vista ampia
  (teleobiettivo)          (grandangolo)

Clipping Planes

Near Plane: Distanza minima visibile Far Plane: Distanza massima visibile

near = 0.1    # Oggetti < 0.1 → invisibili
far = 5000.0  # Oggetti > 5000 → invisibili

         Far Plane (5000)
              
        ╱╲    
            
            
     Camera 
           ╲│
Near Plane (0.1)

Oggetti fuori da questo volume non vengono disegnati!

Codice Proiezione

def setup_projection(self, aspect_ratio):
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(
        self.fov,          # 45 gradi
        aspect_ratio,      # width/height (1.5 per 1200×800)
        self.near_clip,    # 0.1
        self.far_clip      # 5000.0
    )

Trasformazione ModelView

Cosa Fa

Imposta la posizione e orientamento della camera.

Codice

def setup_modelview(self):
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(
        # Posizione camera (eye)
        self.distance, self.height, self.distance,
        # Punto guardato (center)
        0, 0, 0,
        # Direzione "su" (up)
        0, 1, 0
    )

Significato Parametri

gluLookAt(
    eye_x, eye_y, eye_z,      # Dove sta la camera
    center_x, center_y, center_z,  # Dove guarda
    up_x, up_y, up_z          # Quale direzione è "su"
)

Controlli Utente

Input Tastiera

def handle_input(self, keys):
    # Zoom in/out
    if keys[pygame.K_UP]:
        self.distance -= self.zoom_speed
        self.distance = max(self.min_distance, self.distance)
    
    if keys[pygame.K_DOWN]:
        self.distance += self.zoom_speed
        self.distance = min(self.max_distance, self.distance)
    
    # Altezza camera
    if keys[pygame.K_LEFT]:
        self.height += self.height_speed
    
    if keys[pygame.K_RIGHT]:
        self.height -= self.height_speed

Effetto Zoom

Zoom In (UP):              Zoom Out (DOWN):
     ●                           ●
     │\                         │  \
     │ \                        │   \
     │  \                       │    \
 Distance                   Distance
   (più piccolo)              (più grande)
     │                          │
  Terreno                    Terreno
 (più vicino,               (più lontano,
  più grande)                più piccolo)

Effetto Altezza

Height Up (LEFT):         Height Down (RIGHT):

       ●                         ●
      ╱│                        ╱│\
     ╱ │                       ╱ │ \
    ╱  │                      ╱  │  \
Height                    Height
(più alto)               (più basso)
   │                        │
Terreno                  Terreno
(vista dall'alto)       (vista laterale)

Limiti della Camera

Perché i Limiti?

Evitare:

  • Zoom eccessivo (camera dentro il terreno)
  • Zoom troppo distante (terreno invisibile)
  • Angolazioni strane

Implementazione

# Limiti zoom
MIN_DISTANCE = 200.0
MAX_DISTANCE = 2000.0

if keys[pygame.K_UP]:
    self.distance -= self.zoom_speed
    # Blocca al minimo
    self.distance = max(MIN_DISTANCE, self.distance)

if keys[pygame.K_DOWN]:
    self.distance += self.zoom_speed
    # Blocca al massimo
    self.distance = min(MAX_DISTANCE, self.distance)

Limiti Altezza

Nessun limite esplicito sull'altezza, ma potresti aggiungere:

MIN_HEIGHT = 100.0
MAX_HEIGHT = 1000.0

self.height = max(MIN_HEIGHT, min(MAX_HEIGHT, self.height))

Aspect Ratio

Cos'è

Il rapporto larghezza/altezza della finestra:

aspect_ratio = width / height
# 1200 / 800 = 1.5

Perché Importante?

Senza aspect ratio corretto, l'immagine si deforma:

Aspect corretto (1.5):    Aspect sbagliato (1.0):
    ┌─────────────┐           ┌────────┐
    │             │           │        │
    │    ●○●      │           │  ●○●   │
    │             │           │        │
    └─────────────┘           └────────┘
  Proporzioni OK           Schiacciato!

Utilizzo

aspect_ratio = self.display[0] / self.display[1]
gluPerspective(fov, aspect_ratio, near, far)

Matrici di Trasformazione

Matrice Proiezione

Trasforma coordinate 3D in coordinate schermo 2D:

Mondo 3D → Matrice Proiezione → Spazio clip → Schermo 2D

Matrice ModelView

Combina trasformazione del modello E della vista:

ModelView = View × Model

View: Posizione camera
Model: Trasformazioni oggetto (nel nostro caso, nessuna)

Stack Matrici

OpenGL mantiene uno stack di matrici:

glMatrixMode(GL_PROJECTION)  # Seleziona stack proiezione
glLoadIdentity()             # Resetta a identità
gluPerspective(...)          # Applica trasformazione

glMatrixMode(GL_MODELVIEW)   # Seleziona stack modelview
glLoadIdentity()             # Resetta a identità
gluLookAt(...)              # Applica trasformazione

Calcoli Interni (Approfondimento)

gluLookAt - Cosa Fa

Crea una matrice che:

  1. Trasla il mondo in modo che la camera sia all'origine
  2. Ruota il mondo in modo che la camera guardi lungo -Z
Prima:                    Dopo gluLookAt:
      Mondo                     Camera all'origine
        │                            │
        ●  Camera                    O────→ Guarda -Z
       ╱                            ╱
      ╱                            ╱
   Terreno                      Terreno (traslato/ruotato)

gluPerspective - Cosa Fa

Crea una matrice che:

  1. Applica prospettiva (cose lontane = piccole)
  2. Mappa il volume visibile in un cubo [-1,+1]³
                          Cubo normalizzato
Frustum visibile          [-1,+1] in tutte
(pyramide tronca)         le dimensioni
       ╱╲                     ┌───┐
      ╱  ╲                    │   │
     ╱    ╲       →           │   │
    ╱      ╲                  └───┘
   ╱ Camera ╲           

Esempio Completo di Frame

# 1. Setup proiezione
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1.5, 0.1, 5000.0)

# 2. Setup camera
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(
    800, 450, 800,  # Camera a (800,450,800)
    0, 0, 0,        # Guarda il centro
    0, 1, 0         # Y è "su"
)

# 3. Disegna geometria
# OpenGL applica automaticamente entrambe le matrici
# a ogni vertice disegnato
glBegin(GL_QUADS)
glVertex3f(x, y, z)  # Trasformato da matrici
...
glEnd()

Miglioramenti Possibili

Rotazione Camera

def handle_input(self, keys):
    if keys[pygame.K_q]:
        self.rotation_angle += self.rotation_speed
    if keys[pygame.K_e]:
        self.rotation_angle -= self.rotation_speed

def setup_modelview(self):
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    
    # Ruota attorno all'asse Y
    glRotatef(self.rotation_angle, 0, 1, 0)
    
    gluLookAt(...)

Camera Libera (First Person)

# Camera FPS-style
position = [x, y, z]
rotation = [pitch, yaw]

def move_forward():
    position[0] += cos(yaw) * speed
    position[2] += sin(yaw) * speed

def look_around(mouse_dx, mouse_dy):
    yaw += mouse_dx * sensitivity
    pitch += mouse_dy * sensitivity

Camera Smooth (Interpolazione)

target_distance = 500
current_distance = 800

# Invece di salto immediato
current_distance = target_distance

# Usa interpolazione smooth
lerp_speed = 0.1
current_distance += (target_distance - current_distance) * lerp_speed

Componenti Camera

  • Position: Dove sta la camera
  • Target: Dove guarda
  • Up Vector: Orientamento "su"
  • FOV: Angolo di visione
  • Clipping: Near e far plane

Controlli

  • UP/DOWN: Zoom in/out (distance)
  • LEFT/RIGHT: Altezza camera (height)
  • Limiti: Min/max per evitare angoli strani

Matrici

  • Projection: FOV, aspect, clipping
  • ModelView: Posizione e orientamento camera

Vista Isometrica

Posizione a 45° sia orizzontalmente che verticalmente:

camera = (distance, height, distance)
target = (0, 0, 0)

Prossimo Capitolo: Personalizzazione e Configurazione →

← Capitolo Precedente | Torna all'indice