Troika: Garis Besar Teks

Dibuat pada 20 Agu 2020  ·  39Komentar  ·  Sumber: protectwise/troika

Saya mencoba mencari cara membuat garis teks hitam di sekitar teks putih sehingga teks dapat dengan mudah dibaca. Saya tidak yakin, tapi sepertinya saya perlu menggunakan shader untuk berhubungan dengan troika-three-text? Bisakah Anda memberikan beberapa panduan tentang cara mencapai efek ini?

Terima kasih!

Komentar yang paling membantu

Terima kasih atas info tentang Mapbox, @anzorb. Saya pasti akan memeriksa implementasinya lebih dekat, tetapi dari posting blog itu (mereka menyebut garis besar "halo") sepertinya mereka menggunakan pendekatan ambang alfa SDF seperti yang saya sebutkan sebelumnya. Tetapi generasi SDF dan strategi pengemasan atlas mereka berbeda dari milik saya dan tidak memiliki masalah yang sama dengan ukuran bidang jarak yang tidak seragam per mesin terbang. Itu mungkin akan memiliki batasan lebar garis maksimum yang sama.

Saya sebenarnya telah membuat beberapa kemajuan pada garis besar _screen space_ menggunakan turunan standar. Ruang layar yang berarti garis besarnya adalah misalnya lebar 1 piksel layar terlepas dari ukuran/skala atau kemiringan teks. Jika tujuannya hanya untuk menambahkan kontras dengan latar belakang, sepertinya itu mungkin sama baiknya dengan (atau bahkan lebih baik) menguraikan skala itu bersama dengan ukuran teks. Apakah Anda memiliki pendapat tentang itu?

Semua 39 komentar

Saya hampir merasa mungkin apa yang saya butuhkan telah dipenuhi oleh flag debugSDF, jika saja saya bisa mewarnainya.
image
Menampilkan sdf pada dasarnya memberi saya garis besar yang mungkin akan berfungsi jika saya bisa mewarnainya, menyesuaikan ukurannya, dan berpotensi membuatnya sedikit lebih tajam.

Ini seharusnya tidak terlalu sulit untuk dilakukan. Saya mulai bermain dengan textOutline sebagai fitur beberapa waktu lalu tetapi tidak pernah menyelesaikannya.

Secara teori, tepi mesin terbang dapat diperluas hanya dengan mengubah nilai dalam bidang jarak bertanda yang sesuai dengan tepi. Itu 0.5 dalam kode shader saat ini , tetapi itu dapat dibuat dapat dikonfigurasi dengan meneruskannya sebagai seragam.

Idealnya shader dapat menangani menggambar kedua mesin terbang normal ditambah garis luar apa pun di sekitarnya dalam satu panggilan undian, jadi Anda memerlukan beberapa seragam baru: lebar garis besar (tidak yakin unit apa yang akan digunakan?), dan warna daerah garis besar.

Saya mulai bermain dengan textOutline sebagai fitur beberapa waktu lalu tetapi tidak pernah menyelesaikannya.

Saya akan SANGAT senang jika itu didukung secara asli :)
Namun, saya sangat baru mengenal shader, jadi saya tidak yakin seberapa banyak bantuan yang saya dapat. Saya akan memperhatikan masalah ini dengan cermat.

Saya kembali ke ini sedikit dan dengan cepat menyadari mengapa saya tidak menyelesaikannya pada awalnya. Sementara SDF _can_ digunakan untuk membuat garis besar, ada beberapa peringatan:

  • Potensi lebar garis luar maksimum dibatasi oleh luasnya bidang jarak itu sendiri (~8 texel dalam tekstur SDF 64x64).
  • Itu tidak sesuai dengan ukuran visual yang konsisten di semua mesin terbang, karena tekstur SDF diskalakan ke batas setiap mesin terbang.

Jadi mesin terbang yang lebih besar seperti "W" bisa mendapatkan garis besar yang cukup tebal, tetapi yang kecil seperti titik hanya bisa mendapatkan garis besar yang sangat tipis. Dan setiap mesin terbang perlu menggunakan titik potong SDF yang berbeda untuk membuat garis besarnya konsisten secara visual.

Saya tidak berpikir ini belum dapat diatasi, tetapi tidak sesederhana yang saya pikirkan pada awalnya.

@lojjic , menyukai perpustakaan ini , tetapi garis besar teks adalah persyaratan untuk proyek kami ...

Saya kembali ke ini sedikit dan dengan cepat menyadari mengapa saya tidak menyelesaikannya pada awalnya. Sementara SDF _can_ digunakan untuk membuat garis besar, ada beberapa peringatan:

  • Potensi lebar garis luar maksimum dibatasi oleh luasnya bidang jarak itu sendiri (~8 texel dalam tekstur SDF 64x64).
  • Itu tidak sesuai dengan ukuran visual yang konsisten di semua mesin terbang, karena tekstur SDF diskalakan ke batas setiap mesin terbang.

Jadi mesin terbang yang lebih besar seperti "W" bisa mendapatkan garis besar yang cukup tebal, tetapi yang kecil seperti titik hanya bisa mendapatkan garis besar yang sangat tipis. Dan setiap mesin terbang perlu menggunakan titik potong SDF yang berbeda untuk membuat garis besarnya konsisten secara visual.

Saya tidak berpikir ini belum dapat diatasi, tetapi tidak sesederhana yang saya pikirkan pada awalnya.

Saya ingin tahu, bisakah kita melakukan semacam pemrosesan pos menggunakan shader untuk mencapai garis besar dan/atau efek bayangan? Terima kasih sebelumnya!
Inilah efek yang saya coba capai:
Screen Shot 2020-08-31 at 4 32 03 PM

Sunting: ini dari mapbox gl, saya pikir mereka juga menggunakan SDF https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817 , mungkin kita bisa membedah kode mereka untuk melihat apa yang mereka lakukan. https://github.com/mapbox/mapbox-gl-js

Terima kasih atas info tentang Mapbox, @anzorb. Saya pasti akan memeriksa implementasinya lebih dekat, tetapi dari posting blog itu (mereka menyebut garis besar "halo") sepertinya mereka menggunakan pendekatan ambang alfa SDF seperti yang saya sebutkan sebelumnya. Tetapi generasi SDF dan strategi pengemasan atlas mereka berbeda dari milik saya dan tidak memiliki masalah yang sama dengan ukuran bidang jarak yang tidak seragam per mesin terbang. Itu mungkin akan memiliki batasan lebar garis maksimum yang sama.

Saya sebenarnya telah membuat beberapa kemajuan pada garis besar _screen space_ menggunakan turunan standar. Ruang layar yang berarti garis besarnya adalah misalnya lebar 1 piksel layar terlepas dari ukuran/skala atau kemiringan teks. Jika tujuannya hanya untuk menambahkan kontras dengan latar belakang, sepertinya itu mungkin sama baiknya dengan (atau bahkan lebih baik) menguraikan skala itu bersama dengan ukuran teks. Apakah Anda memiliki pendapat tentang itu?

Lebar standar jauh lebih disukai daripada lebar penskalaan. Itu akan berperilaku lebih seperti css dengan cara ini juga.
Setiap text-shadow yang diterapkan melalui css dikonfigurasi secara independen dari font-size .
Jika solusi yang Anda usulkan @lojjic melakukan hal yang sama, maka itu adalah 🎉 🎉

Terima kasih atas tanggapan cepat Anda @lojjic!

Tujuannya adalah untuk menambahkan kontras, dan proposal Anda terlihat bagus. Apakah maksud Anda garis besarnya akan statis? yaitu tidak ada cara untuk mengendalikannya (seperti yang dijelaskan @stephencorwin , menggunakan pendekatan text-shadow-ish).

Sejujurnya, saya tidak melihat itu sebagai masalah, selama 1 piksel terlihat pada layar dengan kepadatan super tinggi (karena saat ini kami mengalikan ukuran font dengan rasio piksel perangkat untuk mencapai proporsi "sama", terlepas dari kepadatannya) , Saya pikir proposal Anda berarti garis besar akan terlihat lebih tipis pada perangkat DPI yang lebih tinggi, bukan?

Terima kasih sebelumnya!

Saya pikir proposal Anda berarti garis besar akan terlihat lebih tipis pada perangkat DPI yang lebih tinggi, bukan?

Ya, itulah salah satu kelemahan dari pendekatan ruang layar. Itu mungkin baik untuk banyak skenario tetapi akan mengganggu saya sebagai desainer untuk memiliki tampilan yang berbeda di seluruh perangkat.

Kelemahan besar lainnya adalah (saya pikir) meningkatkan ketebalan halo akan berdampak pada kinerja karena membutuhkan lebih banyak pembacaan tekstur. Saya harus terus meneliti ini.

Saya juga membutuhkan fitur ini. Saya telah menerapkan fitur seperti itu di aplikasi Android yang saya kembangkan sejak lama dan telah saya gunakan hanya untuk diri saya sendiri dan teman-teman. Saya telah mulai mengimplementasikan ulang aplikasi ini dengan React dan datang untuk menemukan proyek Anda.
Seperti yang lain, saya ingin berterima kasih atas perpustakaan ini. Saya kagum dengan itu.

Pada komentar Anda tentang lebih banyak bacaan tekstur, saya tidak berpikir Anda harus terlalu khawatir tentang itu. Texel tambahan yang Anda butuhkan akan menjadi texel yang dibutuhkan oleh fragmen tetangga dan karenanya saya pikir mereka akan berada di cache GPU dan harganya hampir tidak ada.

Terima kasih atas masukannya @FunMiles. (Colorado mewakili! )

Saya pikir Anda mungkin tepat untuk garis besar 1, mungkin 2 fragmen tebal. Kekhawatiran saya adalah bahwa ketika ketebalan meningkat, keduanya meledakkan jumlah pembacaan tekstur (ketebalan 4 = 56 pembacaan?) serta kemungkinan pembacaan tersebut akan lebih mahal. Tapi saya hanya berspekulasi berdasarkan membaca beberapa hal, saya sama sekali bukan ahli GPU. Saya mungkin harus mencobanya.

@lojjic (Anda di utara sini ) Saya mencoba menemukan kode untuk shader fragmen. Saya akui mengalami kesulitan mencari tahu apa yang tampak (dan saya pikir saya membacanya di suatu tempat) bahwa Anda memodifikasi shader alih-alih menulisnya sepenuhnya.
Namun, meskipun saya tidak tahu seperti apa full shader dan bagaimana Anda benar-benar memasangnya, saya pikir saya mendapatkan beberapa rutinitas inti ...

Saat ini Anda membaca jarak skalar untuk piksel dengan texture2D(uTroikaSDFTexture, vTroikaSDFTextureUV).r; . Jika saya memahami apa yang Anda tulis sebelumnya, satu masalah berkaitan dengan ruang di sekitar mesin terbang. Bisakah Anda menjelaskan lebih detail?
Kembali ke contoh 'W' dan ',' apakah rentang vTroikaSDFTextureUV dalam tekstur sangat pas di sekitar mesin terbang, atau adakah ruang tambahan? Apakah shader fragmen mengetahui batas UV untuk mesin terbang saat ini? Jika ya, untuk fragmen yang akan jatuh di luar, Anda dapat memproyeksikan UV saat ini ke batas dan membaca data tepat di dalam.

Saya pikir adalah mungkin untuk mengetahui apa yang dibutuhkan dengan paling banyak 5 bacaan texel atau dengan penggunaan turunan (saya melihat Anda memeriksa apakah tersedia).

Kembali ke contoh 'W' dan ',' apakah rentang vTroikaSDFTextureUV dalam tekstur sangat pas di sekitar mesin terbang, atau adakah ruang tambahan?

Ada sedikit ruang ekstra di sekitar batas jalur sebenarnya masing-masing mesin terbang, hanya cukup untuk mengakomodasi bagian luar bidang jarak. Itu 8 texel di SDF, tetapi karena setiap SDF adalah 64x64 seragam yang diskalakan ke quad mesin terbang dengan berbagai ukuran, margin yang terlihat itu bervariasi mesin terbang ke mesin terbang.

Apakah shader fragmen mengetahui batas UV untuk mesin terbang saat ini? Jika ya, untuk fragmen yang akan jatuh di luar, Anda dapat memproyeksikan UV saat ini ke batas dan membaca data tepat di dalam.

Info itu harus tersedia. Saya tidak mengikuti Anda tentang "proyeksikan UV saat ini ke batas dan baca datanya tepat di dalam".

Saya akan berterima kasih jika Anda tahu cara untuk mendapatkan garis besar yang lebih tebal dengan bacaan texel yang lebih sedikit! Saya telah mengonsepnya sebagai: untuk fragmen yang tidak berada di dalam jalur mesin terbang, lakukan pencarian radial untuk melihat apakah ada fragmen dalam r=akan jatuh dalam jalur mesin terbang. Itu mungkin cara berpikir yang salah.

Salah satu masalah adalah apa yang terjadi ketika mesin terbang disatukan berdampingan. Kesampingkan itu untuk saat ini, mari kita ambil kasus satu karakter yang digambar dengan garis yang cukup tebal t . Karakter sedang digambar dengan persegi panjang di sekitarnya yang cukup besar untuk mengakomodasi garis luar.
Fragmen shader memiliki dua informasi utama: vTroikaSDFTextureUV dan vTroikaGlyphUV .

Pemahaman saya adalah bahwa vTroikaGlyphUV memiliki nilai yang dijepit antara 0 dan 1 saat berada di dalam mesin terbang. Maksud saya ketika saya berbicara tentang proyeksi adalah bahwa jika vTroikaGlyphUV berada di luar batas itu, Anda dapat mengambil jarak dari titik yang "diproyeksikan" ke batas mesin terbang. Artinya, jika uv = (1,05, 0,7), maka titik proyeksinya adalah (1,0, 0,7). Dengan menggunakan nilai pada (1,0, 0,7+epsilon) dan (1,0, 0,7-epsilon), Anda dapat mengambil gradien ke jarak dan dengan menggunakan itu, hitung perkiraan jarak pada (1,05, 0,7).
Ketika saya melakukan pekerjaan saya sendiri untuk ini, saya ingat pernah membaca artikel tentang seseorang yang melakukan SDF dengan tekstur gradien juga. Pendekatan ini menghindari keharusan membaca tiga teks, tetapi membuat tekstur menjadi tekstur 3 komponen dan menambah kerumitan untuk membangun tekstur.

Apakah ini menjawab pertanyaan Anda?

Sekarang ketika Anda memiliki beberapa karakter yang berdampingan, maka masing-masing harus menyadari tetangga, membuat ini sedikit lebih kompleks. Anda perlu membawa GlyphUV dan TextureUV tidak hanya untuk karakter saat ini, tetapi juga untuk tetangga. Itu mungkin perlu untuk memotong setiap karakter menjadi dua persegi panjang, sehingga tetangga bisa menjadi yang pertama untuk persegi panjang pertama dan yang satu setelah untuk persegi panjang kedua. Saya tidak yakin bagaimana menangani multi-line.... Saya tidak harus berurusan dengan kasus itu di aplikasi saya. Aplikasi saya adalah peta dan setiap label adalah satu baris.

PS: Saya mungkin salah memahami "ruang ekstra di sekitar batas jalur sebenarnya setiap mesin terbang" Anda. Apakah Anda mengatakan bahwa untuk X, misalnya, terbungkus dalam persegi panjang dan ada empat segitiga yang tidak memiliki nilai yang valid?

@FunMiles Saya _think_ mungkin saya melihat ke mana Anda pergi. Saya perlu waktu untuk memikirkannya, tetapi ada pekerjaan tenggat waktu lain yang perlu saya fokuskan saat ini.

PS: Sedikit catatan matematika yang menyenangkan:
Untuk berjaga-jaga jika seseorang bertanya-tanya bagaimana gradien dapat diperoleh dari dua atau tiga titik sejajar, kita harus ingat bahwa gradien jarak memiliki norma tetap (tergantung pada skala yang dipilih). Dan gradien pasti menunjuk ke arah luar kotak mesin terbang. Jadi misalnya jika semua 3 titik contoh (1.0, 0.7), (1.0, 0.7+epsilon) dan (1.0, 0.7-epsilon) berada pada jarak yang sama, maka gradiennya adalah (skala, 0).

Meskipun jelas tidak berkinerja, dimungkinkan untuk menggunakan offset. Saya menggunakan react-three-fiber , yang memanfaatkan troika-text dengan paket drei, tetapi saya pikir saya akan membagikan jika orang lain mencari solusi sebagai pengganti sementara sampai perpustakaan mendukung stroke secara asli:

import React from 'react';
import {Text} from 'drei';

const StrokedText: React.FC<
  {
    strokeWidth?: number;
    strokeColor?: string;
    strokeResolution?: number;
    bold?: boolean;
  } & any
> = ({
  strokeWidth = 1,
  strokeColor: color = '#000000',
  strokeResolution = 100,
  position,
  bold,
  ...props
}) => {
  const font = bold ? FONTS.BOLD : undefined;
  const sharedProps = {
    ...props,
    font,
    color,
    sdfGlyphSize: 12,
    debugSDF: true,
  };

  let zOffset = 0;
  const offset = () => (zOffset += 0.001);

  return (
    <group name="Stroked Text" position={position}>
      {Array(strokeWidth)
        .fill({})
        .map((_, i) => {
          const s= i / strokeResolution;
          return (
            <React.Fragment key={i}>
              {/* <Text {...sharedProps} position={[-s, 0, offset()]} />*/}
              {/* <Text {...sharedProps} position={[s, 0, offset()]} />*/}
              <Text {...sharedProps} position={[0, -s, offset()]} />
              <Text {...sharedProps} position={[0, s, offset()]} />
              <Text {...sharedProps} position={[-s, -s, offset()]} />
              <Text {...sharedProps} position={[s, s, offset()]} />
              {/* <Text {...sharedProps} position={[-s, s, offset()]} /> */}
              {/* <Text {...sharedProps} position={[s, -s, offset()]} /> */}
            </React.Fragment>
          );
        })}
      <Text name="Text" {...props} position={[0, 0, strokeWidth ? offset() : 0]} />
    </group>
  );
};

export default StrokedText;

Kemudian di tempat lain, saya dapat menyebutnya dengan <StrokedText /> alih-alih <Text /> secara normal:

<StrokedText
  color="#ffffff"
  fontSize={fontSize}
  clipRect={[-0.5, -0.15, 0.5, 0.15]}
  textAlign="center"
  position={[0, 0, 0.01]}
>
  {text}
</StrokedText>

image

@FunMiles Saya akhirnya punya waktu untuk mengurai saran Anda. Saya pikir itu masuk akal dengan asumsi keseluruhan persegi panjang SDF mesin terbang mengandung nilai jarak yang berguna (> 0,0). Saat ini tidak demikian; Saya pikir Anda menyadarinya dalam tindak lanjut Anda tentang "x", di mana SDF jatuh ke nol dengan baik di dalam batas quad, jadi ada area signifikan di mana tidak ada gradien jarak yang berguna untuk diekstrapolasi:

image

Mungkin saya bisa melihat ke dalam mengubah generator SDF untuk memastikan gradien bukan nol di keseluruhan quad...? Berpikir keras, itu bisa memiliki konotasi untuk ketepatan jarak, dan bisa memperkenalkan artefak antar karakter dalam tekstur atlas...

Mungkin saya bisa melihat ke dalam mengubah generator SDF untuk memastikan gradien bukan nol di keseluruhan quad

Saya sudah mencobanya, dan ya itu memungkinkan bidang jarak diekstrapolasi di luar batas quad, tetapi karena saya khawatir itu menurunkan kualitas mesin terbang itu sendiri secara signifikan. Itu yang diharapkan hanya dengan gradien 8-bit; menyebarkannya ke jarak yang lebih jauh menghasilkan presisi yang lebih rendah di setiap texel. :(

Mungkin saya bisa membuat SDF terpisah hanya untuk garis luarnya -- bidang dengan penyebaran lebih tinggi tetapi presisi lebih rendah -- dikodekan ke dalam saluran tekstur kedua. Ini akan menggandakan ukuran tekstur tetapi seharusnya tidak lebih lambat secara signifikan. 🤔.

dikodekan ke dalam saluran tekstur kedua.

@lojjic Kedengarannya sangat masuk akal dan pada dasarnya meniru solusi saya sekarang. Plus, itu bisa menjadi pilihan, jadi tidak ada hit perf jika pengguna tidak meminta garis besar.

@lojjic Pendekatan keikutsertaan yang disarankan oleh @stephencorwin akan memastikan bahwa tidak ada yang membayar lebih dari yang mereka siap bayar.

Kembali ke aspek teknis. Mari kita ambil gambar X dalam tanggapan Anda. Apakah saya memahami dengan benar bahwa untuk semua mesin terbang, itu adalah 64x64 piksel? Dengan 8 bit, jika Anda harus mengkodekan seluruh ruang jarak, itu berarti Anda memiliki akurasi 2 _fraksional_ bit. Saya kira Anda menyatakan bahwa akurasi ini tidak cukup.

Mungkin ada trik yang digunakan untuk mendapatkan akurasi dengan biaya yang sangat kecil. Alih-alih melakukan grid 64x64 8 bit, kompres data blok 2x2 menjadi data 32-bit. Salah satu fitur yang jelas dari jarak bertanda antara dua piksel adalah selalu berada dalam [-1,1] kanan dan kiri, atas dan bawah dan [-sqrt(2), sqrt(2)] secara diagonal. Jadi bayangkan Anda menggunakan 12 bit untuk SD bagian tengah blok 2x2, Anda akan memiliki 5 bit untuk setiap pusat piksel untuk mengkodekan perbedaan antara pusatnya dan pusat 2x2. 5 bit ini mewakili paling banyak sqrt(2)/2 jarak. Secara efektif Anda memiliki akurasi 5,5 bit.
Titik tengah 12 bit mengkodekan setidaknya 6 bit akurasi pada jarak maksimum 64. Secara teknis jika kotak hanya memiliki satu titik di sudut, 12 bit harus dapat dikodekan hingga sqrt(2)*64, tetapi Saya tidak berpikir itu sebenarnya mungkin karena kotak itu mungkin cukup terpusat di sekitar setiap mesin terbang. Faktanya, semakin jauh dari tepi mesin terbang dan semakin sedikit informasi yang harus dikodekan delta, (ketika Anda jauh dari tepi mesin terbang, bidang gradien menjadi hampir seragam di lingkungan) jadi dari perspektif teori informasi, itu bahkan mungkin untuk meningkatkan pengkodean
untuk memiliki lebih banyak informasi aktual .... Tapi saya tidak akan memulai dengan pengoptimalan tambahan seperti itu.

Salah satu konsekuensi menarik dari pendekatan ini adalah bahwa seseorang tidak akan membiarkan perangkat keras tekstur melakukan interpolasi apa pun. Tetapi di sisi lain, seseorang akan mendapatkan gradien secara gratis.

Jika Anda memerlukan bantuan, saya dapat menerapkan penyandian/penguraian semua ini.

PS: Saya ingat pernah melihat diskusi di salah satu README.md tentang SDF yang lebih canggih. Apakah saya memimpikannya? Dapatkah seseorang mengarahkan saya kembali ke sana untuk melihat apakah sistem lain itu dapat membantu di sini?

@FunMiles Ide kompresi yang sangat cerdas. Saya akan mengingatnya jika opsi lain gagal. Kehilangan interpolasi linier oleh perangkat keras adalah pengorbanan yang saya lebih suka tidak harus lakukan. 😉.

Terpikir oleh saya bahwa masalah saya dengan bit yang tidak cukup diperburuk dengan menggunakan 0,5 sebagai jarak "nol", jadi hanya setengah dari nilai alfa yang tersedia untuk menyandikan jarak _outside_ mesin terbang. Saya berpotensi mengubahnya untuk menggunakan lebih banyak nilai untuk jarak luar dan lebih sedikit untuk jarak dalam, mendapatkan beberapa presisi di pinggiran.

Ulang. "SDF yang lebih canggih", maksud Anda "MSDF" di mana banyak saluran warna digunakan?

@FunMiles Ide kompresi yang sangat cerdas. Saya akan mengingatnya jika opsi lain gagal. Kehilangan interpolasi linier oleh perangkat keras adalah pengorbanan yang saya lebih suka tidak harus lakukan. 😉.

Saya tidak berpikir Anda harus khawatir kehilangan interpolasi itu. Biayanya sangat rendah tetapi manfaat dari selalu memiliki gradien (dan bahkan sedikit kelengkungan) ketika tidak ada dukungan perangkat keras yang lebih penting menurut saya. Akibatnya, Anda membulatkan titik sampel dan mendapatkan nilai offset baru ke titik sampel yang dibulatkan. Menghitung penutup parsial dari fragmen untuk anti aliasing berlangsung seperti biasanya dengan gradien yang tersedia.
Terpikir oleh saya bahwa masalah saya dengan bit yang tidak cukup diperburuk dengan menggunakan 0,5 sebagai jarak "nol", jadi hanya setengah dari nilai alfa yang tersedia untuk menyandikan jarak _outside_ mesin terbang. Saya berpotensi mengubahnya untuk menggunakan lebih banyak nilai untuk jarak luar dan lebih sedikit untuk jarak dalam, mendapatkan beberapa presisi di pinggiran.

Itu akan memberi Anda paling banyak satu akurasi. Tidak untuk disindir tetapi tidak terlalu signifikan.

Ulang. "SDF yang lebih canggih", maksud Anda "MSDF" di mana banyak saluran warna digunakan?
Itu yang saya maksud. Saya memang menemukan proyek GitHub tentang itu di C++. Apakah Anda memiliki sesuatu untuk digunakan atau apakah saya hanya bingung, mengumpulkan berbagai hal yang saya cari dua minggu lalu?

Saya tidak berpikir MSDF akan membantu, omong-omong.
Bisakah saya bertanya apakah Anda dapat memiliki file .md kecil yang menjelaskan bagaimana Anda membangun SDF dalam JavaScript? Dengan itu, saya pikir saya bisa membuat kode untuk mengimplementasikan ide kompresi saya.

SDF dibuat di sini: https://github.com/protectwise/troika/blob/master/packages/troika-three-text/src/worker/SDFGenerator.js#L134 -- tidak banyak yang bisa dijelaskan tentangnya, kebanyakan memetakan texel ke unit font dan menulis jarak terukur ke dalam nilai texel. Kita harus menambahkan beberapa pengukuran jarak ekstra di sana untuk titik tengah setiap blok 2x2.

Mencoba untuk membungkus otak saya sepenuhnya di sekitar ini... Mereplikasi interpolasi bilinear di GLSL terlihat sederhana/cukup murah, setelah Anda memiliki 4 nilai terdekat. Untuk mendapatkan nilai-nilai itu ketika dikodekan dengan skema kompresi Anda, saya pikir itu akan melibatkan:

  • Jika tepat di tengah texel: 2 atau 3 sampel tekstur
  • Jika di antara 4 texel dari blok 2x2: 4 sampel tekstur
  • Jika di antara dua blok yang berdekatan: ~9 sampel tekstur~ 7 atau 8 sampel tekstur
  • Jika di antara empat blok tetangga: ~11 sampel tekstur~ 13 sampel tekstur

Apakah saya mengatakannya dengan benar?

Oh tunggu, saya masih memikirkan tekstur saluran tunggal. Menggunakan empat saluran rgba, setiap blok data hanya satu kali dibaca. Jadi paling banyak 4 sampel tekstur.

Saya mulai membaca SDFGenerator.js. Aku akan melihatnya lebih.

Saya tidak berpikir Anda membutuhkan lebih dari membaca satu texel per fragmen, kecuali jika Anda ingin secara khusus meningkatkan pencampuran alfa untuk kasus sudut di mana Anda mungkin berada pada titik yang dikelilingi oleh tepi mesin terbang di semua sisi. Anda hanya perlu pusat terdekat dari blok 2x2 di mana pusat fragmen berada.
Namun, saya menyadari bahwa mungkin ada kesulitan yang tidak saya duga sebelumnya... WebGL 1.0 sangat terbatas dalam apa yang disediakannya yang akan berguna di sini: Tidak ada tipe integer unsigned uint bahkan integer 32 bit! dan tidak ada operasi bitwise... Jadi kompresi yang saya sarankan sedikit lebih rumit untuk ditulis menggunakan bilangan bulat 16 bit.

Semua ini tersedia di WebGL 2.0 tapi saya kira kita ingin menargetkan WebGL 1.0 di sini?

Semua ini tersedia di WebGL 2.0 tapi saya kira kita ingin menargetkan WebGL 1.0 di sini?

Saya pikir mungkin masuk akal untuk membatasi garis teks ke webgl 2 dan hanya mendeteksi jika pengguna memiliki kompatibilitas browser itu. Meskipun, saya dapat memahami kemungkinan melakukan versi optimal webgl 2 dengan fallback webgl 1. Imo kita bisa mulai dengan webgl 2 dan membiarkannya meresap dengan komunitas sebelum segera mencoba mendukung keduanya.

Saya pikir saya memiliki pendekatan alternatif untuk mengatasi masalah presisi, jadi @FunMiles jangan khawatir tentang pertempuran dengan hal-hal kompresi untuk saat ini.

hei @lojjic , baru saja memeriksa ini. Adakah kemajuan atau hal-hal yang dapat kami bantu?

Catatan tambahan: Safari akhirnya hadir untuk mendukung WebGL2, jadi mungkin saja untuk tidak mendukung WebGL1 untuk fitur ini.

Implementasi WebGL2 kami dalam kondisi yang cukup baik sehingga kami harus mengaktifkannya secara default untuk pengujian yang lebih luas.
https://trac.webkit.org/changeset/267027/webkit

Saya memiliki iPhone 6 di mana tidak akan pernah ada WebGL 2.0

Menariknya, WebGL 1.0 menetapkan persyaratan yang lebih buruk dari yang saya kira. Bilangan bulat tidak benar-benar ada:

4.1.3 Bilangan bulat
Integer terutama didukung sebagai bantuan pemrograman. Pada tingkat perangkat keras, bilangan bulat nyata akan membantu
implementasi yang efisien dari loop dan indeks array, dan referensi unit tekstur. Namun, tidak ada
persyaratan bahwa bilangan bulat dalam peta bahasa ke tipe bilangan bulat dalam perangkat keras. Tidak diharapkan bahwa
perangkat keras yang mendasari memiliki dukungan penuh untuk berbagai operasi bilangan bulat. Shading OpenGL ES
Implementasi bahasa dapat mengonversi bilangan bulat menjadi pelampung untuk mengoperasikannya. Oleh karena itu, tidak ada portabel
perilaku membungkus.

Namun saya tidak kehilangan harapan. Saya hanya perlu memikirkan kembali sedikit ...
Sementara itu, @lojjic , maukah Anda memberi tahu kami pendekatan alternatif apa yang Anda pikirkan?

@FunMiles Tentu. Saya dapat memperluas bidang jarak ke tepi tekstur, sambil tetap mempertahankan presisi yang cukup untuk bentuk mesin terbang, dengan mengkodekan nilai jarak menggunakan skala non-linear. Jadi jarak yang sangat dekat dengan jalur mesin terbang (dalam 1-2 texel) memiliki banyak nilai untuk dikerjakan, sedangkan yang lebih jauh memiliki lebih sedikit. Shader hanya perlu tahu bagaimana mengkonversi kembali ke jarak linier asli. Bentuk mesin terbang yang tepat tampak hebat, dan presisi yang lebih rendah untuk garis luar yang diekstrusi hampir tidak terlihat, karena tetap dibulatkan.

Saya telah membuktikan ini menggunakan skala linier dua tingkat, dan skala eksponensial. Keduanya memiliki pro dan kontra.

Saya sekarang sedang menerapkan pendekatan Anda (sangat cerdas) menggunakan nilai tepi tetangga untuk memperkirakan gradien di luar quad. Masuk akal sejauh ini, meskipun saya tidak yakin apa yang harus dilakukan tentang area di luar tikungan. Ini mungkin menjadi jelas setelah saya masuk lebih jauh, tetapi jika Anda memiliki jawaban yang mudah untuk saya, saya akan berterima kasih :)

Saya sekarang sedang menerapkan pendekatan Anda (sangat cerdas) menggunakan nilai tepi tetangga untuk memperkirakan gradien di luar quad. Masuk akal sejauh ini, meskipun saya tidak yakin apa yang harus dilakukan tentang area di luar tikungan. Ini mungkin menjadi jelas setelah saya masuk lebih jauh, tetapi jika Anda memiliki jawaban yang mudah untuk saya, saya akan berterima kasih :)

Saya tidak yakin apa yang Anda maksud dengan _di luar sudut_. Apakah maksud Anda seperempat bidang berakar di setiap sudut, di mana proyeksi terdekat adalah sudut itu sendiri? Saya pikir di sana Anda dapat menggunakan aturan di tepi pada tepi vertikal dan horizontal dan melakukan rata-rata tertimbang berdasarkan jarak ke masing-masing.

PS: Ide untuk mengurangi akurasi jauh telah muncul di benak saya hari ini setelah membaca omong kosong integer WebGL ... Saya masih memiliki harapan bahwa teknik kompresi dapat diterapkan di WebGL 1.0 untuk mendapatkan akurasi 11 bit dengan murah dan beberapa lebih banyak bit dengan lebih banyak tes. yaitu menggunakan rgba , a dapat menampung 8 bit rata-rata kemudian untuk masing-masing rgb , mereka akan ditandatangani dan tanda akan mewakili 1 bit masing-masing akurasi untuk rata-rata, lalu akhirnya sisanya, yang akan berada dalam kisaran 0-127 akan memiliki nilai 64 dikurangi untuk mewakili 7 bit untuk 3 dari 4 nilai yang dibutuhkan. Nilai sebenarnya adalah center (mulai dari 0 hingga 2^11-1) + dist_i. Nilai ke-4 akan diperoleh dengan melakukan dikurangi jumlah mereka, karena jumlahnya harus rata-rata. Seseorang hanya akan mendapatkan 11 bit, tapi itu mungkin cukup. Untuk mendapatkan lebih banyak bit perlu menguji apakah nilainya atau r , g , dan b lebih kecil dari -64, positif atau negatif, lebih besar dari 64. Itu pada dasarnya akan berikan 14 bit untuk pusat dan hanya 6 bit untuk perbedaan. Mungkin kompromi yang bagus? Saya perlu menguji bahwa jaminan yang sangat lemah bahwa WebGL 1.0 memberikan akurasi tidak akan mengganggu pemikiran ini....

Ya itu yang saya maksud, area di mana U dan V berada di luar 0-1. Terima kasih, saya akan mencobanya.

@lojjic Sebagai pertanyaan tambahan, dalam posting sebelumnya, Anda tampaknya khawatir tentang memiliki dua nilai tekstur per SDF texel karena memori. Meskipun saya sendiri lebih suka mengurangi memori, 256 glyph pada grid 64x64 hanya menghabiskan 1/4MB memori tekstur. Saya tahu beberapa bahasa mungkin memerlukan lebih banyak mesin terbang, tapi tetap saja, BBC mengatakan bahwa untuk membaca koran, hanya dibutuhkan 2000/3000 karakter. Jadi 4000 karakter akan menghasilkan 4MB dengan satu byte per texel SDF. Layak untuk dikhawatirkan?

@FunMiles Poin yang adil, dan saya sebenarnya tidak terlalu peduli tentang itu.

Beberapa pekerjaan luar biasa tersisa untuk dilakukan, tetapi b19cd3aff4b0876253d76b3fc66b7e2a1f16a7e5 memperbaiki masalah ini. Bagi mereka yang menggunakan react-three-fiber, ini telah dirilis di drei v2.2.0
https://github.com/pmndrs/drei/pull/156

Saya tahu ini ditutup tetapi saya ingin mengucapkan terima kasih atas pekerjaannya. Saya membuatnya berfungsi di aplikasi saya. Butuh sedikit waktu untuk mengetahui bahwa properti tidak akan menerima hanya angka untuk ukuran garis besar. Namun hasilnya hanya apa yang saya butuhkan.
Screen Shot 2020-11-09 at 7 44 52 PM

@FunMiles Terlihat bagus! Anda _harus_ dapat menggunakan nilai numerik untuk outlineWidth , jadi jika itu tidak berhasil untuk Anda karena alasan tertentu beri tahu saya.

Dan terima kasih atas masukan Anda selama ini. Saya masih tidak bisa mendapatkan ekstrapolasi jarak yang mulus di luar batas quad menggunakan jenis teknik yang Anda sebutkan, jadi garis tebal saat ini memiliki bit kental di sudut khususnya, tapi itu cukup baik untuk sebagian besar kasus (hingga ~ 10% ukuran font). Saya benar-benar terbuka untuk mencoba memperbaikinya.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

drcmda picture drcmda  ·  11Komentar

asbjornlystrup picture asbjornlystrup  ·  7Komentar

arpu picture arpu  ·  43Komentar

lojjic picture lojjic  ·  18Komentar

Ocelyn picture Ocelyn  ·  13Komentar