3D Model Formatları · glTF / GLB · Geometri Verileri
Index Buffer glTF Yapısında Bağlantı Katmanı Nedir?
Vertex Data
sayfası V0…V3 koordinatlarının dosyada nasıl yaşadığını öğretti: «köşeler nedir?»
Bu sayfa bir sonraki soruya geçer: bu köşeler hangi sırayla okunup yüzey kurar?
Holodepth geometri hattında mesh iki katmandır: vertex listesi (konumlar ve attribute'lar) + index listesi (hangi vertex indekslerinin hangi üçgende birleşeceği). Index buffer, ikinci katmanın dosyadaki adıdır; bellek optimizasyonundan önce geometri yeniden kullanım sistemi olarak düşünülmelidir.
Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «POSITION bana noktaları verir; indices bana bu noktaları hangi sırayla üçgene bağlayacağımı söyler. Aynı vertex indeksi birden fazla üçgende tekrar kullanılabilir.»
Bu sayfanın sınırı · Vertex Data ile ayrım
Vertex Data (önceki sayfa) şunları anlatır; burada tekrarlanmaz:
- Vertex / POSITION nedir, accessor zinciri, attribute semantic'leri
- «Dört köşe = henüz yüzey yok» nokta bulutu kavramı
- GPU'ya POSITION attribute yolculuğunun format birleşimi
Index Buffer (bu sayfa) şunları anlatır:
- Index buffer nedir, indexed vs non-indexed mesh
- Triangle assembly, winding order (CW / CCW)
- Paylaşımlı vertex, glTF
indicesaccessor'ı,componentType
Runtime API ve bellek profili için
Three.js · Indexed vs Non-Indexed farklı bakış
açısı sunar (WebGL buffer tipleri, Uint16Array); bu sayfa glTF dosya
okumasına odaklıdır.
Index Buffer Nedir?
Çoğu eğitim index buffer'ı doğrudan «0, 1, 2» listesiyle tanıtır sanki mesh'in doğal ilk parçasıymış gibi. Holodepth'te sıra tersine işler: önce vertex listesinin ne taşımadığını netleştirirsiniz, sonra bağlantı tablosunun neden ayrı olduğunu görürsünüz. Bu bölümün giriş sorusu şudur: GPU aynı vertex'i neden tekrar tekrar saklamıyor?
Kısa cevap: aslında saklayabilir tek bir V0 kaydı vertex buffer'da bir kez
durur. Sorun depolama değil, okuma tarifidir. İki farklı üçgen aynı köşeyi
paylaştığında GPU'ya «Triangle A için şu satırı, Triangle B için yine aynı satırı çek»
demenin yolu index buffer'dır. Koordinatı ikinci kez yazmazsınız; yalnızca aynı satır
numarasına ikinci bir referans eklersiniz.
Vertex Data
«köşeler nedir?» sorusunu cevapladı: V0…V3 koordinatları, POSITION accessor,
nokta bulutu. Bu sayfa «bu köşeler hangi sırayla okunur?» sorusuna geçer.
Koordinatları yeniden tanımlamıyoruz; önceki sayfadaki zemin dörtgenini bağlantı katmanı
olmadan bıraktığımız yerden devam ediyoruz.
İki tablo: konum listesi ve bağlantı listesi
Indexed mesh okumak için zihinde iki ayrı liste tutulur. Birincisi vertex
buffer (glTF'de attributes.POSITION ve paralel attribute'lar); ikincisi index buffer (glTF'de indices). İlki «adres
defteri», ikincisi «üçgen tarifleri» gibidir tarifler adresi tekrar yazmaz, numaraya
işaret eder.
Vertex Buffer (POSITION) Index Buffer (indices)
───────────────────────── ─────────────────────────
[0] V0 (-1, 0, 1) 0, 1, 2 → Triangle 0
[1] V1 ( 1, 0, 1) 0, 2, 3 → Triangle 1
[2] V2 ( 1, 0, -1)
[3] V3 (-1, 0, -1)
4 satır konum 6 sayı = 2 üçgen × 3 referans
Tabloda satır numarası (0, 1, 2, 3) ile köşe etiketi (V0…V3)
bilinçli olarak eşleştirilir: glTF ve GPU konuşmasında «vertex 2» derken kastedilen
POSITION listesinin ikinci değil, sıfırdan sayılan 2.
satırıdır
yani bu örnekte V2. Index buffer'daki her değer bu tür bir satır numarasıdır; (x, y, z) float'ı taşımaz.
Index bir işaretçidir, kopya değil
Yeni başlayanların sık yaptığı karışıklık: index buffer'ı «ikinci bir vertex listesi»
sanmak. Oysa ikinci listede uzay koordinatı yoktur; yalnızca birinci listeye geri dönen
tam sayılar vardır. «0» demek «POSITION'ın 0. elemanını getir» demektir o elemandaki
(x,y,z) zaten vertex buffer'da yazılıdır.
Vertex buffer cevaplar: «Köşeler nerede?» · Index buffer cevaplar: «Bu köşelerden hangi üçlü yüzey kurulsun, hangi sırayla?»
Aynı index değeri birden fazla üçgende tekrarlanabilir: yukarıdaki örnekte «0» hem
Triangle 0'da hem Triangle 1'de geçer V0 iki yüzeyde ortaktır. Vertex
buffer'da V0 hâlâ tek satırdır; index buffer iki ayrı yerde «0» yazar. Bu,
Holodepth'in «geometri yeniden kullanım sistemi» tanımının çekirdeğidir; byte tasarrufu bu
modelin sonucudur, tanımın kendisi değil.
GPU nasıl okur?
Draw çağrısı sırasında (bu sayfada API detayı yok) GPU tipik olarak index listesini sırayla üçlüler halinde gezer; her üçlü bir triangle assembly adımıdır (§3'te adlandırılır):
indices = [0, 1, 2, 0, 2, 3]
Üçlü 1: 0, 1, 2
→ POSITION[0], POSITION[1], POSITION[2]
→ uzayda V0, V1, V2 ile bir üçgen
Üçlü 2: 0, 2, 3
→ POSITION[0], POSITION[2], POSITION[3]
→ uzayda V0, V2, V3 ile ikinci üçgen (V0 ve V2 yeniden kullanıldı)
Dikkat: ikinci üçgende GPU yine POSITION[0] ve POSITION[2]
satırlarını okur koordinatları vertex buffer'dan yeniden kopyalamaz, aynı
satırlara tekrar referans verir. NORMAL, UV gibi diğer attribute'lar da aynı indeksle
paralel okunur (semantic tanıtımı
Vertex Data
§3
); bu sayfada odak yalnızca POSITION + index eşlemesidir.
Özet denklem: 4 vertex + 6 index = 2 triangle. Dört köşe dosyada bir kez yaşar; ekrandaki zemin dörtgeni, bu dört kayda altı referansla iki üçgen olarak kurulur.
Index olmadan aynı şekil nasıl tarif edilir?
glTF primitive'de indices alanı yoksa mesh non-indexed
okunur: POSITION listesinin kendisi üçlüler halinde sıralanır, her ardışık üç satır bir
üçgendir. Aynı zemin için V0, V1, V2 yazılır, ardından V0, V2,
V3 tekrar yazılır ortak köşeler koordinat olarak kopyalanır. Görünen şekil
aynı kalabilir; veri modeli farklıdır: bağlantı bilgisi vertex listesinin içine gömülür.
Indexed ve non-indexed yolların tablo karşılaştırması, küp örneği ve «kaç vertex taşınır?» sorusu §2'de genişletilir. Bu bölümde hatırlanacak tek cümle: index buffer, bağlantıyı vertex listesinden ayırarak aynı köşeye birden fazla üçgenin güvenle referans vermesini sağlar.
Vertex Tekrar Kullanım Problemi
§1'de index buffer'ın ne olduğunu «işaretçi» olarak tanımladık. Bu bölümün sorusu bir adım genişler: aynı geometrik köşe, veri modelinde neden birden fazla kez yazılsın ki? İki komşu üçgen ortak bir kenarı paylaştığında uzayda tek bir nokta vardır; dosyada bunu ya tek kayda çok referans (indexed) ya da aynı koordinatın kopyalanması (non-indexed) ile tarif edersiniz. İkisi de geçerli glTF yollarıdır; fark görünür şekilde değil, topolojinin nerede kodlandığında yatar.
Holodepth'te «vertex tekrar kullanım problemi» bir performans şikâyeti değil, okuma disiplini meselesidir: mesh'i okurken «kaç benzersiz köşe var?» ile «draw için kaç vertex satırı okunacak?» sorularını ayırmayı öğrenirsiniz. Indexed yolda bu iki sayı çoğu zaman farklıdır; non-indexed yolda ikinci sayı birinciden büyük veya eşit olur çünkü bağlantı, POSITION listesinin içine gömülür.
İki okuma modeli: indexed ve non-indexed
| Soru | Indexed mesh | Non-indexed mesh |
|---|---|---|
glTF indices |
Var (accessor referansı) | Yok |
| Bağlantı nerede? | Ayrı index tablosunda | POSITION sırasının kendisinde |
POSITION count |
Benzersiz vertex sayısı | Genelde üçgen sayısı × 3 |
| Ortak köşe | Tek satır + çok index referansı | Aynı (x,y,z) birden fazla satırda |
Vertex Data §4 non-indexed yolun varlığını kısaca işaret etmişti; burada iki model yan yana konur. Runtime bellek ve WebGL buffer tipleri Three.js · Indexed vs Non-Indexed sayfasının konusudur bu bölüm yalnızca glTF dosyasında «hangi tablo ne anlama gelir?» sorusuna odaklanır.
Dörtgen örneği aynı zemin, iki veri modeli
§1'deki zemin dörtgenini hatırlayın: dört benzersiz köşe, iki üçgen. Indexed tarif:
POSITION (4 satır) indices (6 sayı)
V0, V1, V2, V3 0, 1, 2, 0, 2, 3
Non-indexed tarif aynı ekran görüntüsünü üretir; fakat POSITION listesi bağlantıyı içerir ortak köşeler koordinat olarak tekrarlanır:
POSITION (6 satır her üçlü bir üçgen)
satır 0–2: V0, V1, V2 → Triangle 0
satır 3–5: V0, V2, V3 → Triangle 1 (V0 ve V2 ikinci kez yazıldı)
indices yok
| Yol | Benzersiz köşe | POSITION satırı | Index sayısı | Üçgen |
|---|---|---|---|---|
| Indexed | 4 | 4 | 6 | 2 |
| Non-indexed | 4 (uzayda) | 6 | — | 2 |
Non-indexed okuma kuralı basittir: ardışık her üç POSITION satırı bir üçgendir. Index tablosu olmadığı için «hangi satırlar birleşir?» sorusunun cevabı listenin sırasına gömülüdür sırayı değiştirirseniz farklı üçgenler (veya bozuk geometri) elde edersiniz; indexed yolda bağlantı indices'te, konum POSITION'da ayrı düzenlenir.
Aynı şekil, farklı dosya hikâyesi
Viewer'da iki primitive yan yana aynı zemin gibi görünebilir. Format okuyucusu için kritik ayrım:
Geometrik eşitlik (ekranda aynı üçgenler) · veri eşitliği (dosyada aynı satır sayısı) aynı şey değildir.
Indexed modelde «4 vertex, 6 index» dersiniz; non-indexed modelde «6 vertex satırı, index
yok» dersiniz. İkinci modelde V0 koordinatı iki satırda tekrarlanır uzayda
aynı nokta, bellekte iki ayrı kayıt. Bu tekrar hata değil; non-indexed formatın bilinçli
tasarımıdır. Bazı üretim hatları veya dönüştürücüler doğrudan üçlü POSITION listesi
yazar; loader yine geçerli mesh üretir.
Küp örneği tekrar sayılabilir hale gelir
Zemin dörtgeninde tekrar iki köşeyle sınırlıydı; küpte paylaşım her yerde görünür. Bir küpün 8 benzersiz köşesi vardır; dış yüzeyi 12 üçgen (6 yüz × 2) ile kaplanır:
Indexed küp (tipik)
8 POSITION satırı → 8 benzersiz köşe koordinatı
36 index → 12 üçgen × 3 referans (köşeler tekrar referanslanır)
Non-indexed küp
36 POSITION satırı → her üçgende 3 koordinat sırayla; indices yok
8 benzersiz köşe (uzayda) ama 36 satır (dosyada)
Örneğin bir köşe indexed modelde POSITION[3] olarak bir kez durur; o köşeye
dokunan her yüzey üçgeni index buffer'da «3» yazar aynı satıra dört, beş veya daha fazla
referans olabilir. Non-indexed modelde aynı (x,y,z) her yüzey üçgeni için
ayrı satırda yeniden listelenir; uzayda bir köşe, dosyada çok satır.
Küp sayıları öğretim içindir; asıl mesele ölçektir: mesh büyüdükçe ortak köşe sayısı
artar, indexed modelde POSITION count sabit kalırken index listesi üçgen
sayısıyla büyür; non-indexed modelde POSITION count doğrudan üçgen sayısıyla
orantılı artar. Bu fark dosya boyutuna yansır fakat Holodepth'te önce şu cümleyi
kurun: indexed mesh, topolojiyi index tablosunda açık tutar; non-indexed mesh
topolojiyi POSITION sırasına gömer.
Neden indexed yol varsayılan okuma?
glTF ekosisteminde çoğu üretilmiş mesh indexed gelir çünkü bağlantı katmanı ayrı
okunabilir: debug sırasında «kaç benzersiz vertex?» sorusu POSITION count ile,
«kaç üçgen?» sorusu indices count ÷ 3 ile yanıtlanır. Non-indexed primitive
hâlâ geçerlidir; özellikle basit veya dönüştürülmemiş üçlü listelerde karşılaşılabilir.
Paylaşımlı köşenin görsel vurgusu ve «shared vertex count» düşüncesi §5'te derinleşir; triangle assembly adımları §3'te pipeline olarak adlandırılır. Bu bölümün çıkış cümlesi:
Vertex tekrar kullanım problemi = ortak köşeyi ya bir kez yazıp çok kez referanslamak (indexed), ya da her üçgende koordinatı yeniden yazmak (non-indexed). İkisi de aynı yüzeyi kurabilir; format okuyucusu hangi tablonun ne anlattığını ayırt edebilmelidir.
Triangle Assembly
Vertex Data §4 «nokta bulutu → üçgen ağı» geçişini kavramsal olarak tanıttı; §2 indexed / non-indexed veri modellerini yan yana koydu. Bu bölüm aradaki işlem adımını isimlendirir: dosyadaki index üçlüleri draw anında somut üçgen primitive listesine nasıl dönüşür? Holodepth'te bu adıma triangle assembly denir kullanıcı bu terimi burada ilk kez görür.
Assembly bir sıkıştırma tekniği değildir; okuma yorumudur. Vertex buffer ve index buffer dosyada durur; GPU (veya loader'ın hazırladığı draw komutu) index listesini sırayla üçlüler halinde gezer ve her üçlü için «şu üç vertex'i bir yüzey say» der. §1'deki «işaretçi» metaforunun draw tarafındaki karşılığı budur: index sayıları artık soyut satır numarası değil, çizilecek üçgenin köşe seçimidir.
Pipeline: assembly nerede durur?
glTF primitive (POSITION + indices + mode)
↓
Vertex Buffer konum ve paralel attribute tabloları (değişmez kaynak)
↓
Index Buffer hangi vertex indeksleri, hangi sırayla (üçlü tarifler)
↓
Triangle Assembly ← BU BÖLÜM: her 3 index → 1 üçgen primitive
↓
Rasterizer üçgeni piksele çevirme (bu sayfada yok)
Üstteki şema format okuyucusu içindir shader, clipping ve fragment aşamaları bilinçli olarak kesilmiştir. Assembly ile rasterizer arasındaki sınır: assembly hâlâ «hangi üç köşe?» sorusundadır; rasterizer «ekranda hangi piksel?» sorusuna geçer. Vertex Data §4 «neden üçgen?» sorusunu cevapladı; bu bölüm «index üçlüsü o üçgeni nasıl seçer?» sorusunu cevaplar.
| Aşama | Girdi | Çıktı (kavramsal) |
|---|---|---|
| Vertex buffer | Accessor'dan çözülen float tablolar | Vertex i → POSITION, NORMAL, UV, … |
| Index buffer | UInt üçlü dizisi | «Triangle k için indeksler: a, b, c» |
| Triangle assembly | Index üçlüleri + vertex buffer | Çizim birimi: 3 köşeli yüzey listesi |
| Rasterizer | Üçgen köşeleri (clip uzayı) | Fragment adayları |
glTF mode — Assembly Kuralı
Primitive'deki mode alanı, index (veya non-indexed POSITION) dizisinin
kaç elemanlı gruplar halinde yorumlanacağını söyler. glTF geometri
sayfalarında varsayılan:
mode: 4 → TRIANGLES (her 3 index = 1 üçgen)
mode: 5 → TRIANGLE_STRIP (şerit; bu sayfada detay yok)
mode: 6 → TRIANGLE_FAN (fan; bu sayfada detay yok)
Çoğu üretilmiş mesh mode: 4 kullanır. Bu durumda indices accessor
count değeri 3'ün katı olmalıdır; kat değilse primitive
geçersiz veya export hatasıdır. Basit aritmetik:
üçgen sayısı =
indices.count÷ 3 (TRIANGLES modunda)
Non-indexed primitive'de assembly yine vardır; fark index tablosunun olmamasıdır POSITION listesi doğrudan üçlüler halinde okunur (§2). Assembly adımı «her ardışık üç satır bir üçgen» kuralıyla çalışır; indexed yolda üçlüler indices'ten gelir.
Adım adım assembly: zemin dörtgeni
§1 ve
§2'deki indices = [0, 1, 2,
0, 2, 3] listesini assembly gözüyle okuyalım. Vertex buffer'da dört satır
sabittir; assembly bu satırları yeniden sıralamaz ve kopyalamaz yalnızca hangi
satırların hangi üçgende bir araya geleceğini seçer.
indices = [0, 1, 2, 0, 2, 3]
── Assembly adım 1 ──
Okunan üçlü: 0, 1, 2
Çekilen vertex: POSITION[0], POSITION[1], POSITION[2] → V0, V1, V2
Üretilen primitive: Triangle 0
── Assembly adım 2 ──
Okunan üçlü: 0, 2, 3
Çekilen vertex: POSITION[0], POSITION[2], POSITION[3] → V0, V2, V3
Üretilen primitive: Triangle 1 (V0 ve V2 ikinci kez referanslandı)
V0 ───────────────────────── V1
│ ╲ T0 │
│ ╲ │
│ ╲ T1 │
V3 ───────────────────────── V2
köşegen paylaşımı: V0 · V2
İki assembly adımının sonunda ekranda bir dörtgen yüzey vardır; vertex buffer hâlâ dört satırdır. «6 vertex taşındı» hissi yanıltıcıdır indexed yolda GPU altı index okur, dört benzersiz POSITION satırına referans verir. Bu ayrım §2'deki «benzersiz köşe vs draw okuması» tablosunun draw anındaki karşılığıdır.
Attribute'lar assembly ile birlikte çekilir
Assembly yalnızca POSITION'ı değil, aynı vertex indeksindeki tüm attribute'ları seçer.
Index 2 dediğinizde loader tipik olarak:
POSITION[2] → (x, y, z)
NORMAL[2] → (nx, ny, nz) (varsa)
TEXCOORD_0[2] → (u, v) (varsa)
Semantic tanıtımı Vertex Data §3'te; burada kritik kural: assembly vertex buffer sırasını değiştirmez, satırları silmez, kopyalamaz. Yalnızca «bu üçlü draw için şu indeksler» der. NORMAL / UV hesabı veya eksik attribute debug'ı ilerideki geometri sayfalarına bırakılır.
Sıra burada anlamlıdır detay §4'te
Assembly adımında üçlünün yazılış sırası (0→1→2 mi, 0→2→1 mi) henüz yüzey yönünü belirler. Bu bölümde üçgenin oluştuğunu tarif ediyoruz; ön yüz / arka yüz ve CW / CCW ayrımı §4 · Winding Order'da merkeze alınır. Şimdilik yeterli cümle: assembly üç köşeyi bir araya getirir; sıra, o üçgenin hangi tarafının «ön» sayılacağını etkiler.
Vertex Field Lab ile aynı üçlüler
Metin ve 3D önizleme birbirini tamamlar: Vertex Field Lab · Quad Split modu, bu bölümdeki assembly adımlarının görsel karşılığıdır. Mod değiştirdiğinizde nokta bulutundan iki üçgene geçişi hissedersiniz; bu sayfa aynı geçişin dosya/index okuma dilimini adlandırır. Demo'yu tekrar anlatmıyoruz yalnızca «Triangle 0 / Triangle 1 = assembly çıktısı» bağlantısını kuruyoruz.
Triangle assembly = index buffer'daki her üçlünün, vertex buffer'dan üç köşe seçerek bir çizim primitive'i üretmesi. Dosyada üçgen diye ayrı bir dizi yoktur; üçgenler, indices'in TRİANGLES modunda üçer üçer okunmasıyla oluşur.
Winding Order
§3 triangle assembly ile index üçlüsünün üç köşeyi bir araya getirdiğini gördük. Bu bölümde üçüncü boyut eklenir: üçlünün yazılış sırası. Index buffer yalnızca «hangi köşeler» değil, hangi sırayla birleştirilecekleri sorusunun cevabıdır. Aynı üç vertex, aynı uzaysal konumda kalır; yalnızca index sırası değişirse tarif edilen yüzeyin önü ile arkası yer değiştirir.
Vertex Data §4 bu ayrımı bir notla işaret etmişti; winding order, Index Buffer sayfasında merkeze alınır. Holodepth format okuyucusu için kritik cümle: koordinatlar aynı kalabilir; index sırası değişince çizilen yüzey yönü değişir.
Aynı üçgen, iki yüzey yönü
Zemin örneğinde Triangle 0 köşeleri V0, V1, V2. Index buffer'da bu üçlü iki
şekilde yazılabilir:
0, 1, 2 → V0 → V1 → V2 (bir yönde dolaşım)
0, 2, 1 → V0 → V2 → V1 (ters dolaşım)
Geometrik olarak aynı düzlemdeki aynı üç nokta; fakat GPU ve glTF viewer çoğu zaman yalnızca bir dolaşım yönünü ön yüz (front face) sayar, diğerini arka yüz (back face). Index buffer'da «1» ve «2»nin yer değiştirmesi koordinat taşımaz yalnızca assembly sırasını tersine çevirir.
Üstten bakış (yukarı = +y)
0, 1, 2 → V0 ──────→ V1 Köşeleri bu sırayla birleştirince
╲ bir dolaşım yönü (ör. CCW)
╲
V2
0, 2, 1 → V0 ──────→ V2 Aynı üçgen; köşe gezinti yönü ters
╱ (ör. CW) → karşı yüz sayılır
╱
V1
CW ve CCW saat yönü okuması
Winding order, üçgen düzlemine belirli bir taraftan bakıldığında köşeleri index sırasıyla birleştirirken izlediğiniz dönüş yönüdür:
- CW (clockwise) — saat yönü
- CCW (counter-clockwise) — saat yönü tersi
«Üstten bakış» ifadesi öğretim içindir; gerçek mesh'te kamera her yönden gelebilir. Önemli olan göreli kuraldır: pipeline bir yönü «ön» kabul eder glTF / WebGL ekosisteminde yaygın varsayılan, model uzayında CCW ön yüz kabulüdür (uygulama ve negatif ölçek durumlarında tersine dönebilir; bu sayfada matris detayı yok).
| Index üçlüsü | Köşe dolaşımı | Tipik yorum (CCW = ön varsayımıyla) |
|---|---|---|
0, 1, 2 |
V0 → V1 → V2 | Ön yüz (örnek zemin için) |
0, 2, 1 |
V0 → V2 → V1 | Arka yüz (aynı geometri) |
Tablo tek üçgen içindir; mesh genelinde tüm üçgenlerin tutarlı aynı kurala uyması gerekir aksi halde bazı yüzeyler içe, bazıları dışa bakar («inside-out» veya delikli görünüm).
Backface Culling : Neden Sıra Önemli?
Render pipeline'da backface culling, arka yüz sayılan üçgenleri çizmeden atlar performans ve doğru görünürlük için. Culling açıkken yanlış winding, dosyada veri «doğru» görünse bile ekranda kaybolan yüzey üretir: üçgen vardır, assembly olur, fakat pipeline «bu arka yüz» deyip rasterize etmez.
Format okuyucusu için yeterli zincir:
Index üçlüsü sırası
→ winding (CW / CCW)
→ ön / arka yüz etiketi
→ culling kararı (çiz / atlama)
Shader kodu, depth test ve API bayrakları bu sayfanın dışındadır. Culling mantığının sahne tarafı Three.js · Bounding & Culling hattında genişler; burada yalnızca index sırası ile görünürlük arasındaki format köprüsü kurulur.
Non-indexed yolda da sıra vardır
Winding yalnızca index buffer'a özgü değildir. Non-indexed primitive'de POSITION listesindeki her ardışık üç satırın sırası aynı rolü oynar: satır 0→1→2 bir dolaşım, satırların fiziksel sırasını değiştirmek winding'i değiştirir. Fark, sıranın indices'te mi yoksa POSITION tekrarında mı kodlandığıdır (§2). Assembly §3'te her iki yolda da üçlü okunur; winding §4'te her iki yolda da üçlünün iç sırasına bağlıdır.
glTF: material.doubleSided ve export
tutarlılığı
Primitive hangi malzemeyi kullanırsa, malzeme kaydındaki doubleSided alanı
culling davranışını etkiler:
doubleSided: false(yaygın) yalnızca ön yüz güvenilir; winding hataları görünür kayıp yaratırdoubleSided: trueher iki yüz de çizilebilir; winding hâlâ ışık / normal hesabını etkiler, yalnızca «tamamen yok olma» riski azalır
Export araçları (Blender, glTF exporter vb.) genelde mesh boyunca tutarlı bir CCW veya CW
kuralı yazar. Dosyayı debug ederken primitive'i malzemeden koparmayın: «yüzey yok»
şikâyeti bazen index byte'ından değil, doubleSided + winding kombinasyonundan
kaynaklanır.
Sık görülen format okuma hataları
Winding kaynaklı sorunlar genelde şu üç senaryoda ortaya çıkar:
- Ters export tüm index üçlüleri sistematik olarak CW/CCW ters; mesh «içeri bakıyor» gibi görünür
- Köşegen yönü dörtgeni iki üçgene bölerken
0,1,2 + 0,2,3yerine0,1,3 + 1,2,3gibi alternatif split; geometri doğru, winding tutarsız olabilir - Negatif ölçek node transform mirror içerir; runtime'da winding etkisi tersine döner (transform konusu sahne hattında)
Index buffer byte düzeni veya componentType bu belirtilerin yerine geçmez
önce üçlü sırasını ve malzeme tarafını kontrol edin. Accessor detayı
§6'da.
Winding order = index (veya non-indexed POSITION) üçlüsündeki sıranın, aynı köşeler için hangi yüzey yönünün «ön» sayılacağını belirlemesi. Index buffer hem köşe seçer hem dolaşım yönü yazar; assembly bu yönü somut üçgene taşır.
glTF Tarafı indices Accessor
§1–§5 kavramsal katmanda index buffer'ı tarif etti. Bu bölüm aynı zemin dörtgenini
glTF JSON dilinde gösterir. Vertex Data
§2'de attributes.POSITION: 0
yalnızca konum accessor'ına işaret ediyordu; indexed primitive'de ikinci bir referans gelir:
indices: 1. Buradaki 1 bir köşe koordinatı değil
accessors dizisindeki 1 numaralı kaydın indeksidir.
Örnek JSON — §1'deki zemin dörtgeni
Aşağıdaki parça öğretim amaçlıdır; tam dosya değil. Dört köşe (count: 4),
altı index (count: 6), iki üçgen (§3) ve mode: 4 (TRIANGLES) ile önceki
bölümlerdeki [0, 1, 2, 0, 2, 3] listesine karşılık gelir.
{
"meshes": [{
"primitives": [{
"attributes": {
"POSITION": 0
},
"indices": 1,
"mode": 4
}]
}],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 4,
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5123,
"count": 6,
"type": "SCALAR"
}
]
}
Primitive üzerindeki üç alan
mesh.primitives[0] kaydı geometri okuması için giriş kapısıdır:
attributes.POSITION: 0— «Konum verisi accessors[0] ile okunur» (Vertex Data ile aynı kural)indices: 1— «Üçgen bağlantısı accessors[1] ile okunur»; bu alan yoksa primitive non-indexed sayılır (§2)mode: 4— TRIANGLES; index listesi 3'ün katı uzunlukta yorumlanır (§3)
Primitive koordinat veya index byte'ı taşımaz; yalnızca hangi accessor? sorusunun cevabını tutar. Mesh görünür bir cisim bloğu değil; attribute ve indices referanslarının metadata'sıdır.
Accessor 0 — POSITION (vertex buffer)
accessors[0]
bufferView: 0 → ham byte dilimi (buffers hattında)
componentType: 5126 → FLOAT
count: 4 → dört benzersiz vertex (V0…V3)
type: VEC3 → her vertex (x, y, z)
Bu kayıt Vertex
Data §1'deki dört köşe listesinin dosyadaki
karşılığıdır. Örnekte min / max yazılmadı; gerçek export'larda
POSITION accessor'ında sık görülür (bounding hesabı için). Index accessor'ında genelde
bulunmaz.
Accessor 1 — indices (index buffer)
accessors[1]
bufferView: 1 → ayrı byte dilimi (0 ile aynı .bin içinde olabilir)
componentType: 5123 → UNSIGNED_SHORT (§7'de diğer tipler)
count: 6 → altı index değeri = 2 üçgen × 3
type: SCALAR → her eleman tek tam sayı (vertex indeksi)
Binary tarafta bu altı skaler, örneğin 0, 1, 2, 0, 2, 3 uint16 dizisi olarak
durur. Loader okurken her değer POSITION tablosuna indeks verir: «2» demek
accessors[0]'ın ikinci VEC3 satırını çek demektir; §1'deki işaretçi kuralının
dosya hâli.
İki accessor, iki soru
| Primitive alanı | Accessor # | type |
count (örnek) |
Cevapladığı soru |
|---|---|---|---|---|
attributes.POSITION |
0 | VEC3 |
4 | Köşeler nerede? |
indices |
1 | SCALAR |
6 | Hangi köşeler hangi sırayla üçgen kurar? |
Tablo, önceki bölümlerdeki blockquote ayrımının JSON karşılığıdır: vertex buffer sorusu ·
index buffer sorusu. componentType farkı (5126 float vs 5123 uint16) byte
yorumunu belirler; ayrıntı §7'de.
Buffer zinciri — değişmeyen kural
Hem POSITION hem indices için ham veri yolu aynıdır:
buffers → bufferViews → accessors → primitive alanı
↑
POSITION: bufferView 0 · indices: bufferView 1
İki accessor farklı bufferView indeksleri kullanabilir; GLB içinde genelde aynı
.bin chunk'ının bitişik veya ayrı dilimleridir. Kurallar
Binary Buffers,
BufferView ve
Accessor Mantığı sayfalarında POSITION için anlatıldı; indices yalnızca farklı semantic + SCALAR tipi ekler.
indices yoksa ne olur?
Primitive'de indices anahtarı yoksa mesh non-indexed okunur; Vertex Data
örneğindeki gibi yalnızca attributes.POSITION: 0 kalır. Bu durumda
accessors[0].count genelde üçgen sayısı × 3'tür; bağlantı POSITION sırasına
gömülüdür. Aynı dosyada bir primitive indexed, diğeri non-indexed olabilir; karıştırmayın.
glTF'de index buffer =
primitive.indices→ biraccessorskaydı (type: SCALAR) →bufferView→ byte. Koordinatattributesiçinde değil; bağlantıindicesiçinde ayrı referanslanır.
Index Tipi — componentType
§6 primitive'in
indices: 1
ile bir accessor'a işaret ettiğini ve accessors[1]'in type:
SCALAR olduğunu gösterdi. Bu kapanış bölümü son parçayı netleştirir: binary
tarafta her index değeri kaç byte? Cevap componentType alanındadır. POSITION
accessor'ı için 5126 (FLOAT) + VEC3 öğrenilmişti; indices için
yalnızca tam sayı tipleri geçerlidir; koordinat float'ı değil, vertex satır
numarası okunur.
Holodepth ayrımı: componentType «veri kalitesi» değil, byte okuma
kuralıdır. Yanlış tip, Accessor Lens demosunda olduğu gibi aynı byte'ı yanlış
yorumlatır; index tarafında sonuç genelde saçma üçgenler veya loader hatasıdır.
glTF sabitleri — indices için geçerli tipler
Indices accessor'ında yalnızca unsigned tam sayı componentType değerleri
kullanılır. Her skaler bir vertex indeksidir; aralık, temsil edebileceği en büyük
POSITION satır numarasını sınırlar:
| Sabit | Değer | Byte | Temsil edebileceği max indeks | Tipik kullanım |
|---|---|---|---|---|
UNSIGNED_BYTE |
5121 | 1 | 255 | ≤256 vertex; küçük prop, seyrek |
UNSIGNED_SHORT |
5123 | 2 | 65 535 | Çoğu glTF mesh (§6 örneği) |
UNSIGNED_INT |
5125 | 4 | 4 294 967 295 | 65k+ benzersiz vertex |
Seçim, POSITION count değerine bağlıdır: en büyük geçerli indeks
count − 1'dir. Zemin örneğinde count: 4 → indeksler yalnızca
0…3 aralığında olmalıdır; UNSIGNED_BYTE fazlasıyla yeterlidir. Export aracı
yine de sıklıkla UNSIGNED_SHORT yazar; uyumluluk ve araç varsayılanı
nedeniyle, zorunluluk nedeniyle değil.
Doğrulama kuralı — indeks vs vertex sayısı
Yeni başlayanların sık karıştırdığı iki sayı:
indices.count— kaç index değeri okunur (ör. 6); üçgen sayısı × 3 (§3)attributes.POSITIONaccessorcount— kaç benzersiz vertex satırı var (ör. 4)
Index değerlerinin her biri ikinci sayıya bağlıdır:
0 ≤ index değeri < POSITION
count(her skaler için)
Dört vertex varken index listesinde «6» görmek «altı vertex var» demek değildir; geçersiz
satır numarasına işaret demektir. Sonuç: bozuk geometri, uçan üçgenler veya loader
reddi. Bu, winding veya shared vertex hatasından farklı bir sınıftır; önce
componentType + count çiftini doğrulayın.
Aynı üçlü, farklı byte düzeni
Kavramsal üçlü 0, 1, 2 her tipde aynı anlama gelir; binary düzen değişir:
Üç index: 0, 1, 2
UNSIGNED_BYTE → 00 01 02 (3 byte)
UNSIGNED_SHORT → 00 00 01 00 02 00 (6 byte, little-endian tipik)
UNSIGNED_INT → 12 byte (her indeks 4 byte)
bufferView.byteLength, accessor.count ve
componentType birlikte tutarlı olmalıdır: örneğin 6 × 2 byte = 12 byte
SHORT listesi. Uyumsuzluk, POSITION tarafında olduğu gibi index tarafında da accessor
zincirini kırar.
POSITION float'ı ile karıştırmayın
Aynı dosyada iki accessor yan yana durur; okuma kuralları farklıdır:
accessors[0] componentType 5126 type VEC3 → float üçlü koordinat
accessors[1] componentType 5123 type SCALAR → uint16 vertex indeksi
Index buffer'a FLOAT uygulamak format ihlalidir. Format okuyucusu indices satırında «koordinat mı, satır numarası mı?» diye sorar; cevap her zaman satır numarasıdır (§1).
Runtime köprüsü — kısa atıf
Loader, componentType'a göre typed array üretir (Uint16Array,
Uint32Array vb.). WebGL draw limitleri ve API tarafı
Three.js · Indexed vs Non-Indexed · index tipi sayfasında
anlatılır. Bu sayfa format hattında kalır: dosyada hangi sabit yazılı, POSITION
count ile uyumlu mu?
Index Buffer sayfası — durma noktası
§1–§7 birlikte şu zinciri tamamlar: index buffer nedir → indexed / non-indexed → assembly
→ winding → shared vertex → glTF indices accessor → byte tipi. Shader,
VAO binding ve buffer upload bu hattın dışındadır. Normal, UV ve diğer attribute'ların
geometri hattındaki yeri bir sonraki sayfalara bırakılır.
Index Buffer format okuması:
primitive.indices→SCALARaccessor →componentTypeile uint dizisi → her değer POSITION tablosuna indeks → assembly ile üçgen. Bu cümleyi kurabiliyorsanız sayfa görevini tamamladınız.
Demo · Surface Compiler Lab
Vertex Field Lab Geometry Data hattını anlatır: koordinatlar, nokta, tek primitive. Bu laboratuvar ise Geometry Topology hattıdır; aynı dört köşe (glTF'de V0–V3) kullanılır ama soru değişir: hangi düğümler birbirine bağlı? Mesh burada çizilmez; derlenir. Index buffer bağlantı tablosudur; assembly bu tabloyu yüzeye çevirir.
Nasıl kullanılır? Sahnedeki düğümler (N0–N3) octahedron pin olarak durur; bakır renkli çizgiler connection stream'dir. Sol panelde Nodes / Primitives / Hubs sayacı topoloji metriklerini gösterir. Vertex Field'daki küre + cyan halo burada bilinçli olarak yok; farklı metafor, aynı matematik.
Beş derleme aşaması
- Node Matrix — Dört düğüm hazır; POSITION lookup bekliyor, bağlantı yok (§1).
- Connection Stream — Index akışı
N0→N1→N2; bakır izler yanar, yüzey henüz dolu değil — yalnızca topoloji okunuyor (§3). - Topology Build — İlk primitive derlenir; CCW / CW ile yüz yönü seçilir (§4).
- Shared References — İkinci bağlantı pass'i; N0 ve N2 hub olarak iki primitive'e referans verir (§5).
- Compiled Surface — Tam çıktı tablosu
[0,1,2,0,2,3]+UNSIGNED_SHORT(§7).
Node matrix · connection stream · compile pipeline · hubs
Derleme aşaması
Derleyici paneli · TOPOLOGY
Node registry · N0–N3 → idx
Compile pipeline
3D · topology compile
Bu demo ne hissettirir? Vertex Field «nokta → üçgen» der; Surface Compiler «bağlantı → yüzey» der. Node Matrix'te koordinatlar vardır ama topoloji yoktur. Connection Stream'de bakır izler akar; henüz dolu mesh yok. Topology Build'de ilk yüzey derlenir. Shared References hub düğümlerini gösterir. Compiled Surface draw-ready çıktıdır. Demo bittiğinde şu ayrımı kurabilmelisiniz: «Vertex = veri; Index = bağlantı; Mesh = derlenmiş topoloji.»