Sudah ada sejumlah pertanyaan tentang rendering teks di OpenGL, seperti:
Tetapi sebagian besar yang dibahas adalah membuat paha depan bertekstur menggunakan pipa fungsi tetap. Tentunya shader harus membuat cara yang lebih baik.
Saya tidak terlalu peduli tentang internasionalisasi, sebagian besar string saya akan menjadi label centang plot (tanggal dan waktu atau murni numerik). Tetapi plot akan dirender ulang pada kecepatan refresh layar dan mungkin ada cukup banyak teks (tidak lebih dari beberapa ribu mesin terbang di layar, tetapi cukup bahwa tata letak yang dipercepat perangkat keras akan menyenangkan).
Apa pendekatan yang direkomendasikan untuk rendering teks menggunakan OpenGL modern? (Mengutip perangkat lunak yang ada menggunakan pendekatan adalah bukti yang baik bahwa itu bekerja dengan baik)
- Geometri shader yang menerima misalnya posisi dan orientasi serta urutan karakter dan memancarkan paha depan bertekstur
- Geometri shader yang membuat font vektor
- Seperti di atas, tetapi menggunakan shading tessellation sebagai gantinya
- Sebuah penghitung komputasi untuk melakukan rasterisasi font
Jawaban:
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
dant
koordinat dan hanya berbeda dalamr
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:
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.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 .
sumber
clip(...)
saluran denganif (text.a < 0.5) {discard;}
(atautext.a < threshold
). HTH.http://code.google.com/p/glyphy/
Kelemahannya adalah kodenya untuk iOS dengan OpenGL ES. Saya mungkin akan membuat port Windows / Linux OpenGL 4.x (semoga penulis akan menambahkan beberapa dokumentasi nyata).
sumber
Teknik yang paling luas masih quads bertekstur. Namun pada tahun 2005 LORIA mengembangkan sesuatu yang disebut tekstur vektor, yaitu rendering grafik vektor sebagai tekstur pada primitif. Jika seseorang menggunakan ini untuk mengubah font TrueType atau OpenType ke dalam tekstur vektor, Anda akan mendapatkan ini:
http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005
sumber
Saya terkejut bayi Mark Kilgard, NV_path_rendering (NVpr), tidak disebutkan oleh siapa pun di atas. Meskipun tujuannya lebih umum daripada rendering font, itu juga dapat membuat teks dari font dan dengan kerning. Bahkan tidak memerlukan OpenGL 4.1, tetapi ini adalah ekstensi vendor / Nvidia saja saat ini. Ini pada dasarnya mengubah font menjadi jalur menggunakan
glPathGlyphsNV
yang bergantung pada pustaka freetype2 untuk mendapatkan metrik, dll. Kemudian Anda juga dapat mengakses info kerning denganglGetPathSpacingNV
dan menggunakan mekanisme render jalur umum NVpr untuk menampilkan teks dari menggunakan path yang "dikonversi" font. (Saya mencantumkannya dalam tanda kutip, karena tidak ada konversi nyata, kurva digunakan apa adanya.)The demo rekaman untuk kemampuan huruf NVpr ini sayangnya tidak terlalu mengesankan. (Mungkin seseorang harus membuat satu di sepanjang garis demo SDF jauh lebih manis yang dapat ditemukan di intertubes ...)
Pembicaraan presentasi API NVpr 2011 untuk bagian font dimulai di sini dan berlanjut di bagian selanjutnya ; agak disayangkan bagaimana presentasi itu terpecah.
Lebih banyak materi umum tentang NVpr:
Dan karena kata "stensil" tidak menghasilkan hit di halaman ini sebelum jawaban saya, tampaknya bagian dari komunitas SO yang berpartisipasi di halaman ini sejauh, meskipun cukup banyak, tidak menyadari bebas-tessellation, stensil-buffer- metode berbasis untuk rendering jalur / font secara umum. Kilgard memiliki posting seperti FAQ di forum terbuka yang dapat menjelaskan bagaimana metode rendering jalur tessellation bebas berbeda dari grafis 3D standar rawa, meskipun mereka masih menggunakan GPU [GP]. (NVpr membutuhkan chip yang mampu CUDA.)
Untuk perspektif sejarah, Kilgard juga penulis klasik "A Simple OpenGL-based API untuk Texture Mapped Text", SGI, 1997 , yang tidak harus bingung dengan NVpr berbasis stensil yang memulai debutnya pada tahun 2011.
Kebanyakan jika tidak semua metode terbaru dibahas pada halaman ini, termasuk metode berbasis stensil seperti NVpr atau metode berbasis SDF seperti GLyphy (yang saya tidak membahas di sini lebih jauh karena jawaban lain sudah membahasnya) memiliki satu batasan: mereka adalah cocok untuk tampilan teks besar pada monitor konvensional (~ 100 DPI) tanpa jaggy pada semua tingkat penskalaan, dan mereka juga terlihat bagus, bahkan pada ukuran kecil, pada DPI tinggi, tampilan seperti retina. Mereka tidak sepenuhnya menyediakan apa yang Microsoft Direct2D + DirectWrite berikan kepada Anda, yaitu mengisyaratkan mesin terbang kecil pada tampilan utama. (Untuk survei visual yang mengisyaratkan secara umum, lihat halaman typotheque ini misalnya. Sumber daya yang lebih mendalam ada di antigrain.com .)
Saya tidak mengetahui adanya hal-hal berbasis OpenGL yang terbuka & diproduksi yang dapat melakukan apa yang dapat dilakukan Microsoft dengan mengisyaratkan pada saat ini. (Saya akui ketidaktahuan pada internal OS X GL / Quartz Apple, karena sejauh pengetahuan saya Apple belum menerbitkan bagaimana mereka melakukan font rendering path / font berbasis GL. Tampaknya OS X, tidak seperti MacOS 9, tidak lakukan petunjuk sama sekali, yang mengganggu beberapa orang .) Bagaimanapun, ada satu makalah penelitian 2013 yang membahas mengisyaratkan melalui shader OpenGL yang ditulis oleh Nicolas P. Rougier dari INRIA; mungkin perlu dibaca jika Anda perlu melakukan petunjuk dari OpenGL. Walaupun kelihatannya sebuah perpustakaan seperti freetype sudah melakukan semua pekerjaan ketika datang untuk mengisyaratkan, itu sebenarnya tidak begitu karena alasan berikut, yang saya kutip dari makalah:
Solusinya tidak sepele, jadi saya tidak akan mencoba menjelaskannya di sini. (Makalah ini akses terbuka.)
Satu hal lain yang saya pelajari dari makalah Rougier (dan yang sepertinya tidak dipertimbangkan oleh Kilgard) adalah bahwa kekuatan font yang (Microsoft + Adobe) telah ciptakan bukan hanya satu tetapi dua metode spesifikasi kerning. Yang lama didasarkan pada apa yang disebut tabel kern dan didukung oleh jenis bebas. Yang baru disebut GPOS dan hanya didukung oleh pustaka font yang lebih baru seperti HarfBuzz atau pango di dunia perangkat lunak bebas. Karena NVpr tampaknya tidak mendukung salah satu dari pustaka tersebut, kerning mungkin tidak berfungsi dengan NVpr untuk beberapa font baru; ada beberapa yang tampaknya ada di alam liar, menurut diskusi forum ini .
Akhirnya, jika Anda perlu melakukan layout teks kompleks (CTL) Anda saat ini tampaknya kurang beruntung dengan OpenGL karena tidak ada perpustakaan berbasis OpenGL tampaknya ada untuk itu. (DirectWrite di sisi lain dapat menangani CTL.) Ada perpustakaan open-source seperti HarfBuzz yang dapat membuat CTL, tapi saya tidak tahu bagaimana Anda membuatnya bekerja dengan baik (seperti menggunakan metode berbasis stensil) melalui OpenGL. Anda mungkin harus menulis kode lem untuk mengekstrak garis bentuk ulang dan memasukkannya ke dalam solusi berbasis NVpr atau SDF sebagai jalur.
sumber
Saya pikir taruhan terbaik Anda adalah melihat ke dalam grafik Kairo dengan OpenGL backend.
Satu-satunya masalah yang saya miliki ketika mengembangkan prototipe dengan core 3.3 sudah tidak digunakan lagi di OpenGL. Itu 1-2 tahun yang lalu jadi situasinya mungkin telah membaik ...
Bagaimanapun, saya berharap di masa depan driver grafis opengl desktop akan mengimplementasikan OpenVG.
sumber