Foto Facebook 3D Di Dalam: Parallax Shaders

gambar

Dalam beberapa bulan terakhir, Facebook telah membanjiri foto 3D . Jika Anda belum dapat melihatnya, maka saya akan menjelaskan: Foto 3D adalah gambar di dalam pos yang dengan lancar mengubah sudut saat menggulir halaman atau saat Anda menggerakkan mouse di atasnya.

Beberapa bulan sebelum fitur ini muncul, Facebook menguji fitur serupa dengan model 3D. Meskipun Anda dapat dengan mudah memahami bagaimana Facebook dapat membuat model 3D dan memutarnya sesuai dengan posisi mouse, dengan foto 3D situasinya mungkin tidak begitu intuitif.

Teknik yang digunakan Facebook untuk membuat tiga dimensi gambar dua dimensi kadang-kadang disebut peta ketinggian elevasi . Ini menggunakan fenomena optik yang disebut paralaks .

Contoh foto Facebook 3D (GIF)

Apa itu paralaks


Jika Anda memainkan Super Mario, maka Anda tahu persis apa paralaksnya. Meskipun Mario berlari dengan kecepatan yang sama, tampaknya objek yang jauh di latar bergerak lebih lambat (lihat di bawah).


Efek ini menciptakan ilusi bahwa beberapa elemen, seperti gunung dan awan, terletak lebih jauh. Ini efektif karena otak kita menggunakan paralaks (bersama dengan isyarat visual lainnya) untuk memperkirakan jarak ke objek yang jauh.

Bagaimana otak mengevaluasi jarak?
Diasumsikan bahwa otak manusia menggunakan beberapa mekanisme untuk memperkirakan jarak. Pada jarak pendek dan menengah, jarak dihitung dengan membandingkan perbedaan posisi objek yang terlihat dengan mata kanan dan kiri. Ini disebut visi stereoskopik dan tersebar luas di alam.

Namun, untuk objek yang cukup jauh, satu penglihatan stereoskopis tidak cukup. Pegunungan, awan, dan bintang berbeda terlalu sedikit untuk mata yang berbeda untuk melihat perbedaan yang signifikan. Oleh karena itu, paralaks relatif ikut berperan. Objek di latar belakang bergerak kurang dari objek di latar depan. Ini adalah gerakan relatif mereka yang memungkinkan Anda untuk mengatur jarak relatif.

Dalam persepsi jarak, banyak mekanisme lain digunakan. Yang paling terkenal di antaranya adalah kabut atmosfer, yang memberi warna biru pada objek jauh. Di dunia lain, sebagian besar petunjuk atmosfer ini tidak ada, sehingga sangat sulit untuk menilai skala objek di planet lain dan bulan. Pengguna YouTube Alex McCulgan menjelaskan ini di saluran Astrum- nya, menunjukkan betapa sulitnya untuk menentukan ukuran objek bulan yang ditampilkan dalam video.


Parallax sebagai pergeseran


Jika Anda terbiasa dengan aljabar linier, maka Anda mungkin tahu betapa rumit dan tidak sepele matematika rotasi 3D. Oleh karena itu, ada cara yang jauh lebih sederhana untuk memahami paralaks, yang tidak membutuhkan apa pun selain perubahan.

Mari kita bayangkan bahwa kita sedang melihat kubus (lihat di bawah). Jika kita tepat sejajar dengan pusatnya, maka wajah depan dan belakang akan terlihat seperti dua kotak dengan ukuran berbeda untuk mata kita. Inilah prospeknya .


Namun, apa yang terjadi jika kita memindahkan kamera ke bawah, atau menaikkan kubus ke atas? Dengan menerapkan prinsip yang sama, kita dapat melihat bahwa wajah depan dan belakang telah bergeser relatif terhadap posisi sebelumnya. Yang lebih menarik adalah bahwa mereka telah bergerak relatif satu sama lain. Wajah belakang, yang jauh dari kita, seakan bergerak kurang.


Jika kita ingin menghitung posisi sebenarnya dari simpul-simpul kubus ini dalam ruang lingkup yang diproyeksikan, maka kita harus serius mengambil trigonometri. Namun, ini tidak terlalu penting. Jika gerakan kamera cukup kecil, maka kami dapat memperkirakan perpindahan titik, menggerakkannya sesuai dengan jaraknya.

Satu-satunya hal yang perlu kita tentukan adalah skala. Jika kita memindahkan X meter ke kanan, maka akan terlihat bahwa objek Y meter telah pindah Z meter. Jika X tetap kecil, paralaks menjadi tugas interpolasi linier daripada trigonometri. Intinya, ini berarti kita dapat mensimulasikan rotasi 3D kecil dengan menggeser piksel tergantung pada jaraknya dari kamera.

Hasilkan peta kedalaman


Pada prinsipnya, apa yang dilakukan Facebook tidak jauh berbeda dengan apa yang terjadi di Super Mario. Untuk gambar yang diberikan, piksel tertentu digeser ke arah gerakan berdasarkan jarak ke kamera. Untuk membuat foto 3D Facebook, Anda hanya perlu foto itu sendiri dan peta yang menyatakan seberapa jauh setiap piksel dari kamera. Peta seperti itu memiliki nama yang diharapkan - "peta kedalaman" . Ini juga disebut peta ketinggian, tergantung pada konteksnya.

Mengambil foto cukup sederhana, tetapi menghasilkan peta kedalaman yang tepat adalah tugas yang jauh lebih sulit. Perangkat modern menggunakan berbagai teknik. Paling sering menggunakan dua kamera; masing-masing mengambil gambar dari subjek yang sama, tetapi dengan perspektif yang sedikit berbeda. Prinsip yang sama digunakan dalam penglihatan stereoskopik , yang digunakan orang untuk mengevaluasi kedalaman pada jarak pendek dan menengah. Gambar di bawah ini menunjukkan bagaimana iPhone 7 dapat membuat peta kedalaman dari dua gambar yang sangat dekat.


Rincian pelaksanaan rekonstruksi tersebut dijelaskan dalam artikel Fotografi 3D Instan , yang disajikan oleh Peter Hedman dan Johannes Kopf di SIGGRAPH2018.

Setelah membuat peta kedalaman berkualitas tinggi, simulasi tiga dimensi menjadi tugas yang hampir sepele. Keterbatasan sebenarnya dari teknik ini adalah bahwa bahkan jika Anda dapat membuat ulang model 3D kasar, itu tidak memiliki informasi tentang cara membuat bagian-bagian yang tidak terlihat dalam foto asli. Saat ini, masalah ini tidak dapat diselesaikan, dan oleh karena itu, semua gerakan yang terlihat dalam foto 3D agak tidak signifikan.

Kami berkenalan dengan konsep foto 3D dan secara singkat berbicara tentang bagaimana smartphone modern dapat membuatnya. Pada bagian kedua, kita akan belajar bagaimana teknik yang sama dapat digunakan untuk mengimplementasikan foto 3D di Unity menggunakan shader.


Bagian 2. Parallax shader dan peta kedalaman


Template shader


Jika kita ingin membuat ulang foto 3D Facebook menggunakan shader, maka kita harus memutuskan apa yang akan kita lakukan. Karena efek ini bekerja paling baik dengan gambar 2D, akan logis untuk mengimplementasikan solusi yang kompatibel dengan sprite Unity. Kami akan membuat shader yang dapat digunakan dengan Sprite Renderer .

Meskipun shader seperti itu dapat dibuat dari awal, seringkali lebih baik untuk memulai dengan template yang sudah jadi. Yang terbaik adalah mulai bergerak maju dengan menyalin spades sprite yang ada, yang digunakan Unity secara default untuk semua sprite. Sayangnya, mesinnya tidak dilengkapi dengan file shader yang dapat Anda edit sendiri.

Untuk mendapatkannya, Anda harus pergi ke arsip unduhan Unity dan unduh paket Built in shaders (lihat di bawah) untuk versi mesin yang Anda gunakan.


Setelah mengekstrak paket, Anda dapat melihat kode sumber dari semua shader yang datang dengan Unity. Kami tertarik pada file Sprite-Diffuse.shader , yang digunakan secara default untuk semua sprite yang dibuat.

Gambar


Aspek kedua yang perlu diformalkan adalah data yang kita miliki. Bayangkan kita memiliki gambar yang ingin kita hidupkan dan peta dalamnya. Yang terakhir akan menjadi gambar hitam dan putih, di mana piksel hitam dan putih menunjukkan seberapa jauh atau dekat mereka dari kamera.

Gambar-gambar yang digunakan dalam tutorial ini diambil dari proyek kucing Pickle Dennis Hotson , dan ini tanpa ragu adalah yang terbaik yang akan Anda lihat hari ini.


Peta ketinggian yang terkait dengan gambar ini mencerminkan jarak moncong kucing dari kamera.


Sangat mudah untuk melihat bagaimana hasil yang baik dapat dicapai dengan peta kedalaman yang sederhana. Ini artinya mudah untuk membuat peta kedalaman Anda sendiri untuk gambar yang ada.

Sifat-sifat


Sekarang setelah kita memiliki semua sumber daya, kita dapat mulai menulis kode shader paralaks. Jika kami mengimpor gambar utama sebagai sprite, maka Unity akan secara otomatis meneruskannya ke shader melalui properti _MainTex . Namun, kita perlu membuat peta kedalaman tersedia untuk shader. Ini dapat diimplementasikan menggunakan properti shader baru yang disebut _HeightTex . Saya sengaja memutuskan untuk tidak menyebutnya _DepthTex agar tidak membingungkannya dengan tekstur kedalaman (ini adalah konsep Unity serupa yang digunakan untuk membuat peta kedalaman adegan).

Untuk mengubah kekuatan efek, kami juga akan menambahkan properti _Scale .

 Properties { ... _HeightTex ("Heightmap (R)", 2D) = "gray" {} _Scale ("Scale", Vector) = (0,0,0,0) } 

Dua properti baru ini juga harus sesuai dengan dua variabel dengan nama yang sama yang perlu ditambahkan ke bagian CGPROGRAM / ENDCG :

 sampler2D _HeightTex; fixed2 _Scale; 

Sekarang semuanya sudah siap, dan kita dapat mulai menulis kode yang akan melakukan offset.

Langkah pertama adalah sampel nilai dari peta kedalaman, yang dapat dilakukan dengan menggunakan fungsi tex2D . Karena _HeightTex adalah tekstur hitam dan putih, kita bisa mengambil saluran merahnya dan membuang sisanya. Nilai yang dihasilkan mengukur jarak dalam beberapa unit acak dari piksel saat ini ke kamera.

Nilai kedalaman antara 0sebelumnya 1tapi kami akan merentangkannya ke interval dari 1sebelumnya +1. Ini memungkinkan Anda untuk memberikan paralaks positif (warna putih) dan negatif (warna hitam).

Teori


Untuk mensimulasikan efek paralaks pada tahap ini, kita perlu menggunakan informasi kedalaman untuk menggeser piksel gambar. Semakin dekat piksel, semakin kuat perlu digeser. Proses ini dijelaskan dalam diagram di bawah ini. Pixel merah dari gambar asli, sesuai dengan informasi dari peta kedalaman, harus bergeser dua piksel ke kiri. Demikian pula, piksel biru harus menggeser dua piksel ke kanan.


Meskipun secara teoritis ini harus bekerja, tidak ada cara mudah untuk menerapkan ini di shader. Masalahnya adalah bahwa shader dengan prinsipnya hanya dapat mengubah warna piksel saat ini . Saat mengeksekusi kode shader, ia harus menggambar piksel tertentu di layar; kita tidak bisa hanya memindahkan piksel ini ke tempat lain atau mengubah warna tetangga. Pembatasan lokalitas ini memberikan operasi paralel shader yang sangat efisien, tetapi tidak memungkinkan kami untuk menerapkan semua jenis efek yang sepele asalkan ada akses acak untuk merekam setiap piksel dalam gambar.

Jika kita ingin akurat, maka kita perlu sampel peta kedalaman semua piksel tetangga untuk mencari tahu yang mana yang harus (jika harus) pindah ke posisi saat ini. Jika beberapa piksel berada di tempat yang sama, maka kita dapat meratakan pengaruhnya. Meskipun sistem seperti itu bekerja dan memberikan hasil terbaik, sistem ini sangat tidak efisien dan berpotensi ratusan kali lebih lambat daripada shader difusi asli yang kami mulai.

Alternatif terbaik adalah solusi berikut: kami mendapatkan kedalaman piksel saat ini dari peta kedalaman; kemudian, jika kita perlu menggesernya ke kanan , maka ganti warna saat ini dengan piksel di sebelah kiri (lihat gambar di bawah). Di sini kita mengasumsikan bahwa jika Anda ingin memindahkan piksel ke kanan, maka piksel tetangga di sebelah kiri juga seharusnya bergerak dengan cara yang sama.


Mudah untuk melihat bahwa ini hanyalah perkiraan biaya rendah dari apa yang benar-benar ingin kami capai. Namun, ini sangat efektif karena peta kedalaman biasanya menjadi halus.

Kode


Dengan mengikuti algoritma yang dijelaskan pada bagian sebelumnya, kita dapat mengimplementasikan paralaks shader dengan offset sederhana dari koordinat UV .

Ini mengarah ke kode berikut:

 void surf (Input IN, inout SurfaceOutput o) { // Displacement fixed height = tex2D(_HeightTex, IN.uv_MainTex).r; fixed2 displacement = _Scale * ((height - 0.5) * 2); fixed4 c = SampleSpriteTexture (IN.uv_MainTex - displacement) * IN.color; ... } 

Teknik ini bekerja dengan baik pada benda yang hampir rata, seperti yang terlihat dalam animasi di bawah ini.


Tapi itu benar-benar bekerja sangat baik dengan model 3D, karena sangat mudah untuk membuat tekstur kedalaman untuk adegan 3D. Di bawah ini adalah gambar yang diberikan 3D dan peta kedalamannya.


Hasil akhir ditunjukkan di sini:

Source: https://habr.com/ru/post/id444706/


All Articles