Garis-garis render, kecuali jika Anda hanya membuat total selusin karakter, tetap menjadi "tidak jalan" karena jumlah simpul yang diperlukan per karakter untuk perkiraan kelengkungan. Meskipun telah ada pendekatan untuk mengevaluasi kurva bezier dalam pixel shader, ini menderita karena tidak mudah antialiased, yang sepele dengan menggunakan quad-peta-peta bertekstur, dan mengevaluasi kurva dalam shader masih secara komputasi jauh lebih mahal daripada yang diperlukan.
Pertukaran terbaik antara "cepat" dan "kualitas" masih merupakan paha depan bertekstur dengan tekstur bidang jarak yang telah ditandatangani. Ini sangat sedikit lebih lambat daripada menggunakan quad bertekstur normal biasa, tetapi tidak begitu banyak. Kualitas di sisi lain, berada di stadion baseball yang sama sekali berbeda. Hasilnya benar-benar menakjubkan, secepat yang Anda bisa dapatkan, dan efek seperti cahaya juga mudah ditambahkan. Selain itu, teknik ini dapat diturunkan ke perangkat keras yang lebih lama, jika diperlukan.
Lihat kertas Valve yang terkenal untuk tekniknya.
Teknik ini secara konseptual mirip dengan bagaimana permukaan implisit (metaballs dan semacamnya) bekerja, meskipun tidak menghasilkan poligon. Ini berjalan sepenuhnya dalam pixel shader dan mengambil sampel jarak dari tekstur sebagai fungsi jarak. Segala sesuatu di atas ambang yang dipilih (biasanya 0,5) adalah "dalam", yang lainnya "keluar". Dalam kasus yang paling sederhana, pada perangkat keras yang tidak mampu-shader berusia 10 tahun, menetapkan ambang uji alpha ke 0,5 akan melakukan hal yang tepat (meskipun tanpa efek khusus dan antialiasing).
Jika seseorang ingin menambahkan sedikit lebih berat ke font (faux bold), ambang yang sedikit lebih kecil akan melakukan trik tanpa memodifikasi satu baris kode (cukup ganti seragam "font_weight" Anda). Untuk efek cahaya, seseorang hanya menganggap segala sesuatu di atas satu ambang sebagai "dalam" dan segala sesuatu di atas ambang lainnya (lebih kecil) sebagai "keluar, tetapi dalam cahaya", dan LERP di antara keduanya. Antialiasing bekerja dengan cara yang sama.
Dengan menggunakan nilai jarak yang ditandatangani 8-bit daripada satu bit, teknik ini meningkatkan resolusi efektif peta tekstur Anda 16 kali lipat di setiap dimensi (alih-alih hitam dan putih, semua kemungkinan nuansa digunakan, sehingga kami memiliki 256 kali informasi menggunakan penyimpanan yang sama). Tetapi bahkan jika Anda memperbesar jauh melampaui 16x, hasilnya masih terlihat cukup dapat diterima. Garis-garis lurus panjang pada akhirnya akan menjadi sedikit goyah, tetapi tidak akan ada artefak pengambilan sampel yang "khas".
Anda bisa menggunakan geometri shader untuk menghasilkan paha depan poin (mengurangi bandwidth bus), tapi jujur keuntungannya agak marjinal. Hal yang sama berlaku untuk rendering karakter instan seperti yang dijelaskan dalam GPG8. Ongkos pemasangan hanya diamortisasi jika Anda memiliki banyak teks untuk menggambar. Keuntungannya, menurut saya, tidak ada hubungannya dengan kompleksitas tambahan dan non-downgrade. Plus, Anda dibatasi oleh jumlah register konstan, atau Anda harus membaca dari objek buffer tekstur, yang tidak optimal untuk koherensi cache (dan tujuannya adalah untuk mengoptimalkan untuk memulai dengan!).
Buffer vertex sederhana dan sederhana sama cepat (mungkin lebih cepat) jika Anda menjadwalkan unggahan sedikit lebih cepat dan akan berjalan pada setiap perangkat keras yang dibangun selama 15 tahun terakhir. Dan, itu tidak terbatas pada jumlah karakter tertentu dalam font Anda, atau jumlah karakter tertentu untuk di-render.
Jika Anda yakin tidak memiliki lebih dari 256 karakter dalam font Anda, susunan tekstur mungkin layak dipertimbangkan untuk menghapus bandwidth bus dengan cara yang sama seperti menghasilkan paha depan dari titik-titik dalam shader geometri. Bila menggunakan tekstur array, koordinat tekstur semua paha depan memiliki identik, konstan s
dan t
koordinat dan hanya berbeda dalam r
koordinat, yang sama dengan indeks karakter untuk membuat.
Tetapi seperti teknik lainnya, keuntungan yang diharapkan adalah marjinal dengan biaya yang tidak sesuai dengan perangkat keras generasi sebelumnya.
Ada alat yang berguna oleh Jonathan Dummer untuk menghasilkan tekstur jarak: halaman deskripsi
Pembaruan:
Seperti yang baru-baru ini ditunjukkan dalam Programmable Vertex Pulling (D. Rákos, "OpenGL Insights", hlm. 239), tidak ada latensi atau overhead tambahan yang signifikan terkait dengan menarik data titik secara terprogram dari shader pada GPU generasi terbaru, dibandingkan dengan melakukan hal yang sama menggunakan fungsi tetap standar.
Selain itu, GPU generasi terbaru memiliki cache L2 untuk keperluan umum yang berukuran lebih dan lebih masuk akal (mis. 1536kiB pada nvidia Kepler), jadi orang dapat mengharapkan masalah akses yang tidak koheren ketika menarik offset acak untuk sudut-sudut quad dari tekstur buffer menjadi kurang dari masalah.
Ini membuat ide untuk menarik data konstan (seperti ukuran quad) dari tekstur buffer lebih menarik. Implementasi hipotetis dengan demikian dapat mengurangi PCIe dan transfer memori, serta memori GPU, ke minimum dengan pendekatan seperti ini:
- Hanya unggah indeks karakter (satu per karakter yang akan ditampilkan) sebagai satu-satunya input ke vertex shader yang melewati indeks ini dan
gl_VertexID
, dan perkuat itu hingga 4 poin dalam geometri shader, masih memiliki indeks karakter dan id simpul (ini akan menjadi "gl_primitiveID tersedia di vertex shader") sebagai satu-satunya atribut, dan menangkap ini melalui umpan balik transformasi.
- Ini akan cepat, karena hanya ada dua atribut output (hambatan utama dalam GS), dan dekat dengan "no-op" jika tidak di kedua tahap.
- Mengikat tekstur buffer yang berisi, untuk setiap karakter dalam font, posisi vertex quad bertekstur relatif terhadap titik dasar (ini pada dasarnya adalah "metrik font"). Data ini dapat dikompresi menjadi 4 angka per quad dengan menyimpan hanya offset dari simpul kiri bawah, dan meng-encode lebar dan tinggi kotak yang disejajarkan dengan sumbu (dengan asumsi setengah mengapung, ini akan menjadi 8 byte buffer konstan per karakter - font khas 256 karakter dapat masuk sepenuhnya ke 2kiB dari L1 cache).
- Tetapkan seragam untuk garis dasar
- Ikat tekstur penyangga dengan offset horizontal. Ini bisa bahkan mungkin dihitung pada GPU, tetapi jauh lebih mudah dan lebih efisien untuk hal semacam itu pada CPU, karena ini adalah operasi ketat berurutan dan sama sekali tidak sepele (memikirkan kerning). Selain itu, diperlukan umpan balik umpan balik, yang akan menjadi titik sinkronisasi lain.
- Render data yang dihasilkan sebelumnya dari buffer umpan balik, shader verteks menarik offset horizontal dari titik dasar dan offset sudut sudut dari objek buffer (menggunakan id primitif dan indeks karakter). ID simpul asli dari simpul yang dikirimkan sekarang adalah "ID primitif" kami (ingat GS mengubah simpul menjadi paha depan).
Seperti ini, seseorang idealnya dapat mengurangi bandwidth simpul yang dibutuhkan sebesar 75% (diamortisasi), meskipun itu hanya akan mampu membuat satu baris. Jika seseorang ingin dapat membuat beberapa baris dalam satu panggilan draw, seseorang perlu menambahkan garis dasar ke tekstur buffer, daripada menggunakan seragam (membuat bandwidth bertambah kecil).
Namun, bahkan dengan asumsi pengurangan 75% - karena data titik untuk menampilkan jumlah teks yang "masuk akal" hanya sekitar 50-100kiB (yang praktis nolke GPU atau bus PCIe) - Saya masih ragu bahwa kompleksitas yang ditambahkan dan kehilangan kompatibilitas ke belakang benar-benar sepadan dengan masalahnya. Mengurangi nol hingga 75% masih hanya nol. Saya akui tidak mencoba pendekatan di atas, dan dibutuhkan lebih banyak penelitian untuk membuat pernyataan yang benar-benar berkualitas. Tapi tetap saja, kecuali seseorang dapat menunjukkan perbedaan kinerja yang benar-benar menakjubkan (menggunakan jumlah teks "normal", bukan milyaran karakter!), Sudut pandang saya tetap bahwa untuk data vertex, buffer vertex lama yang sederhana, cukup dibenarkan cukup baik untuk dianggap sebagai bagian dari "solusi canggih". Sederhana dan mudah, itu bekerja, dan itu bekerja dengan baik.
Setelah mereferensikan " OpenGL Insights " di atas, ada baiknya juga menunjukkan bab "2D Shape Rendering by Distance Fields" oleh Stefan Gustavson yang menjelaskan render bidang jarak dengan sangat rinci.
Pembaruan 2016:
Sementara itu, ada beberapa teknik tambahan yang bertujuan untuk menghapus artefak pembulatan sudut yang menjadi mengganggu pembesaran ekstrim.
Satu pendekatan hanya menggunakan bidang jarak pseudo bukan bidang jarak (perbedaannya adalah bahwa jarak adalah jarak terpendek tidak ke garis sebenarnya, tetapi ke garis atau garis imajiner yang menonjol di tepi). Ini agak lebih baik, dan berjalan pada kecepatan yang sama (shader identik), menggunakan jumlah memori tekstur yang sama.
Pendekatan lain menggunakan median-of-three dalam detail tekstur tiga saluran dan implementasi yang tersedia di github . Ini bertujuan untuk menjadi perbaikan atas dan-atau peretasan yang digunakan sebelumnya untuk mengatasi masalah ini. Kualitas bagus, sedikit, hampir tidak terasa, lebih lambat, tetapi menggunakan memori tekstur tiga kali lebih banyak. Selain itu, efek tambahan (misalnya cahaya) lebih sulit untuk diperbaiki.
Terakhir, menyimpan kurva bezier yang sebenarnya membentuk karakter, dan mengevaluasinya dalam shader fragmen telah menjadi praktis , dengan kinerja yang sedikit lebih rendah (tapi tidak terlalu masalah) dan hasil yang menakjubkan bahkan pada perbesaran tertinggi.
Demo WebGL rendering PDF besar dengan teknik ini secara real time tersedia di sini .