Lensa sudut lebar tidak boleh berperilaku berbeda dari model lensa biasa lainnya. Mereka hanya memiliki FOV yang lebih besar (dalam D3DXMatrixPerspectiveFovLH
arti - saya asumsikan Anda menggunakan DirectX), atau nilai kiri / kanan dan bawah / atas yang lebih besar (dalam glFrustum
arti OpenGL ).
Saya percaya bagian yang sangat menarik terletak pada pemodelan lensa fisheye. Ada Fisheye Quake yang bisa Anda pelajari, ia datang dengan sumbernya.
Proyeksi mata ikan yang benar
Proyeksi lensa mata ikan, bagaimanapun, sangat non-linear. Dalam jenis lensa yang lebih umum (sepengetahuan saya, yang terbatas pada kamera pengintai), sebuah titik M
di ruang diproyeksikan ke permukaan belahan unit, kemudian permukaan itu mengalami proyeksi paralel ke cakram unit:
M
x M: world position
\ M': projection of M on the unit hemisphere
\ ______ M": projection of M' on the unit disc (= the screen)
M'_x' `-.
,' |\ `.
/ | \ \
/ | \ \
| | \ |
__________|_____|____\_________|_________
M" O 1
Ada pemetaan fisheye lain yang mungkin memberikan efek lebih menarik. Terserah kamu.
Saya bisa melihat dua cara untuk menerapkan efek fisheye di HLSL.
Metode 1: melakukan proyeksi pada vertex shader
Keuntungan : hampir tidak ada yang perlu diubah dalam kode. Shader fragmen sangat sederhana. Daripada:
...
float4 screenPoint = mul(worldPoint, worldViewProjMatrix);
...
Anda melakukan sesuatu seperti ini (mungkin banyak disederhanakan):
...
// This is optional, but it computes the z coordinate we will
// need later for Z sorting.
float4 out_Point = mul(in_Point, worldViewProjMatrix);
// This retrieves the world position so that we can project on
// the hemisphere. Normalise this vector and you get M'
float4 tmpPoint = mul(in_Point, worldViewMatrix);
// This computes the xy coordinates of M", which happen to
// be the same as M'.
out_Point.xy = tmpPoint.xy / length(tmpPoint.xyz);
...
Kelemahan : karena seluruh pipa render dipikirkan untuk transformasi linear, proyeksi yang dihasilkan tepat untuk simpul, tetapi semua variasi akan salah, serta koordinat tekstur, dan segitiga akan tetap tampak sebagai segitiga meskipun harus tampak terdistorsi.
Penanganan masalah : dapat diterima untuk mendapatkan perkiraan yang lebih baik dengan mengirimkan geometri yang disempurnakan ke GPU, dengan lebih banyak subdivisi segitiga. Ini mungkin juga dilakukan dalam geometri shader, tetapi karena langkah ini terjadi setelah vertex shader, geometri shader akan sangat kompleks karena harus melakukan proyeksi tambahan sendiri.
Metode 2: melakukan proyeksi pada shader fragmen
Metode lain adalah membuat adegan menggunakan proyeksi sudut lebar, kemudian mendistorsi gambar untuk mencapai efek mata ikan menggunakan shader fragmen layar penuh.
Jika titik M
memiliki koordinat (x,y)
pada layar mata ikan, itu berarti titik tersebut memiliki koordinat (x,y,z)
pada permukaan belahan bumi, dengan z = sqrt(1-x*x-y*y)
. Yang berarti ada koordinat (ax,ay)
dalam adegan kami yang diberikan dengan FOV theta
seperti itu a = 1/(z*tan(theta/2))
. (Tidak 100% yakin tentang matematika saya di sini, saya akan periksa lagi malam ini).
Oleh karena itu shader fragmen akan menjadi seperti ini:
void main(in float4 in_Point : POSITION,
uniform float u_Theta,
uniform sampler2D u_RenderBuffer,
out float4 out_FragColor : COLOR)
{
z = sqrt(1.0 - in_Point.x * in_Point.x - in_Point.y * in_Point.y);
float a = 1.0 / (z * tan(u_Theta * 0.5));
out_FragColor = tex2D(u_RenderBuffer, (in_Point.xy - 0.5) * 2.0 * a);
}
Keuntungan : Anda mendapatkan proyeksi sempurna tanpa distorsi selain dari yang disebabkan oleh akurasi piksel.
Kekurangan : Anda tidak dapat secara fisik melihat seluruh pemandangan, karena FOV tidak dapat mencapai 180 derajat. Juga, semakin besar FOV, semakin buruk presisi di tengah gambar ... yang tepat di mana Anda ingin presisi maksimum.
Penanganan masalah : kehilangan presisi dapat ditingkatkan dengan melakukan beberapa render pass, misalnya 5, dan melakukan proyeksi dengan cara peta kubus. Solusi lain yang sangat sederhana adalah hanya memotong gambar akhir ke FOV yang diinginkan - bahkan jika lensa itu sendiri memiliki 180 derajat FOV, Anda mungkin ingin membuat hanya sebagian darinya. Ini disebut mata ikan "full-frame" (yang agak ironis, karena memberi kesan bahwa Anda mendapatkan "penuh" sesuatu saat benar-benar memotong gambar).
(Catatan: jika Anda menemukan ini berguna tetapi tidak cukup jelas, tolong beritahu saya, saya merasa ingin menulis artikel yang lebih rinci tentang ini).
Seharusnya begitu
z = sqrt(1.0 - in_Point.x * in_Point.x - in_Point.y * in_Point.y)
, bukan?Implementasi GLSL saya adalah:
sumber