- LUT (lookup table) adalah metode untuk merujuk nilai yang sudah dihitung sebelumnya seperti tabel, dan digunakan secara luas mulai dari pewarnaan video termal hitam-putih hingga variasi objek game dan color grading video
- Contoh WebGL menunjukkan alur mengunggah frame video ke GPU sebagai tekstur 2D, lalu menerapkan tinting, LUT 1D, dan LUT 3D di Fragment Shader yang menentukan warna per piksel
- LUT 1D menggunakan nilai kecerahan
[0.0 - 1.0]sebagai koordinat array warna untuk mengubah input hitam-putih menjadi RGB, dan filtering bilinear GPU menginterpolasi nilai antara secara alami meski LUT berukuran kecil - Seperti contoh Left 4 Dead dari Valve, tinting dan LUT dimanfaatkan untuk membuat variasi mobil, kulit zombi, dan warna pakaian di dalam batasan memori tekstur
- LUT memang menambah biaya pembacaan tekstur, tetapi merupakan alat praktis untuk menyimpan sebelumnya perhitungan mahal seperti koreksi gamma atau membawa workflow color grading eksternal ke grafis real-time
Peran LUT dalam Pemrograman Grafis
- Lookup table (LUT) adalah metode menghitung nilai terlebih dahulu, menyimpannya dalam baris atau tabel, lalu merujuknya saat diperlukan
- Dalam pemrograman grafis, struktur sederhana ini dapat menghasilkan berbagai efek visual
- Mengubah video hitam-putih menjadi berwarna
- Menerapkan koreksi warna dan styling
- Membuat variasi objek dalam video game secara efisien
- Contohnya menggunakan WebGL, tetapi teknik yang sama juga dapat diterapkan pada DirectX, OpenGL, Vulkan, Unity, dan visualisasi data ilmiah
- Video demo adalah tangkapan dari Panasonic GH6 dan kamera termal TESTO 890, dan prosesnya dilakukan secara lokal di GPU tanpa keluar dari perangkat
Pipeline WebGL dan tinting
- Output kamera termal adalah video hitam-putih, dan setiap frame dikirim ke GPU melalui WebGL sebagai tekstur 2D
- Fragment Shader adalah kode yang menentukan warna akhir untuk setiap fragment pada output
- Dalam contoh, warna video pada posisi saat ini dibaca dengan
texture2D(video, tex).rgb - Output akhir WebGL 1.0 ditulis sebagai RGBA ke
gl_FragColor
- Dalam contoh, warna video pada posisi saat ini dibaca dengan
- Tinting adalah metode memberi rona dengan mengalikan warna tekstur dengan warna tertentu
- Dalam contoh, warna oranye dikalikan dengan
videoColor * vec3(1.0, 0.5, 0.0) - Putih menjadi oranye, sedangkan hitam tetap hitam karena dikalikan 0
- Dalam contoh, warna oranye dikalikan dengan
- Dalam konteks ini, biaya perkalian untuk tinting bisa sulit diukur
- Biaya mengambil tekstur dari memori jauh lebih besar daripada perkalian
- Saat banyak thread berjalan paralel, perkalian untuk piksel lain dapat dilakukan sementara menunggu pembacaan tekstur sebuah piksel
- Ini menjelaskan perbedaan yang dibuat tinting, bukan berarti optimisasi performa keseluruhan sudah selesai
Pemanfaatan tinting oleh Valve
- Left 4 Dead dari Valve Software memanfaatkan tinting untuk membuat variasi mobil
- Menyediakan tekstur terpisah untuk setiap jenis dan warna mobil dapat melampaui anggaran memori tekstur
- Valve menggunakan tekstur mask tambahan untuk melakukan tinting pada area cat mobil dengan warna berbeda per instance
- Satu tekstur warna dibagikan oleh 3 model mobil
- Dengan biaya dua tekstur, mereka dapat membuat 4 model mobil dan variasi warna yang pada dasarnya tidak terbatas
- Di Source Engine, bukan hanya mobil; pada dasarnya semua hal dapat diberi tinting
Mengubah nilai hitam-putih menjadi warna dengan LUT 1D
- LUT 1D adalah array angka; untuk gambar RGB, ini adalah array satu dimensi berisi warna
- Nilai kecerahan video hitam-putih digunakan sebagai koordinat sumbu X LUT untuk mengambil warna
- Nilai kecerahan video berada dalam rentang
[0.0 - 1.0] - Hitam
0.0dipetakan ke warna di sisi kiri LUT, dan putih1.0ke warna di sisi kanan LUT - Nilai tengah dipetakan ke warna pada posisi yang sesuai
- Nilai kecerahan video berada dalam rentang
- Karena WebGL 1.0 tidak memiliki tekstur 1D, digunakan tekstur 2D dengan tinggi 1px
- Kode contoh berbentuk
texture2D(lut, vec2(videoColor, 0.5)) - Karena input adalah nilai 1D dan output adalah RGB, strukturnya adalah “1D vector in, 3D vector out”
- Kode contoh berbentuk
- Filtering bilinear GPU secara otomatis menginterpolasi nilai antara saat pembacaan tekstur
- Video hitam-putih 8-bit memiliki 256 tingkat kecerahan
- Meski LUT 1D hanya selebar 32 piksel, akses di antara piksel akan diinterpolasi secara linear
- Bahkan dengan informasi 8 piksel saja, hasilnya bisa mendekati gradien penuh warna selebar 256 piksel
Pemilihan colormap dan keseragaman perseptual
- Contoh mencakup daftar colormap yang didukung matplotlib dan diekspor sebagai LUT 1D
- Jika data tidak memiliki struktur tertentu, sebaiknya gunakan colormap yang seragam secara perseptual atau atur warna berdasarkan prinsip tersebut
- Seri viridis adalah contoh representatif
- Colormap yang seragam secara perseptual tetap membuat bagian dingin tampak gelap dan bagian panas tampak terang meski dicetak hitam-putih
- Colormap seperti jet, yang terutama hanya mengubah hue dan mengabaikan kecerahan perseptual, tidak menjamin sifat ini
- Kemampuan orang dengan gangguan penglihatan warna untuk menafsirkan data dengan benar juga merupakan kriteria penting dalam memilih colormap
Performa LUT 1D dan aproksimasi polinomial
- Biaya LUT 1D kecil umumnya bisa rendah, tetapi ada lebih banyak hal yang perlu dipertimbangkan dibanding tinting
- Kekhawatiran performa utama adalah pembacaan tekstur dependen
- Hasil pembacaan tekstur pertama menentukan koordinat pembacaan tekstur kedua
- Dalam pemrograman grafis, ini adalah pola yang dapat menghilangkan sebagian jalur yang bisa dioptimalkan
- GPU memiliki cache tekstur, dan LUT kecil dapat masuk ke cache sehingga biaya pembacaan LUT bisa sangat rendah
- Penilaian performa yang rinci memerlukan alat analisis khusus per platform
- Nvidia NSight menyediakan analisis performa per tahap shader, tetapi tidak mendukung OpenGL
- Jika colormap diimplementasikan sebagai aproksimasi polinomial, tidak perlu menangani tekstur LUT
- Aproksimasi viridis ShaderToy dari Matt Zucker ditulis dalam bentuk Horner’s method
- Warna dihitung dengan operasi multiply-add berbentuk
c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6))))) - Apakah ini benar-benar lebih cepat daripada LUT sulit dinilai tanpa analisis per platform
Variasi zombi di Left 4 Dead 2
- Left 4 Dead 2 menggunakan LUT untuk variasi warna kulit dan pakaian yang tidak cukup dicapai dengan tinting sederhana
- Tinting sederhana mungkin tidak menyediakan variasi luminans warna yang cukup
- Untuk kulit dan pakaian, beberapa LUT dipilih secara acak untuk membuat berbagai variasi warna
- Artist memilih color ramp yang sesuai untuk dimasukkan ke game final
- Dari satu tekstur, bisa dibuat variasi setelan jas terang dan setelan jas gelap sekaligus
- Presentasi lengkap terkait dapat dilihat di Shading a Bigger Better Sequel dari GDC
- “Exclusive Masking” adalah cara memasukkan dua rentang tekstur ke dalam satu channel
- Texture 1 berada dalam rentang 0-128
- Texture 2 berada dalam rentang 128-256
- Biayanya adalah berkurangnya presisi warna
LUT 1D untuk menyimpan perhitungan sebelumnya
- LUT 1D juga dapat digunakan dalam pemrograman grafis sebagai cache untuk perhitungan mahal
- Gamma correction adalah contoh representatif
- Jika bukan aproksimasi, diperlukan fungsi
pow() - Terutama pada GPU lama,
pow()bisa menjadi instruksi yang mahal - Jika menggunakan kurva piecewise sRGB standar, jalur branch juga bertambah
- Jika bukan aproksimasi, diperlukan fungsi
- Dengan menghitung transformasi gamma terlebih dahulu sebagai LUT 1D, perhitungan per piksel dapat dilewati
- Dalam kasus ini, strukturnya adalah “1D vector in, 1D vector out”
- LUT 1D dapat menghasilkan hingga 4 channel warna
- Redshift adalah contoh software yang mengurangi kelelahan mata dengan memberi tint oranye pada monitor pada malam hari
- Mengubah Gamma Ramp untuk channel Red, Green, dan Blue monitor
- Perhitungan Kelvin Warmth → RGB dan Gamma tambahan dihitung terlebih dahulu dalam 3 LUT 1D
- Implementasi terkait ada di kode sumber Redshift
- Dengan cara ini, remapping dilakukan di monitor, bukan kartu grafis, sehingga tidak berdampak pada performa, tetapi dukungan antarmuka hardware saat ini sering goyah atau rusak
- Stack grafis Raspberry Pi pernah kehilangan dukungan terkait dalam pembaruan baru
- Microsoft memperingatkan penggunaan SetDeviceGammaRamp
LUT 3D: memetakan ulang seluruh ruang RGB
- LUT 3D merepresentasikan seluruh ruang RGB sebagai satu kubus dan memetakan ulang semua warna yang mungkin
- Karena mengubah vektor RGB tiga dimensi input menjadi vektor RGB tiga dimensi output, strukturnya adalah “3D vector in, 3D vector out”
- Jika LUT 1D diterapkan masing-masing pada Red, Green, dan Blue, keseimbangan warna dapat diubah
- LUT 3D diperlukan untuk transformasi yang membutuhkan kombinasi RGB input
- Perubahan saturasi
- Perubahan hue
- Penyesuaian warna tertentu
- Pemisahan warna
- LUT 3D biasanya berbentuk kubus; dalam game disimpan dalam bentuk strip atau square, dan dalam alat pengeditan video digunakan sebagai file “Iridas/Adobe”
.cube
Mengimplementasikan LUT 3D di WebGL 1.0
- Video pada contoh adalah footage dengan profil warna Panasonic V-Log yang direkam menggunakan Panasonic GH6
- V-Log adalah profil log yang mempertahankan lebih banyak dynamic range serta memiliki definisi Gamut dan Gamma yang jelas
- Karena WebGL 1.0 tidak mendukung tekstur 3D, pembacaan tekstur 3D diimplementasikan dengan dua pembacaan tekstur 2D dan interpolasi
- Pendekatan ini didasarkan pada presentasi Google I/O 2011 oleh Gregg Tavares dan penjelasan webglfundamentals.org
- Kode contoh lama memiliki kesalahan pada perhitungan sumbu Z kubus yang membuat warna bergeser kebiruan, dan diperbaiki pada 2019
- Untuk menjaga kompatibilitas di WebGL 1.0, OpenGLES 2, dan OpenGL 2.1 tanpa
OES_texture_3D, gunakan versi terbaru kode sampling tekstur 3D
Membawa workflow color grading dengan LUT 3D
- Koreksi yang diterapkan pada LUT 3D akan diterapkan apa adanya pada video atau scene grafis yang melewati LUT tersebut
- Dalam contoh, video V-Log dan LUT dibawa ke DaVinci Resolve untuk diproses
- Menerapkan V-Log to V-709 3D-LUT dari Panasonic
- Mengoreksi kontras dan white point agar putih menjadi full-bright
- Mengekspor kembali LUT yang sudah dikoreksi
- Video sebenarnya tetap berupa sumber asli, sementara color grading diterapkan secara real-time di WebGL melalui LUT
- LUT yang diunggah harus mempertahankan ukuran yang sama
- Batasan contoh adalah 1024px × 32px
- Bentuk kubus 32³px harus dipertahankan
Cara industri game menggunakan LUT 3D
- Menggunakan LUT 3D untuk menata warna game di alat eksternal adalah workflow standar yang sudah dikenal luas di industri video game
- Prosedur umumnya adalah sebagai berikut
- Ambil screenshot scene yang akan dikoreksi warnanya
- Buka screenshot dan LUT 3D yang sudah diinisialisasi bersama-sama di alat seperti Photoshop
- Terapkan koreksi warna yang sama pada screenshot dan LUT
- Potong bagian LUT 3D lalu ekspor
- Left 4 Dead juga menggunakan cara yang sama
- Alat koreksi warna Photoshop dapat digunakan dengan bebas, tetapi filter yang mengubah hubungan antar beberapa piksel tidak dapat digunakan
- Keluarga convolution seperti blur, sharpen, dan emboss dapat membuat remapped color menjadi buram dan menghasilkan hasil tak terduga
Membakar color grading kompleks menjadi satu LUT
- Alat color grading seperti DaVinci Resolve dapat membuat transformasi warna dan color grade yang kompleks lalu mengekspornya sebagai LUT 3D
- Contoh menerapkan LUT Kodak 2383 yang menargetkan tampilan film print
- Mengubah video gamma V-Log menjadi Cineon Film Log
- Mengubah ruang warna ke Rec.709
- Menerapkan emulasi film dan mengubah gamma kembali ke Rec.709
- Terakhir, menyesuaikan white point
- Tanpa mengimplementasikan transformasi detail yang kompleks secara langsung, semuanya dapat dibakar menjadi satu LUT dan dibawa ke aplikasi grafis
- Video contoh menggunakan format kompresi tinggi 8-bit demi kompatibilitas artikel, tetapi umumnya pekerjaan ini dilakukan pada footage 10-bit
- Ukuran LUT yang digunakan lebih kecil dari yang mungkin dibayangkan
- Panasonic V-Log to V-709 3D-LUT resmi berukuran 33³px
- LUT monitoring dalam kamera Panasonic menggunakan 17³px
- Bahkan kamera sinema Panasonic dengan harga puluhan ribu dolar AS juga menggunakan 17³px
Contoh LUT di luar grafis
- LUT juga digunakan di luar pemrograman grafis
- LUT turut dimanfaatkan dalam kasus porting Tomb Raider ke Game Boy Advance
- Port engine open-source OpenLara memproses banyak hal lewat software karena Game Boy Advance tidak memiliki fungsi 3D
- Salah satunya adalah LUT untuk mengimplementasikan pembagian bilangan bulat
- LUT ini ditempatkan di bagian awal ruang alamat ROM untuk melewati load instruction
1 komentar
Opini Hacker News
Rasanya efek ini sama sekali tidak akan bisa diimplementasikan tanpa lookup table: https://twitter.com/zeta0134/status/1756988843851383181
Intinya adalah memakai dua lookup table. Tabel besar menyimpan informasi pencahayaan berbentuk lingkaran dalam radius yang dapat dikonfigurasi di sekitar pemain, dan ada satu tabel utuh untuk setiap radius. Tabel kedua berisi urutan pseudo-acak untuk baris latar belakang. Setiap kali rutinitas pencahayaan obor dipanggil, waktunya hanya cukup untuk memperbarui 1/20 layar, tetapi dengan sedikit mengacak urutannya, tepinya terlihat halus dan raster scan yang semestinya tampak bisa disembunyikan. Urutan ini adalah semacam grab bag agar tidak ada baris yang kelaparan pembaruan, sehingga karena komputasi real-time terlalu lambat, dipakailah tabel
Efek lookup table pertama yang benar-benar membuat saya terkesan adalah cara memakainya untuk membuat texture tunnel
Untuk setiap piksel di layar, ada lookup table yang berisi sudut dan jaraknya dari pusat layar, lalu itu dipakai untuk memilih texel apa yang diletakkan di posisi tiap piksel. Hasilnya tampak seperti bergerak di dalam terowongan geometri 3D, tetapi biayanya sangat rendah sehingga bisa dilakukan bahkan di pico: https://www.lexaloffle.com/bbs/?pid=63818
Awalnya saya mengira Stardust memakai efek ini, tetapi setelah baru saja mencarinya, ternyata sebenarnya hanya memutar animasi 6 frame yang berulang di latar belakang: https://codetapper.com/amiga/sprite-tricks/stardust/
https://web.engr.oregonstate.edu/~mjb/cs557/Projects/Papers/Parallax_Occlusion_Mapping.pdf
Ada video tentang bagaimana Wind Waker memakai beberapa LUT untuk menciptakan tampilan yang khas. BoTW dan ToTK juga memakai teknik yang sama
https://www.youtube.com/watch?v=mnxs6CR6Zrk
Saya penulis artikelnya. Kalau ada pertanyaan, saya bisa menjawab
Namun cara artikel ini memperkenalkan color grading berbasis LUT agak mengejutkan. Di artikel, itu terlihat seperti solusi niche keren yang dipakai L4D2, tetapi sebenarnya sudah lama menjadi standar industri dan dipakai di semua game yang pernah saya kerjakan. Dari game AAA seperti NFS (2015) sampai game indie besar seperti Lost in Random, semuanya begitu
[1] https://www.copetti.org/writings/consoles/game-boy-advance/#operating-system
“Here is every single colormap that matlibplot supports,...”
Bahkan di ranah proses bisnis yang membosankan, hal ini ternyata sangat berguna
Sering kali codebase yang penuh conditional bisa disederhanakan menjadi lookup table yang rapi. Mungkin orang tidak selalu terpikir karena sesuatu yang tampak sederhana pun bisa menjadi lookup table 50 ribu baris. Bagi pengguna akhir itu mungkin terlihat banyak, tetapi komputer tidak terlalu peduli. Selain itu, lookup table bersifat repetitif sehingga biasanya mudah dikelola, dan sekalipun tidak, tetap saja bernilai. Pengguna akhir juga bisa mengonfigurasinya tanpa perubahan kode. Secara keseluruhan, ini konsep yang sangat berguna untuk berbagai skenario yang selalu muncul saat mengoding business logic
Game retro sangat sering memakai tabel. Pada masa itu, kecepatan memori sangat tinggi sementara prosesornya lambat, jadi masuk akal untuk memindahkan sebanyak mungkin perhitungan ke tabel. Makin cerdik caranya, makin megah game yang bisa dibuat
Saya suka kanal itu. Ia mengutak-atik seluruh kode Mario 64 agar mod-nya berjalan lebih cepat, sampai bisa stabil di 60 FPS [0]
[0] https://www.youtube.com/watch?v=t_rzYnXEQlE
Kalau banyak berurusan dengan LUT, saya sedang membuat aplikasi Mac untuk menangani ilmu warna tingkat lanjut dan pekerjaan konversi: https://videovillage.com/lattice
Dulu saya sempat sedikit mendalami skena homebrew NES, dan melihat efek fisika yang menakjubkan di game bernama Bobl, jauh melampaui apa yang tampaknya bisa dihitung sistem itu. Ternyata itu adalah tabel lookup, dan saya menyadari bahwa alat sederhana bisa membuat sesuatu tampak seperti proses yang sangat kompleks
https://morphcatgames.itch.io/bobl
A Podcast Of Unnecessary Detail merilis episode yang membahas porting Doom ke SNES dan bagaimana LUT dipakai untuk fungsi trigonometri. Konteksnya adalah SNES tidak memiliki prosesor grafis
https://festivalofthespokennerd.com/podcast/series-3-episode-4/
https://github.com/RandalLinden/DOOM-FX
PPU itu juga bisa melakukan rotasi dan scaling background. Itulah Mode 7—bayangkan Mario Kart—dan juga mendukung transparansi hardware yang terlihat di banyak game. Selain itu, untuk Doom dan Starfox, kartridnya berisi chip Super FX yang menangani perhitungan 3D. Jadi pada judul tertentu itu, pada dasarnya mereka berurusan dengan dua prosesor grafis
Ada seri Retro Game Mechanics Explained yang membahas hardware SNES dengan sangat bagus sekaligus menyakitkan saking detailnya:
https://www.youtube.com/watch?v=57ibhDU2SAI&list=PLHQ0utQyFw5KCcj1ljIhExH_lvGwfn6GV&index=1
Penggunaan LUT yang pernah saya buat dan langsung teringat antara lain hamburan atmosfer, pewarnaan sprite, scope night vision, scope FLIR, efek “video feed” hitam-putih, efek glitch, shading heightmap, koefisien titik alfa untuk plume knalpot pesawat luar angkasa, heatmap dwell mouse pengunjung situs web, efek kristalin, dan terakhir pewarnaan post-processing dalam ruang warna mentah
LUT adalah visualisasi atas array nilai yang sudah diketahui, dan ternyata sangat berguna
http://www.effectgames.com/demos/canvascycle/
Xbox pertama tidak terlalu bisa melakukannya, dan Photoshop juga tidak mendukungnya, sehingga popularitasnya meredup. Namun hardware modern cukup mampu menangani palette swap yang dibuat di AESprite