holodepth

Three.js · Varlık · Draco

Vertex quantization: hassasiyetten hıza giden yol

3B modeli saklarken en büyük engellerden biri, çoğu zaman gereksiz süreklilik hassasiyetidir: bir köşenin uzaydaki yerini anlamsız derecede ince bilmek, ekranda fark edilmeyen bir avantaj sağlamadan veriyi şişirir. Vertex quantization (köşe nicelemesi), bu fazlalığı kontrollü biçimde budama işlemidir.

Bu sayfa yalnızca konum kanalına odaklanır; özniteliklerin tamamı ve GPU köprüsü için Öznitelik sıkıştırma · position ve
Mesh compression · niceleme ile birlikte okuyun.

Önce okuyun: Ağ → decodeGPU zinciri.

«Nasıl küçültüyoruz?» — adım adım niceleme

Nicelemeyi, sürekli bir sinyali dijital bir ızgara (grid) üzerine oturtmaya veya görüntü çözünürlüğünü bilinçli düşürmeye benzetebilirsiniz: amaç bilgi kaybetmek değil, görsel toleransın altındaki ayrımları taşımayı bırakmaktır.

  1. Bounding box (sınırlayıcı kutu): Modelin kapladığı hacmi içine alan eksenlere hizalı bir kutu seçilir; niceleme bu kutunun içinde yapılır. Kutu gereğinden genişse, aynı bit bütçesi daha kaba bir dünyaya yayılır.
  2. Izgara oluşturma: Kutunun her ekseni, seçilen bit derinliği b için yaklaşık 2b eş aralıklı parçaya bölünür. Örneğin eksen başına 11 bit, o eksende 2048 ayrık konum demektir (211).
  3. Snap (mıknatıslama): Ham verideki 32-bit float bileşenler (ör. uzun ondalık kuyruklu bir değer), her eksende ızgaradaki en yakın tam sayı indeksine yuvarlanır.
  4. Açma (dequantization): İstemci aynı kutu ve bit bilgisini kullanarak indeksleri tekrar dünya uzayına ölçekler; bu çarpma / kaydırma ucuzdur, maliyet çoğu zaman sıkıştırılmış tel + entropy tarafındadır.

Motor seviyesi formüller (eksen başına)

Pratikte x, y, z birbirinden bağımsız niceleme görür: her eksen için kendi min, max ve b değeri (veya ortak kutu ile paylaşılan sınırlar) kullanılır; aşağıdaki ifadeler tek bir bileşen içindir.

range = max − min, b bit ve q saklanan nice değer olsun. Sürekli değerden tamsayıya geçişte motorlar çoğu zaman en yakın ızgaraya yuvarlar (round). Açma (dequantization) aynı range ve b ile tersine çevirir; böylece encode → tel → decodeGPU hattı kapanır:

q = round((value - min) / (max - min) * (2^b - 1))
value = min + (q / (2^b - 1)) * range

Hata mertebesi. İki komşu ızgara noktası arası adım kabaca range / (2b − 1)’dir; yuvarlama sonrası mutlak hata en fazla yaklaşık yarım adım ile sınırlıdır. Büyük b için bu, kabaca range / 2b mertebesinde düşünülebilir — yani bit arttıkça aynı kutuda hata üstel olarak küçülür.

Hassasiyet: sayıların dili

Üretimde her köşe konumu çoğu zaman üç adet 32-bit float (x, y, z) olarak gelir: bu, ince gradyanlar için esneklik sunar; fakat web teslimatında aynı bilgi yoğunluğu her zaman gerekmeyebilir.

Nicelemede ise tipik tablo şöyle düşünülür: eksen başına b bit ile o eksende 2b ayrık seviye vardır; üç eksen birlikte düşünüldüğünde konum «hücre» sayısı bu seviyelerin çarpımıyla büyür. Ham float’ın anlamdaki «sonsuz» sürekliliği yerine, sınırlı bir kod kitabı taşınır. Sonuç: köşe başına düşen bit genellikle belirgin biçimde düşer; tam yüzde modelin ölçeğine, kutuya ve b seçimine bağlıdır.

Bu dönüşüm kayıplı (lossy) olabilir; kazanç, dosya boyutu ve decode sonrası ara temsilin hafiflemesi — takas masası yine geçerlidir.

GPU tarafı: ölçek + kaydırma

Nice değer VRAM’de tamsayı olarak dursa bile, köşe işlerken genellikle tekrar dünya veya model uzayına çevrilir; bu, shader veya CPU tarafında aynı matematiğin çarpan + toplam (scale + offset) biçiminde yazılması demektir. Örneğin bir bileşen için scale = range / (2b − 1) ve offset = min seçilirse value = q × scale + offset — yani yukarıdaki açma formülünün doğrudan ALU dostu yazımı.

Tamsayı depolama avantajı

Uint16 / Uint32 gibi sıkı tamsayı temsiller, aynı köşe sayısında daha az bayt ve çoğu mimaride daha öngörülebilir hizalama (alignment) sunar; bu da bellek kopyalama ve önbellek satırı kullanımında küçük ama ölçekte hissedilir kazançlar doğurabilir. Float tamponla karışık düzenlerde (interleaved) yine de düzen seçimi ölçümle doğrulanmalıdır — Attributes & buffers sayfasındaki düzenle birlikte düşünün.

Görsel kalite: ne kadar kaybediyoruz?

Niceleme kaybı kontrollü olmalıdır; kontrolsüz düşük bit, geometriyi ızgaraya «fırlatır».

Wobbling ve z-fighting riski

Bit çok düşükse (ör. eksen başına 8 gibi agresif değerler), köşeler büyük adımlarla kayar; animasyon veya kamera hareketinde yüzeyde dalgalanma (wobbling) hissi doğabilir. Birbirine çok yakın yüzeylerde derinlik ayrımı zayıflayınca z-fighting (titreyen çakışan yüzey) de tetiklenebilir.

Bit için pratik denge

11–12 bit (eksen başına): birçok vitrin ve ürün görüntüleyicide, tipik izleme mesafesinde başlangıç tatlı noktası olarak sık seçilir. 14–16 bit: geniş dünya ölçeği, şehir ölçeği tarama veya mühendislik doğruluğu gerektiren içeriklerde daha güvenli taraftır.

Yüksek bit ile düşük bit farkını görmek için aynı kamerada yan yana A/B vitrin kurmak en hızlı kalite kontrolüdür; tek kare ekran görüntüsü, özellikle düşük bitte köşe kaymasını netleştirir.

İnteraktiv laboratuvar: bbox + ızgara + snap

Aşağıdaki sahne harici model yüklemez; yüksek segmentli prosedürel düzlemde yüksek frekanslı yükseklik (detay) vardır — düşük bitle bu detay bloklaşır ve köşeler yukarıdaki q = round((value - min) / (max - min) * (2^b - 1)) mantığıyla aynı sınırlayıcı kutu içinde ızgaraya kilitlenir. Tek sahne modunda bit sürgüsü (8–16) geometriyi anında yeniden üretir; Split modunda sol 16 bit, sağ 8 bit sabit karşılaştırma (ortadaki tutamacı sürükleyebilirsiniz). Izgara ve hata görselleştirme onay kutuları aşağıdadır. Öznitelik laboratuvarı kanal renklerini gösterirken, burada odak şekil (konum tamponu) üzerindedir.

Niceleme laboratuvarı · güvenli (asset yok) · Three.js r170
Üçgen sayısı
Izgara adımı (max eksen, ~)
BBox genişliği (x×y×z)
Görünüm

Amaç: aynı yüksek frekanslı yüzeyde b küçüldükçe snap’in artması; 8 bitte «voksel» hissi, 14–16 bitte daha pürüzsüz silüet. Izgara (8 bit XZ kafesi) düşük bitten otomatik görünür; yüksek bitte kaybolur — «çözünürlük artıyor» hissi. Hata görselleştir tepe başına orijinal konuma göre sapmayı renklendirir; lejant yalnızca tek sahne + bu mod açıkken görünür. Bit sürgüsü değişince kısa bir ease (≈0,18 sn) yeni ızgaraya oturmayı hissettirir. Orijinal alt katman tek sahne modunda, nicelemesiz yüzeyi hafif gri ve biraz altta gösterir; fark özellikle düşük bitte okunur. Split modunda bit sürgüsü devre dışıdır; sol ve sağ yarı farklı b ile aynı matematiği gösterir ve sağ yarıda 8 bit ızgarası görünür. Wobbling bu demoda canlandırılmaz; sayfadaki wobbling notu hareketli sahneler içindir.

Ölçek faktörü

Aynı b, farklı dünya ölçeklerinde farklı fiziksel adım demektir. Küçük bir obje dar kutuda 11 bit ile genelde temiz kalırken; kilometrelerce uzanan bir stadyum veya şehir modelinde aynı bütçe, detaylarda bloklaşma / voksel hissi üretebilir. Bu yüzden bit seçimi yalnız «kalite kaydırıcısı» değil, kutu boyutu + sahne ölçeği ile birlikte düşünülmelidir.

Floating origin ve büyük dünya

Dünya koordinatları milyonlarca birime çıktığında, saf float32 zaten inceleme (precision) sorunları yaşar; üzerine kaba niceleme bindiğinde artefakt daha erken görünür. Bu yüzden büyük sahnelerde kamera veya oyuncuya göre periyodik orijin kaydırma (floating origin / dünya yeniden merkezleme) sık kullanılır: geometri lokal uzayda küçük kalır, dev öteleme üst node’da tutulur — Holodepth notu ile aynı ailedir.

Scene graph ve hiyerarşi için Scene graph sayfasına bakın.

HoloDepth teknik notu

Merkeze yakın tutmak

Görsel kaliteyi korumada sık işe yarayan pratik: geometriyi mümkün olduğunca orijine yakın (0, 0, 0 çevresinde) çalışmak ve büyük ötelemeleri üst düğüme (node dönüşümü) taşımaktır. Böylece niceleme hatası, dünya uzayında daha homojen dağılır; aşırı büyük mutlak koordinatlarda float zaten incelir, üstüne kaba bir ızgara bindiğinde artefakt daha çok belli olur.

Bu not, Scene graph düşüncesiyle birleşince özellikle anlamlıdır: geometriyi «yerelde» tutup sahneyi dışarıda ölçeklemek.