A virtuális kamerákat a számítógépes grafikában arra használjuk, hogy azok “szemén keresztül” ránézzünk a virtuális világra. Ezek a kamerák egy pixelgrafikus szeletet készítenek ezen virtuális világból, ez a szelet az, amit mi, mint felhasználók a monitoron látunk megjelenni.
Unity-ben egy virtuális kamerát úgy hozunk létre, hogy egy Camera komponenst adunk egy GameObject-hez. Ha csak egy ilyen kamera van jelen a Scene-ben, akkor annak képét fogja automatikusan megjeleníteni a motor. Több kamerás rendszerekkel egyelőre nem foglalkozunk.
Virtuális kamerák típusai
A virtuális világ megjelenítésére szolgáló kameráknak alapvetően 2 fajtája van:
- Perspektivikus kamera
- Ortografikus kamera
A perspektivikus kamerák a valós világból megszokott perspektív hatással jelenítik meg a virtuális világot. Ez azt jelenti, hogy egy objektum kamerától való távolságával arányosan a mérete is csökken. Ami messzebb van, azt kisebbnek látjuk. Ilyen egyszerű.
Ezzel szemben az ortografikus kamerán keresztül nézve a virtuális világra, ami közelebb van az nem tűnik nagyobbnak, mint a távolabbi verziói. A 3D térben futó párhuzamos vonalak az ortografikus kamera által renderelt képen is párhuzamosak lesznek.
Kamerák beállításai
A Unity Camera komponens egyik beállítása a “Projection”. Itt tudunk választani az Ortografikus és a Perspektív nézet közt.
Emellett természetesen sokat számít, hogy az adott kamera a térben hol helyezkedik el és mi az orientációja, (merre néz). Ezeket az információkat azonban nem a kamera, hanem a Transform komponens tartalmazza, ami minden GameObject-en kötelezően jelen van:
Lásd: Unity Engine alapjai és logikája
Az ortografikus kamerát például gyakran használják úgy, hogy tökéletes felül- vagy oldalnézetből mutatja a világot. Ezt a transform komponens megfelelő beállításával érik el: (Pozicionálás forgatás)
Egy másik jellemző módja az ortografikus kamera felhasználásának az izometrikus nézet. Ebben az esetben a függőleges tengely mentén 45 fokkal van elforgatva a kamera, a vízszintes tengelyen pedig körül belül 35-tel. Ezen értékek nem kőbe vésettek, játékonként részben eltérhetnek, úgy hogy azok nézete még mindig izometrikusnak nevezhető.
A virtuális kamerák mindig egy térrészt vágnak ki a világból. A valódi kamerákkal szemben egy virtuális kamerának mindig van egy legközelebbi és legtávolabbi távolsága, amit belát.
A kamerához legközelebbi látható síkot elülső, a legtávolabbi síkot pedig hátulsó vágósíknak hívjuk.
Ezáltal az ortografikus kamera egy téglatestet vág ki a térből, perspektív pedig egy csapott tetejű piramist. Ezutóbbi alakzat matematikai neve, Frusztum.
Ha egy test vagy annak csak bizonyos pontjai ezen alakzaton kívül helyezkednek el, akkor biztosak lehetünk benne, hogy nem kerülnek kirajzolásra.
Egy ortografikus kamerát az elülső és hátulsó vágósík távolságán kívül még az általa belátott magasság és szélesség ír le. Ezek adják meg a belátott téglatest dimenzióit. Ezzel szemben perspektivikus kamerát a vágósíkok távolságával és egy vízszintes és függőleges szög értékkel a nyílásszöggel, azaz Field of View-val írhatunk le.
Unity alatt perspektív kameránál mindig a függőleges nyílásszöget, ortografikus kameránál pedig a függőleges magasságot tudjuk csak állítani. A vízszintes nyílásszöget vagy ortografikus szélességet a játékot megjelenítő ablak képarányából és a függőleges értékekből számolja ki automatikusan a játékmotor.
(Unity kameránál perspektív esetben választhatjuk azt a beállítást is, hogy a vízszintes nyílásszöget állítjuk be. Ám ez ne tévesszen meg senkit! Ilyenkor is a függőlegeset menti el a Unity és amint változik a megjelenített képarány, egyből módosul a vízszintes nyílásszög vele együtt. Továbbra is a függőleges szög lesz állandó.)
A virtuális kamera nézetét tehát a következő beállítások írnak le:
Transform komponensen:
- Pozíció - Position
- Orientáció (elforgatás) - Rotation
Camera komponensen:
- Projekció: Projection - Ortographic / Perspective
- Elülső vágósík - Near clipping plane
- Hátulsó vágósík - Far clipping plane
Ha Ortografikus a kamera:
- Függőleges magasság - Size (Unity-ben fél magasságot kell beállítani)
- Vízszintes szélesség: Automatikusan számolódik ki a képarány alapján.
Ha Perspektív a kamera:
- Függőleges nyílásszög - Field of View
- Vízszintes nyílásszög: Automatikusan számolódik ki a képarány alapján.
Ezen kívül több fontos beállítást tartalmaz egy Unity kamera, de ezeket itt most nem tárgyaljuk részletesen. Javaslom mindenkinek, hogy bátran kísérletezzen velük.
Vízszintes adatok beállása
Ha perspektív kamera a vízszintes látószögét vagy ortografikus kamera vízszintes mértét akarjuk fixre beállítani arra nincs kész lehetőség Unity-ben. Ehhez saját szkriptet kell írnunk ami mindig kiszámolja a függőleges értéket egy beállított vízszintes érték és a képarány alapján és ez alapján frissíti a kamerát folyamatosan.
Ezt teszi az alábbi kódrészlet, ami egy az egyben felhasználható bármilyen Unity projektben:
using System;
using UnityEngine;
// A kamera méretét szabályozó komponens, amely lehetővé teszi a kamera látószögének fixálását a vízszintes irányban is.
// Perspektív és ortográfikus kamerák is támogatott.
[ExecuteAlways] // Azért kell, hogy az Editor időben is működjön
[RequireComponent(typeof(Camera))] // Kamera komponens kötelező
public class CameraSizeController : MonoBehaviour
{
// Referencia látószög perspektív kamera esetén
[SerializeField] float referenceVerticalFieldOfView = 60;
[SerializeField] float referenceHorizontalFieldOfView = 60;
[Space]
// Referencia ortográfikus mérte kamera esetén
[SerializeField] float referenceHorizontalOrthographicSize = 10;
[SerializeField] float referenceVerticalOrthographicSize = 10;
[Space]
// Milyen mértékben legyen fix a vízszintes látószög vagy ortográfikus méret
[SerializeField, Range(0, 1)] float fixHorizontal;
new Camera camera;
Vector2Int lastScreenSize = Vector2Int.zero; // Legutóbbi képernyő méret
void Awake() => UpdateCamera(); // Awake-ben végrehajtjuk a beállítást, ...
void Update() => UpdateCamera(); // ...és minden Update-ben is.
void UpdateCamera()
{
if (camera == null)
camera = GetComponent<Camera>(); // Kamera komponens lekérése, ha szükséges
Vector2Int screenSize = new Vector2Int(Screen.width, Screen.height); // Képernyő méret
if (screenSize == lastScreenSize) // Ha nem változott a képernyő felbontása, akkor nincs semmi dolgunk
return;
lastScreenSize = screenSize; // Eltároljuk a legutóbbi felbontást
if (camera.orthographic) // Ha ortográfikus kamera
UpdateOrthographicCamera();
else // Ha perspektív kamera
UpdatePerspectiveCamera();
}
// Ortográfikus kamera frissítése
void UpdateOrthographicCamera()
{
if (fixHorizontal <= 0) // Ha a függőleges érték fix, akkor nincs sok dolgunk
{
camera.orthographicSize = referenceVerticalOrthographicSize;
return;
}
// A vízszintes méret alapján számolt függőleges méret
float verticalOrthographicSizeBasedOnHorizontal = referenceHorizontalOrthographicSize / camera.aspect; // A vízszintes méret alapján számolt vertikális méret
if (fixHorizontal >= 1)
camera.orthographicSize = verticalOrthographicSizeBasedOnHorizontal; // Ha teljsen fix a vízszintes látószög
else
camera.orthographicSize = Mathf.Lerp(referenceVerticalOrthographicSize, verticalOrthographicSizeBasedOnHorizontal, fixHorizontal); // Interpolálás (Súlyozott átlagolás)
}
// Perspektív kamera frissítése
void UpdatePerspectiveCamera()
{
if (fixHorizontal <= 0) // Ha a függőleges érték fix, nincs sok dolgunk.
{
camera.fieldOfView = referenceVerticalFieldOfView;
return;
}
// A vízszintes látószög alapján számolt függőleges látószög
float verticalFieldOfViewBasedOnHorizontal = Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * referenceHorizontalFieldOfView / 2) / camera.aspect) * 2 * Mathf.Rad2Deg;
if (fixHorizontal >= 1)
camera.fieldOfView = verticalFieldOfViewBasedOnHorizontal; // Ha teljsen fix a vízszintes látószög
else
camera.fieldOfView = Mathf.Lerp(referenceVerticalFieldOfView, verticalFieldOfViewBasedOnHorizontal, fixHorizontal); // Interpolálás (Súlyozott átlagolás)
}
}