Membuat SVG Bertekstur Noise
(daniel.do)- Seiring ilustrasi web berkembang melampaui vektor datar ke arah penggunaan tekstur noise serta pencahayaan dan bayangan, cara mewujudkannya dalam SVG yang ringan dan dapat digunakan ulang menjadi semakin penting
- Tujuan utamanya adalah menambahkan efek bayangan bertekstur pada bentuk sederhana, lalu memindahkannya ke komponen Svelte atau React agar warna dan bentuknya bisa diubah dan dipakai ulang
- Struktur dasarnya adalah mendefinisikan bentuk sekali di dalam
<defs>dan menggunakannya kembali dengan<use>, lalu menyusun mask gradien yang tidak terlalu terikat pada warna memakaimaskdanlinearGradient - Kesan berbutir dibuat dengan filter SVG berbasis
<feTurbulence>, lalu dicampur dengan warna isi yang dipilih melalui kombinasi<feComposite>,<feColorMatrix>, dan<feBlend> - Hasilnya sudah mencapai tekstur yang diinginkan, tetapi perbedaan rendering di Safari masih tersisa, sehingga perlu penyesuaian tambahan untuk tampilan lintas browser dan penerapan pada ilustrasi yang lebih kompleks
Menambahkan tekstur noise ke SVG hanya dengan kode
- Dalam desain web belakangan ini, ilustrasi vektor tetap banyak digunakan, tetapi gaya pencahayaan dan bayangan dengan kesan butiran kasar lebih menonjol dibanding bentuk datar yang bersih
- Gaya seperti ini memang bisa diekspor ke SVG dari program ilustrasi, tetapi teksturnya bisa masuk sebagai raster atau ukuran vektornya membesar
- Tujuannya adalah membuat efek bayangan bertekstur dengan noise hanya memakai spesifikasi SVG standar, sambil mempertahankan struktur yang mudah dijadikan komponen
- Susunannya dibuat agar cara yang sama tetap bekerja meski bentuk dan warnanya diganti demi kemudahan penggunaan ulang
Bentuk dasar dan gradien
- Bentuk dasar SVG seperti lingkaran atau persegi mudah digambar, tetapi dalam komponen yang dapat digunakan ulang, gradien warna tetap saja tidak cukup
- Untuk membuat gradien yang berubah mengikuti warna dasar, digunakan mask (masker)
- Mask SVG mengontrol area yang terlihat atau tersembunyi dengan warna hitam dan putih
- Caranya mungkin agak membingungkan, tetapi bisa dimulai dari contoh sederhana
- Jika strukturnya menggunakan bentuk lingkaran yang sama berkali-kali,
<circle id="shape">didefinisikan di dalam<defs>lalu dirujuk dengan<use href="#shape"> - Cara ini mengurangi pengulangan dan mengumpulkan definisi bentuk di satu tempat, sehingga strukturnya tetap DRY
Cara membuat tekstur noise
- Untuk menaruh tekstur di atas gradien, digunakan filter SVG
- Pembuatan noise ditangani oleh
<feTurbulence><feTurbulence>adalah primitive filter SVG untuk membuat tekstur buatan- Untuk mendapatkan nuansa yang diinginkan, berbagai nilainya perlu disetel
- Filter akhirnya mencampurkan tekstur dengan warna melalui beberapa tahap
<feTurbulence type="fractalNoise" baseFrequency="19.5" numOctaves="10">menghasilkan noise<feComposite>mengomposisikan hasil turbulence ke dalamSourceAlpha<feColorMatrix type="luminanceToAlpha">mengurangi variasi warna<feBlend mode="color-burn">menggabungkannya dengan grafik asli
- Filter diterapkan ke elemen
<use>akhir denganfilter="url('#noise')"
Susunan SVG akhir
- Contoh akhir mendefinisikan bentuk, filter, mask, dan gradien bersama-sama di dalam
<defs> - Gradien disusun dengan
linearGradient id="fade"- Titik
0%menggunakan warna hitam denganstop-opacity="0.6" - Titik
65%dan75%menggunakan warna putih untuk menyesuaikan transparansi secara bertahap
- Titik
- Pada bentuk akhir, warna isi, mask, dan filter diterapkan sekaligus
fill="hsl(337, 92%, 69%)"mask="url(#gradient)"filter="url('#noise')"
- Dengan menambahkan warna dan menyetel gradien secara lebih halus, diperoleh hasil yang lebih dekat ke efek visual yang diinginkan
- Hasil lengkapnya bisa dilihat di Full Demo, dan kode implementasinya dibuka di repository
Hasil dan keterbatasan
- Setelah eksperimen tambahan, ilustrasi yang memuaskan berhasil dibuat, tetapi hasilnya belum sepenuhnya sempurna
- Terutama di Safari, rendering-nya berbeda dari browser lain
- Dibandingkan ilustrasi kompleks yang dijadikan referensi, hasil ini masih sederhana, tetapi jika terus dipoles ada kemungkinan bisa dipakai di lebih banyak situasi
- Menurut tambahan pada 7 Desember 2023, setelah dikirim ke Hacker News, penulis mengetahui artikel CSS-Tricks tahun 2021 oleh Jimmy Chion, Grainy Gradients
- Teknik yang dicapai artikel tersebut tampak serupa, sehingga bisa dijadikan bahan pelengkap untuk dirujuk bersama
2 komentar
Seperti biasa, Safari memang tidak pernah mengecewakan! Julukan IE-nya era 2020-an memang sangat pantas.
Opini Hacker News
Belakangan saat mengutak-atik SVG, saya mencoba menambahkan drop shadow yang sulit dibuat dengan canvas, tetapi di Safari drop shadow CSS di dalam SVG tidak berfungsi, jadi harus memakai filter drop shadow native SVG, dan hasilnya juga terlihat berbeda dari browser lain
Contoh konkretnya ada di https://www.einarmagnus.net/pages/logo, dan JavaScript dipakai untuk mendeteksi Safari lalu menyalakan versi SVG dan mematikan versi CSS
Latar “yin-yang rekursif” ada di https://einarmagnus.net/blog/2020/01/22/finding-the-logo
Saya juga ingin bereksperimen lebih jauh dengan tekstur, tetapi frustrasi karena tampilannya di Safari terlalu berbeda. Saya penasaran apakah suatu hari cara interpretasi SVG akan konvergen
Topik ini layak dibaca di https://razrfalcon.github.io/notes-on-svg-parsing/
Di laporan bug library SVG, saya sering melihat ungkapan “SVG saya tidak dirender dengan benar”, tetapi intinya sebenarnya tidak ada yang namanya SVG yang dirender dengan benar. Begitu mulai memakai fitur lanjutan seperti teks, filter, dan animasi, hasilnya mudah rusak berbeda-beda di tiap renderer
Keren melihat bagaimana perubahan kecil pada parameter bisa menghasilkan desain yang cukup berbeda seperti scorpion, balance, dan spruce
Istilah yang dicari penulis lebih dekat ke dithering. “Grainy Gradients” dari CSS-Tricks juga menjelaskan teknik yang sama
https://css-tricks.com/grainy-gradients/
Ada juga alternatif untuk membuat efek serupa dengan CSS, tetapi caranya diterapkan ke seluruh gambar
https://github.com/tomren1/dither-with-css
Dithering adalah teknik yang, saat mengkuantisasi gambar halus dengan kedalaman warna tinggi menjadi jumlah warna terbatas, memilih tiap piksel secara probabilistik menjadi salah satu dari nilai atas atau bawah untuk mengurangi banding. Pada titik yang persis sesuai dengan warna yang diinginkan, efeknya mungkin tidak tampak seperti noise
Di sini yang muncul hanya tekstur noise yang seragam, dan tidak benar-benar mengurangi banding. Untuk tujuan estetika, yang ini tampak lebih baik daripada dithering sungguhan
Namun, seperti dithering, efek ini bisa menutupi cacat dan meningkatkan ketajaman yang dirasakan sehingga kualitas gambar terlihat lebih baik
Penulis tampaknya mencari istilah desain untuk menyebut gaya visual, seperti “flat”, “skeuomorphic”, atau “italian style”
Kombinasi bentuk geometris dan grain mengingatkan saya pada Memphis style
Saya malah teringat seni poster perjalanan vintage. Contoh: https://www.graphicart-news.com/wp-content/uploads/2012/09/2...
[0] https://en.wikipedia.org/wiki/Stippling
Saat membuat ini, saya benar-benar belum melihatnya, dan setelah mencoba sendiri saya sampai pada kesimpulan yang sama
Ini mengingatkan saya pada fotografer film dan pembuat film yang berusaha keras menghilangkan film grain, sementara fotografer digital justru ingin menambahkannya kembali. Rumput tetangga memang selalu lebih hijau
Di tengah segala sesuatu yang secara digital terasa steril, contoh di halaman ini terlihat cukup menarik
Masalahnya bukan noise itu sendiri, melainkan selalu soal apakah jumlahnya terlalu banyak
Apakah ada materi yang merangkum fitur apa saja yang rusak di tiap implementasi? Saya penasaran dengan cara menjaga kesehatan mental saat memakai SVG
Baru-baru ini saya membuat kesalahan dengan membuat poster konferensi yang kompleks dalam SVG, dan sekarang hasil render-nya berbeda-beda di tiap browser dan program
https://kxygk.github.io/imergination/
Hal-hal yang saya alami saat membuatnya seperti ini: kita bisa menyertakan atau menautkan SVG, tetapi kalau di dalamnya ada SVG lain lagi, itu tidak berjalan. Misalnya jika strukturnya poster → diagram → banyak plot/peta, SVG yang diperbarui secara dinamis saat gambar turunannya berubah pada praktiknya mustahil
Browser web juga kadang tidak menampilkan gambar yang di-embed/ditautkan sesuka mereka karena alasan “keamanan”. Jika SVG pada tautan di atas dibuka di tab terpisah, tampilannya tidak benar: https://raw.githubusercontent.com/wiki/kxygk/imergination/ag...
Mengubah SVG yang kompleks menjadi PDF juga sulit dilakukan tanpa ketidaksesuaian, dan kadang memori habis. Tiap konverter SVG-to-PDF memberi hasil yang berbeda
Berbagai implementasi seperti Inkscape kadang memperlakukan SVG yang disertakan secara arbitrer seperti grafik raster, dan saya tidak pernah berhasil memastikan kapan itu terjadi. Ada juga masalah ketika merender ke PNG, Inkscape tidak meneruskan pengaturan DPI ke gambar turunan
Keren. Sepertinya Inkscape mendukung penambahan noise semacam ini lewat berbagai efek di menu Filters. Setelah mengekspor sebagai Plain SVG dan melihat kodenya, terlihat bahwa ia memakai
feTurbulenceSebagai perbandingan, saya juga mencoba noise fill di Affinity Designer 2, dan pada SVG yang diekspor, noise-nya tertanam sebagai gambar JPEG base64
Dari posisi sulit membenarkan lisensi Adobe dan juga kurang cocok dengan InkScape, Designer sebenarnya adalah alternatif yang sempurna kalau bukan karena keanehan-keanehan seperti ini
Di situs web “ApeFest”[1] juga ada noise dinamis, jadi saya melihat CSS-nya. Itu situs acara yang membakar retina para peserta dengan UV
Sebenarnya mereka memakai overlay PNG[2] berbentuk tile, lalu menggoyangkannya dengan animasi CSS agar tampak “acak”. Koreksi: sepertinya sebenarnya digerakkan dengan JS. Cukup low-tech, tapi berfungsi
[1] https://apefest.com/
[2] https://framerusercontent.com/images/rR6HYXBrMmX4cRpXfXUOvpv...
Saya ingin sering memakai filter SVG seperti ini, tetapi masalahnya adalah tampilannya sangat berbeda tergantung engine dan tingkat zoom
Karena itu, filter ini hanya bisa dipakai untuk efek halus ketika ketidakakuratan tidak terlalu penting, dan akhirnya sayangnya saya terus kembali ke raster
Selain itu, karena sifatnya yang bekerja pada level piksel, hal seperti
feDisplacementMapmerusak antialiasing, sehingga merusak kira-kira separuh situasi ketika kita ingin memakainyaPerlin noise dan penerusnya, fractal noise, punya efektivitas biaya yang luar biasa untuk menambah realisme atau kesan organik
Misalnya, kita bisa melihatnya dipakai dengan sangat efektif dalam adegan pelarian dari Cave of Wonders di Aladdin (1992)
Saya tidak tahu seharusnya ini terlihat seperti apa, tetapi di ponsel saya tampil hanya sebagai gradien halus tanpa noise
Saya suka efeknya, tetapi apakah ada cara membuatnya independen dari tingkat zoom?
Terkait itu, sepertinya ini juga menambahkan keacakan, tapi saya juga penasaran apakah ada cara memberi seed. Misalnya, akan bagus jika kita bisa mendefinisikan satu hasil render yang benar pada ukuran tertentu
seed, dan algoritme fungsi acaknya juga didefinisikan dalam spesifikasi sebagai 186 baris kode C[0], jadi secara teori hasilnya harus sama di tiap implementasiNamun jika melihat kodenya, ia memakai operasi floating-point, dan setahu saya itu bersifat implementation-defined, jadi tampaknya ada kemungkinan perilakunya berbeda-beda antarplatform
[0]: https://drafts.fxtf.org/filter-effects/#elementdef-feturbule...