3D Model Formatları · glTF / GLB · Dosya Yapısı
BufferView Sistemi: Verinin Tam Olarak Nerede Olduğu
Dosya yapısı serisinde zincir şu ana kadar şöyle ilerledi: JSON yapısı sahneyi organize etti; binary buffer ham veriyi depoladı; accessor baytların nasıl okunacağını söyledi. Bu sayfa anatominin adres katmanıdır: accessor «VEC3 float oku» der peki buffer’ın hangi kısmından?
Cevap: BufferView. Vertex attribute düzeni,
POSITION / NORMAL / UV kanalları, geometri üretimi,
GPU upload hattı, interleaved layout veya Three.js BufferAttribute
API’si bu sayfada işlenmez her biri ayrı konudur. Odak tek soruda:
«Buffer içerisindeki ham verinin tam olarak hangi bölümünün kullanılacağını kim
tanımlar?»
Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «Buffer büyük bir bayt havuzudur; bufferView bu havuz içerisindeki belirli bir bölgeyi tanımlar.»
BufferView Nedir?
Önce problemi kurun. Binary buffer sayfasında gördük: tek bir havuzda position, normal, UV ve indeks verisi yan yana durabilir sürekli, etiketsiz bir octet şeridi. Accessor ise okuma kuralını verir:
FLOAT · VEC3 · count 1024
Bu talimat «her eleman üç float, toplam 1024 eleman» der. Fakat doğal soru hâlâ cevapsızdır: «Nereden başlamalı?» Havuzun başından mı? Ortasından mı? İndeks bloğunun hemen ardından mı? Accessor tek başına bu soruya cevap veremez çünkü görevi yorum tarif etmektir, adres tarif etmek değil.
BufferView, glTF JSON’undaki bufferViews tablosunun bir
kaydıdır. Görevi: belirli bir buffers girişinin içinde hangi bayt
aralığının «görünür dilim» olarak kullanılacağını tanımlamak. Veri taşımaz;
buffer’daki octet’leri kopyalamaz; yalnızca «şu ofsetten şu uzunluğa kadar» der
pencere tanımıdır.
Eksik halka: «hangi bayt?»
Accessor–buffer zinciri bölümünde üç halkalı yol çizildi: accessor → bufferView → buffer. Accessor sayfası «nasıl oku» sorusuna odaklandı; «nereden oku» sorusunu bilinçli olarak buraya bıraktı. Bu ayrım tesadüf değildir: glTF’de yorum ile adres farklı sorumluluklardır. Aynı dilim farklı accessor kurallarıyla okunabilir; aynı accessor kuralı farklı dilimlere uygulanabilir esneklik, katmanların ayrılmasından gelir.
Pratik sonuç: hex editörde buffer’ın tamamını görürsünüz; hangi bölümün «position bloğu»
olduğunu buffer söylemez. JSON’da ilgili bufferViews[i] kaydını açarsınız
orada byteOffset ve byteLength yazar. İşte bufferView’in işi bu
aralığı resmen tanımlamaktır.
Tablo kaydı, veri bloğu değil
bufferViews dizisindeki her öğe küçük bir JSON nesnesidir megabyte’lık binary
içeriği metne gömmez. Tipik alanlar: hangi buffer (buffer indeksi), nereden
başla (byteOffset), kaç bayt (byteLength), isteğe bağlı
byteStride (bu sayfada detaylandırılmaz; interleaved layout sonraki geometri
konularına bırakılır). Kayıt «talimat» niteliğindedir: loader binary’yi açtığında bu
sayılara göre alt dizin (slice) mantığı uygular.
Buffer İçindeki Bir Pencere
§1'de bufferView'in «adres defteri girişi» olduğunu gördük; bu bölüm aynı fikri görselle oturtur. BufferView'i anlatmanın en net yolu pencere metaforudur: buffer uzun, sürekli bir banttır; bufferView o bant üzerinde kayan, sabit boyutlu bir «görünüm» açar. Octet'ler yerinde kalır; taşınmaz, kopyalanmaz. BufferView yalnızca «şu aralığa bak» der; pencerenin dışındaki baytlar bu kayıt için görünmez sayılır.
Buffer (4096 byte)
0────────────────────────────────────────4096
BufferView #0 — «position dilimi»
┌────────── 12288 byte ──────────┐
0─────────┤ POSITION ├────4096
└────────────────────────────────┘
↑ byteOffset=256 byteLength=12288
Şemayı satır satır okuyun. Üst çizgi tüm havuzun sınırlarını verir: modelin binary
deposu tek parça. Ortadaki kutu, bufferViews[0] kaydının işaret ettiği
dilimdir; bufferView havuzun tamamını değil, yalnızca
byteOffset ile byteLength arasında kalan segmenti «position
bloğu» olarak ilan eder. Sol taraftaki boşluk (0–255) bu kayıt için padding veya başka
bir bloğun alanı olabilir; bufferView o bölgeye bakmaz. Sağdaki kalan bant da aynı
buffer içinde durur; başka bir bufferViews[i] kaydı onu tanımlayana kadar
loader için isimsiz octet'tir.
byteOffset sıfır olabilir; dilim en baştan başlar. Zorunlu değildir. Export
araçları hizalama, başlık baytı veya önceki attribute blokları nedeniyle ara boşluk
bırakır; bufferView bu boşluğu atlayarak «asıl veri burada» der. Önemli nokta:
ofset ve uzunluk bayt cinsindendir; float sayısı veya vertex adedi değil.
Kaç köşe olduğunu hâlâ accessor söyler; bufferView yalnızca «bu accessor, buffer'ın şu
diliminden okunacak» adresini verir.
Dilim, görünüm, pencere — aynı fikir
Farklı kaynaklarda «slice», «view», «window» sözcükleri geçer; glTF spesifikasyonunda resmi
ad bufferView'dir. Ortak nokta: fiziksel depo
değişmez, yalnızca hangi alt aralığın anlamlı kabul edileceği tanımlanır.
JavaScript'te ArrayBuffer üzerinde slice() düşünmek benzer bir
sezgi verir; fakat glTF'de dilim tanımı JSON'da saklanır, loader çalışma anında uygular.
Dosyayı kapattığınızda binary aynı kalır; değişen yalnızca «hangi alt aralığın position
sayıldığı» kaydıdır.
Bir bufferView kaydı tek bir aralık tanımlar. «Position + normal aynı
kayıtta» gibi birleşik alan yoktur; her mantıksal blok (position, normal, UV, indices)
genelde ayrı bir bufferView indeksi alır. Aynı buffer #0 üzerinde
yan yana durabilirler; her biri farklı byteOffset / byteLength
ile kendi penceresini çizer. Bu organizasyon
6. bölümde genişletilir.
Kısa özet: bufferView, accessor'ın «nasıl oku» talimatına eklenen «nereden başla, kaç bayt» cevabıdır. Pencere metaforu bozulmadan kalır; yalnızca artık o pencerenin buffer içindeki konumu ve boyutu sayısal alanlarla okunabilir hale gelir.
BufferView Veri Taşımaz
§2'de bufferView'i «pencere» olarak gördük: buffer içinde bir aralık işaret eder. Bu bölümde vurgu daha net: bufferView veri taşımaz. Yalnızca «şu baytlar bu kayıt için geçerli» der. Accessor sayfasındaki «kopya üretmez» fikriyle aynı ailedendir; bufferView tarafında bu kural daha da keskindir çünkü JSON kaydının içinde hiçbir zaman ham sayı listesi yoktur.
- Veri değildir: Kayıtta position float'ları veya index integer'ları yazılı değildir; yalnızca buffer indeksi, ofset ve uzunluk gibi adres alanları vardır.
- Kopya değildir: Loader binary'den ayrı bir bellek bloğu ayırmak zorunda değildir; «buffer #0'ın şu dilimine bak» demek yeterlidir.
- Yeni depo oluşturmaz: Model başına bir (veya birkaç) buffer yeterlidir; her bufferView ekstra havuz icat etmez, mevcut havuz üzerinde yeni bir pencere açar.
Aşağıdaki örnek tipik bir kayıttır; üç alanın her biri §2'deki pencere metaforunun sayısal karşılığıdır:
{
"buffer": 0,
"byteOffset": 256,
"byteLength": 1024
}
Okuma sırası basittir: buffer: 0 hangi havuza bakılacağını,
byteOffset: 256 dilimin nereden başlayacağını,
byteLength: 1024 kaç bayt okunacağını söyler. Position veya normal
içeriği bu JSON'da yoktur; içerik hâlâ orijinal binary'de durur. BufferView
yalnızca adres defteri girişidir.
Accessor'ın kopya
üretmemesi ile birlikte düşününce resim netleşir: büyük binary bir kez yüklenir;
accessor ve bufferView üstüne referans katmanları ekler; veri tekrar tekrar kopyalanmaz.
Buffer taşır, bufferView sınırlar
Buffer
octet'leri fiziksel olarak taşır; GLB içindeki binary chunk veya harici .bin
dosyasıdır. BufferView ise o octet'lerin hangi alt aralığının anlamlı dilim
sayılacağını JSON'da yazar. İkisi birbirinin yerine geçemez: bufferView olmadan buffer
«uzun ama isimsiz» bir şerittir; hangi bölümün position, hangisinin UV olduğu belli
değildir. Buffer olmadan bufferView ise boş bir adrestir; işaret edecek octet yoktur.
BufferView Hangi Soruları Cevaplar?
3. bölümde bufferView’in veri
taşımadığını, yalnızca aralık tanımladığını gördük. Somut hali bufferViews
tablosundaki küçük JSON kayıtlarıdır. Loader, accessor’dan «nasıl oku» cevabını aldıktan
sonra binary’ye uzanmadan önce bir dizi adres sorusu daha sorar cevaplar
bufferView alanlarında yazar. Bu bölüm o soruları görev odaklı listeler:
«loader bu kayıtla buffer içinde nereye bakacağını nasıl bilir?»
BufferView’in görev alanı dar ve net tutulmalıdır. Üç temel soruya cevap verir; tablonun dördüncü satırı bilinçli olarak «cevap yok accessor’un işi» der. Tip, eleman sayısı, semantic ad veya GPU eşlemesi burada işlenmez; amaç bufferView’in hangi boşlukları doldurduğunu netleştirmektir.
Dilimleme öncesi: hangi havuz?
Binary
buffer sayfasında tek bir modelde birden fazla mantıksal blok yan yana durabilir.
Bazı glTF dosyalarında birden fazla buffers girişi de olabilir geometri bir
havuzda, küçük gömülü görsel başka bir havuzda. BufferView kaydı açılmadan loader «hangi
depoya bakacağım?» sorusunu yanıtlayamaz; bu yüzden tablonun ilk satırı
buffer indeksine aittir.
Accessor sayfasındaki «okuma öncesi talimat» sırasına paralel olarak bufferView de binary’ye dokunmadan önce okunur: önce hangi havuz, sonra hangi ofset, sonra kaç bayt. Adres netleşmeden accessor kuralları uygulanamaz aksi halde doğru tip yanlış bellek bölgesinden okunur.
Aşağıdaki tablo dört satırlık bir özet sunar. İlk üç satır bufferView’in asıl görev alanını; dördüncü satır ise bilinçli sınırı işaret eder. Alan adları JSON’da göründüğü haliyle bırakılmıştır ki dosyayı açtığınızda doğrudan eşleştirebilesiniz.
| Soru | Alan | BufferView cevabı |
|---|---|---|
| Hangi buffer? | buffer |
buffers tablosundaki indeks örn. 0 |
| Nereden başla? | byteOffset |
Havuz içindeki başlangıç baytı örn. 256 |
| Kaç bayt oku? | byteLength |
Dilimin uzunluğu örn. 1024 |
| Nasıl yorumlanacak? | Accessor’un işi (accessor soruları) |
Tablodaki üç satır neden ayrı ayrı?
İlk üç satır birbirinin yerine geçmez loader’ın güvenli bir dilim seçebilmesi için hepsinin birlikte yanıtlanması gerekir. Tablo hücrelerini tekrarlamak yerine her satırın neden ayrı bir soru olduğu şöyle düşünülebilir:
buffer(hangi havuz): glTF’de birden fazla binary kaynağı olabilir. Bu alan «buffersdizisinin kaçıncı elemanı?» der. Ofset ve uzunluk, seçilen havuzun içinde anlamlıdır; buffer indeksi olmadanbyteOffset: 256hangi şeride ait olduğu belirsiz kalır.byteOffset(nereden): Seçilen havuzun kaçıncı baytından itibaren dilim başlar? Sıfır en baştan demektir; sıfır olmak zorunda değildir export araçları hizalama veya padding için ara boşluk bırakabilir. Bu alan «pencerenin sol kenarı»dır; içeriğin tipi veya anlamı hakkında bilgi taşımaz.byteLength(ne kadar): Dilimin sağ sınırı ofsetten itibaren kaç octet «bu bufferView’e ait» sayılır. Okuma bu sınırı aşmamalıdır; validator’lar genelde «ofset + uzunluk ≤ buffer.byteLength» koşulunu kontrol eder. Uzunluk, accessor’dakicountile uyumlu olmalıdır; fakat count’un kendisi bufferView’de değil, accessor’da tanımlanır iki alanın ilişkisi aşağıda birleşir.
Dördüncü satır: bilinçli sınır
Tablonun son satırı negatif bir cevap değil, görev ayrımıdır. «Nasıl
yorumlanacak?» sorusu bufferView kaydında aranmamalı orada componentType,
type veya count yoktur. BufferView «256’dan 1024 bayt» der;
accessor «o aralıktaki baytları VEC3 float olarak şu kadar eleman say» der. İkisini
karıştırmak, dosyayı okurken «bufferView position verisidir» sanmaya eşdeğerdir; oysa
position değerleri buffer’da, fiziksel konum bufferView’de,
biçim accessor’da durur.
Accessor sayfasında «buffer içinde tam ofset» sorusunun bufferView’e ait olduğu yazılmıştı; bu bölüm tam tersi perspektifi verir: bufferView «tip nedir?» sorusuna cevap vermez o soru accessor tablosundadır.
BufferView'in cevaplamadığı sorular
Yukarıdaki tablo loader'a adres ve dilim sınırları hakkında bilgi verir. Aşağıdaki sorular ise başka katmanlara aittir; cevabını bufferView kaydında aramayın:
- «Bu baytlar float mı, short mu?»
Cevap accessor
componentTypealanındadır (accessor · tip sorusu). - «Kaç vertex / kaç eleman?»
Cevap accessor
countalanındadır. BufferView yalnızca «bu dilimde en fazla şu kadar bayt var» der; kaç mantıksal eleman olduğunu accessor hesaplar. - «Bu dilim position mu, normal mi?»
Cevap primitive
attributesharitasındadır. BufferView kaydında semantic ad yoktur (accessor · etiket değildir). - «Buffer fiziksel olarak nerede?»
URI, GLB chunk veya base64 bağlantısı
bufferstablosundadır (buffer · havuz ≠ dosya). BufferView yalnızca mantıksal buffer indeksine bakar. - «GPU'da hangi VBO'ya gider?» Motor ve upload katmanının konusudur; glTF bufferView tanımının dışındadır.
Bu ayrımı net tutmak önemlidir. BufferView «buffer #0'ın 36864. baytından sonra 12288 bayt» der; «bu normal verisidir» demez. Adres ile anlam bilinçli olarak ayrılır. Böylece aynı dilim, farklı accessor kurallarıyla yeniden okunabilir; format esnekliği bu katman ayrımından gelir.
Yanıtlar birleşince: dilim cümlesi
Tablodaki üç cevap tek tek «depo adresi» parçalarıdır; birleşince loader için tek bir dilim cümlesi oluşur. Örneğin:
buffer #0 · offset 36864 · length 36864
cümlesi «buffers[0] havuzunda 36864. bayttan başlayarak 36864 octet oku
bu aralık bufferView #1’in sınırlarıdır» anlamına gelir. Accessor eklendiğinde cümle
genişler:
accessor
sayfasındaki «bufferView #0’daki baytlardan 1024 VEC3 float oku» ifadesinde
sol yarı (hangi bayt aralığı) bufferView’den,
sağ yarı (nasıl oku) accessor’dan gelir.
İsteğe bağlı byteStride alanı tabloda ayrı satır olarak durmaz dilim
düz blok değil «adım adım yürünecek şerit» olduğunda devreye girer. Temel üç alan
(buffer, byteOffset, byteLength) yanıtlandığında
loader dilimi seçmeye hazırdır; yorumlama
5. bölümde accessor ile
yan yana sabitlenir, runtime sırası
9. bölümde özetlenir.
İsteğe bağlı: byteStride
Bazı kayıtlarda byteStride alanı bulunur; interleaved vertex layout’ta
ardışık öznitelikler arasındaki bayt mesafesini tanımlar. Bu sayfa interleaved düzeni
öğretmez yalnızca alanın varlığını not eder: bufferView bazen «düz blok»
(yalnızca ofset + uzunluk) bazen «her vertex kaydı arasında şu kadar bayt atla» tanımlar.
Stride, tablodaki üç temel soruya ek bir adres kuralıdır; tip, count veya semantic
hâlâ accessor ve primitive tarafındadır. Detay geometri / vertex layout konularına
bırakılır.
Accessor ve BufferView Arasındaki Fark
4. bölümde dilim cümlesi oluştu; accessor tarafındaki karşılığı accessor sayfasında «okuma cümlesi» olarak anlatıldı. Bu bölüm iki katmanı yan yana koyar ve görevlerin neden üst üste binmediğini netleştirir. Tip, count, semantic veya GPU detayı burada genişletilmez; odak yalnızca «nasıl» ile «nereden» ayrımıdır.
Üç katman, üç farklı soru sorar; cevaplar birbirinin yerine geçmez:
- Accessor: «Bu veri
VEC3FLOATolarak okunacak.» nasıl? - BufferView: «256. bayttan başla, şu kadar octet.» nereden?
- Buffer: «İşte ham octet'ler.» ne saklanıyor? (anlam yok)
Accessor çevirmen «baytları şöyle oku» der. BufferView haritada «şu mahalle» sınırını çizer; tip seçmez, eleman sayısı vermez. Buffer arazinin kendisidir: içerik orada, etiket yok (buffer kördür).
Üç soru, tek okuma
Loader binary tarafında tek bir okuma yapar; bu okuma üç JSON kaydının cevabını birleştirerek oluşur. BufferView olmadan accessor «1024 VEC3 float» der ama hangi octet'ten başlanacağı belirsiz kalır (accessor · eksik halka). Accessor olmadan bufferView «36864 bayt dilim» der ama o dilimdeki octet'lerin float mı short mu olduğu belirsiz kalır (4. bölüm · dördüncü satır).
Pratik sıra şöyledir: önce dilim seçilir (bufferView), sonra dilime yorum uygulanır (accessor). Buffer en altta ham octet'leri sağlar. Kısaca «önce adres, sonra biçim»; bu sıra ters çevrilirse aynı tip kuralı yanlış bellek bölgesine uygulanabilir.
Görevler neden birleşmez?
«Accessor'a byteOffset ve byteLength de yazsak; bufferView'e gerek
kalmaz mı?» sorusu doğaldır. glTF bunları ayırır çünkü adresleme ile yorumlama
farklı ölçeklerde tekrarlanır:
- Tek buffer, çok dilim: Aynı havuzda position, normal, UV ve indeks yan yana durur (veri havuzu). Her dilim ayrı bufferView kaydı alır; her kanal için accessor ayrı «nasıl oku» tarifi verir. Ofset ve uzunluk her accessor'da tekrarlansaydı JSON şişer; export araçları segmentasyonu merkezi yönetemez.
- Tek dilim, farklı yorum (nadir): Aynı bayt aralığı teorik olarak farklı accessor kurallarıyla okunabilir. Pratikte her kanal kendi çiftine sahiptir: adres bir kez bufferView'de, yorum accessor'da tanımlanır.
- Referans yönü: Accessor
bufferViewindeksine bakar; bufferViewbufferindeksine bakar. Ters referans yoktur; buffer üst katmanları bilmez.
Accessor sayfasındaki «neden arada bufferView var?» sorusu aynı mimari kararı anlatır. Bu sayfa aynı farkı bufferView gözlüğünden özetler: bufferView tek başına «nasıl»ı bilmez; accessor tek başına «nereden»i bilmez.
JSON'da birlikte okumak
Dosyayı açtığınızda zincir yalnızca accessors dizisinde görünmez; üç binary
tablo birlikte okunur. En altta buffers fiziksel havuzu tanımlar (URI veya GLB
chunk). Ortada bufferViews havuz içindeki dilimleri listeler. Üstte
accessors dilime uygulanacak okuma kuralını yazar. Accessor doğrudan buffer
URI'si taşımaz; arada bilinçli bir
ara
katman vardır. Aşağıdaki alt bölümler bufferView ↔ accessor
eşleşmesini JSON üzerinden adım adım gösterir; tip enum'ları ve primitive
attribute haritası genişletilmez.
JSON yapı
blokları bölümünde bufferViews «buffer içindeki bayt aralığı»,
accessors «bufferView üzerinden tip tanımı» olarak listelenir. Bağlantı
indeks diliyle kurulur: kayıtlar birbirine gömülü nesne değil, dizi sıra
numarasıyla birbirine bağlanır; tıpkı materials veya meshes
referansları gibi
(accessor · indeks dili).
Referans yönü: aşağı iner, yukarı çıkmaz
Zincirde okuma yönü tek yönlüdür: accessor → bufferView → buffer. BufferView kaydında «hangi accessor'lar beni kullanıyor?» listesi yoktur; buffer kaydında «hangi dilimler var?» yazmaz. Her katman yalnızca bir alt katmana işaret eder. Loader, primitive veya animasyon kanalı «accessor #N» dediğinde yukarıdan aşağı iner; ters yönde tarama glTF modelinde tanımlı değildir.
buffers tablosu örnekte görünmez ama zincirin tabanıdır. Tipik giriş şöyle
özetlenir: «buffer #0, toplam byteLength şu kadar; veri şu URI/chunk'ta.»
BufferView kayıtları bu havuzun içinde konumlanır; accessor kayıtları bufferView
indeksine referans verir. Üç tablo birlikte «depo → dilim → yorum» hiyerarşisini tamamlar.
Aşağıdaki parça sadeleştirilmiştir: iki bufferView dilimi, iki accessor. İkisi de aynı
okuma kuralını paylaşır; farklı dilimlere işaret ederler. componentType: 5126
glTF'de float anlamına gelir; ayrıntı
accessor
· çevirmen örneği bölümündedir. Burada yalnızca «aynı tip, farklı adres» vurgulanır.
"bufferViews": [
{ "buffer": 0, "byteOffset": 0, "byteLength": 36864 },
{ "buffer": 0, "byteOffset": 36864, "byteLength": 36864 }
],
"accessors": [
{ "bufferView": 0, "componentType": 5126, "type": "VEC3", "count": 3072 },
{ "bufferView": 1, "componentType": 5126, "type": "VEC3", "count": 3072 }
]
Takip: accessors[0]
İlk accessor kaydını adım adım çözün:
bufferView: 0→bufferViews[0]kaydına git.- Orada
buffer: 0→ veribuffers[0]havuzundadır. byteOffset: 0,byteLength: 36864→ dilim havuzun en başından 36864 octet.- Accessor tarafında
type: "VEC3",count: 3072,componentType: 5126→ bu dilimden 3072 adet üçlü float oku.
BufferView 2. ve 3. adımlara cevap verir: hangi havuz, hangi ofset, kaç bayt. Accessor 4. adıma cevap verir: o aralığı nasıl kesip yorumlayacağınız. İkisi birleşince birleşik cümle oluşur; henüz «position» veya «normal» adı devreye girmez.
Takip: accessors[1] aynı
kural, farklı dilim
İkinci accessor «nasıl oku» sorusuna aynı cevabı verir (3072 × VEC3 float).
Fark bufferView: 1 indeksindedir:
bufferViews[1]→ yinebuffer: 0(aynı fiziksel havuz).byteOffset: 36864→ dilim birinci dilimin bittiği yerden başlar.byteLength: 36864→ yine 36864 octetlik pencere; bu kez havuzun ikinci segmenti.
Bu örnek §6'daki «bir buffer, birçok bufferView» organizasyonunun JSON karşılığıdır: tek
buffers[0], iki ardışık dilim. Export aracı veriyi aynı .bin / GLB chunk'a yan
yana yazmış; JSON'da iki bufferView ile sınırlarını çizmiştir. Mesh primitive'i bu kayıtlara
doğrudan bufferView ile değil, accessor indeksiyle bağlanır. Örneğin
"POSITION": 0, "NORMAL": 1 «0. accessor kuralını position kanalı
için kullan» der; dilim adresi accessor → bufferView zincirinden gelir.
JSON'da olmayan şeyler
Örnek parçada bilinçli olarak yer almayan alanlar, ayrımı net tutmak içindir:
- Semantic ad (
POSITION,NORMAL): bufferView veya accessor kaydında yok; primitiveattributesharitasında (accessor · etiket değildir). - Ham float değerleri: JSON'da değil;
buffers[0]binary'sinde (binary buffer). - Accessor iç
byteOffset: isteğe bağlı; dilim içi kaydırma sonraki alt bölümde.
Özet: JSON parçası «adres + yorum» eşleşmesini gösterir. İki accessor aynı okuma kuralını paylaşır; farklı bufferView indeksleri farklı «nereden» cevabı verir. Bu sayfa yalnızca fiziksel adres ayrımını vurgular; kanal adları ve sahne anlamı üst organizasyon katmanındadır.
İki ofset: bufferView ve accessor
Karışıklığın sık kaynağı: her iki kayıtta da byteOffset alanı vardır. Görevleri
farklıdır:
- bufferView.byteOffset: Seçilen
buffers[i]havuzuna göre mutlak başlangıç. «Pencerenin sol kenarı buffer'ın neresinde?» - accessor.byteOffset (isteğe bağlı): Seçilen bufferView diliminin içinde ek kaydırma. «Pencere açıldıktan sonra birkaç bayt daha atla.»
Birleşik formül: gerçek başlangıç = bufferView.byteOffset + accessor.byteOffset (accessor ofseti yoksa sıfır kabul edilir). Bu sayfa bufferView ofsetini merkeze alır; accessor iç ofseti «dilim içi ince ayar»dır. Örneğin aynı interleaved bufferView içinden yalnızca position bileşenine atlamak için kullanılabilir (interleaved mekanik bu sayfada işlenmez). Karışıklığı önlemek için şunu hatırlayın: bufferView buffer'a göre, accessor bufferView'e göre konumlanır. İkisi aynı «ofset» sözcüğünü paylaşsa da referans çerçeveleri farklıdır.
Birleşik cümle: adres + yorum
§4'teki dilim cümlesi ile accessor okuma cümlesi birleşince loader şunu uygular:
bufferViews[1] dilimi · 3072 × VEC3 · FLOAT
Yani: «buffers[0]'ın 36864. baytından başlayan 36864 octetlik dilimde, 3072
adet üçlü float oku.» Sol parça bufferView, sağ parça accessor. Buffer'ın kendisi bu
cümlede yalnızca «octet'ler orada» olarak varsayılır
(veri +
yorumlama = anlam formülünde «veri» buffer'da, «yorumlama» accessor'da; bufferView
arada «hangi veri parçası» köprüsüdür).
Sık karıştırılan noktalar
Dosyayı incelerken veya loader yazarken şu hatalar bufferView–accessor ayrımını bozar:
- «bufferView = position verisi»: bufferView yalnızca aralık tanımlar; position değerleri buffer'da, kanal adı primitive'de.
- «accessor buffer'a doğrudan bağlanır»: glTF'de tipik yol accessor → bufferView → buffer; URI veya chunk bilgisi buffer tablosundadır.
- «byteLength = vertex sayısı»:
byteLengthoctet cinsinden dilim boyutudur; eleman sayısı accessorcountile gelir. İkisinin tutarlılığı doğrulama konusudur. - «Aynı bufferView = aynı semantic»: Aynı dilim farklı amaçlarla okunabilir; semantic eşlemesi primitive tarafındadır.
Bu sınırlar netse §6'daki «bir buffer, birçok bufferView» organizasyonu ve §10'daki «accessor tek başına çalışamaz» özeti doğal olarak oturur. Runtime sırası 9. bölümde kısaca özetlenir; adım adım loader walkthrough accessor sayfasında accessor perspektifinden anlatılır; burada tekrarlanmaz.
Aynı Buffer İçinde Birden Fazla BufferView
Tek havuz, birden fazla tüketici fikri bufferView ile somutlaşır. Tipik bir geometri export’unda aynı buffer şeridi mantıksal segmentlere bölünür; her segment ayrı bufferView kaydı alır:
-
bufferView 0Position dilimi · offset 0 -
bufferView 1Normal dilimi · offset 36864 -
bufferView 2UV dilimi · offset 73728 -
bufferView 3Indices dilimi · offset 86016
Şemadaki isimler (position, normal, UV, indices) yalnızca tipik paketleme düzenini anlatır bufferView kayıtları bu isimleri taşımaz; yalnızca sayısal aralık taşır. Anlam, accessor + primitive semantic birleşiminde gelir. Önemli fikir: bir buffer, birçok bufferView tıpkı bir dosyada birden fazla bölüm tanımlamak gibi.
Çakışmayan aralıklar
Sağlıklı export’ta bufferView dilimleri genelde birbirini kesmez; her biri farklı
byteOffset / byteLength çifti kullanır. Teoride örtüşen aralıklar
mümkün olsa da pratikte nadir ve kafa karıştırıcıdır bu sayfa örtüşme senaryolarına
girmez; odak net segmentasyon üzerindedir.
Bir bufferView, birden fazla accessor?
Evet aynı
buffer’dan
birden fazla accessor mantığı bufferView dilimine de uygulanabilir. Aynı dilim
farklı
count / type kurallarıyla okunabilir (nadir ve dikkat gerektirir).
Ters yönde: her accessor tipik olarak bir bufferView’e işaret eder; dilim paylaşımı bellek
verimliliği için kullanılır.
Neden Ayrı BufferView Katmanı Var?
5. bölümde accessor ile bufferView görevlerinin ayrıldığını; 6. bölümde tek buffer’ın birçok dilime bölündüğünü gördük. Bu bölüm «neden?» sorusuna mühendislik cevabı verir format tasarımının bilinçli kararıdır, sonradan eklenmiş bir kolaylık değildir. GPU pipeline, sıkıştırma extension’ları veya vertex layout detayı işlenmez; odak «adresleme katmanı neden ayrı tabloda durur?» sorusundadır.
«Accessor doğrudan buffer’a ofset yazsa olmaz mı?» sorusu doğaldır. glTF bufferView’i ara katman olarak koyar çünkü birkaç mühendislik ihtiyacını aynı anda karşılar:
- Veriyi kopyalamamak: Binary bir kez yüklenir; üst katmanlar aynı octet'lere referans verir. Accessor kopya üretmez; bufferView de üretmez. İkisi birlikte «tek kaynak, çok görünüm» modelini kurar.
- Bellek tekrarını önlemek: Aynı buffer şeridini birden fazla mesh paylaşabilir. Her tüketici kendi dilimini ayrı bir bufferView kaydıyla işaret eder; veri ikinci kez yazılmaz.
- Tek buffer kullanabilmek: Export araçları geometriyi genelde tek havuza paketler. BufferView segmentleri, loader'a «bu aralıkta ne var?» sorusunun cevabını JSON'da toplar.
- Yükleme maliyetini azaltmak: Dosya açılışında binary bir kez okunur; küçük bufferView kayıtları onu mantıksal dilimlere böler. Her kanal için ayrı dosya veya ayrı bellek tahsisi gerekmez.
- Standart veri organizasyonu: Adres bufferView'de, yorum accessor'da kalınca export araçları, validator'lar ve loader'lar aynı spec dilini konuşur.
Tek kaynak, çok görünüm
Binary buffer katmanı zaten «ham veriyi bir kez depola» kararını vermiştir. BufferView bu kararın devamıdır: havuz belleğe alındıktan sonra her kanal için ayrı bellek bloğu allocate etmek gerekmez. JSON’daki küçük kayıtlar «şu aralığa bak» der; binary fiziksel olarak tek yerde kalır. Accessor aynı dilimi farklı biçimde okuyabilir (nadir); bufferView aynı dilimi farklı accessor’lara sunabilir her iki yönde de octet’ler taşınmaz, yalnızca referans ve yorum değişir.
Paylaşım: aynı havuz, çok tüketici
Tek havuz, birden fazla tüketici fikri pratikte sık görülür: bir karakter modelinde tüm mesh geometrisi tek büyük .bin şeridine paketlenir; farklı parçalar farklı bufferView dilimlerine işaret eder. BufferView olmadan ya her mesh için buffer kopyası gerekir ya da accessor’a tekrarlayan «global ofset» alanları yazılır ikisi de bellek israfına gider. Dilim tablosu «paylaşılan depodan şu pencereyi kullan» der; kopya yoktur.
Export gerçeği: tek havuza paketleme
DCC ve export araçları genelde veriyi ardışık segmentler halinde yazar position bloğu, ardından normal, UV, indeks. Bu düzen 6. bölümdeki şemayla örtüşür. BufferView, loader’a «segment sınırları JSON’da şurada» der; hex editörde tüm şeridi görüp elle segment aramaya gerek kalmaz. Adres bilgisi merkezi bir tabloda toplanır; export aracı değiştikçe aynı spec dili korunur.
Yükleme: bir okuma, çok dilim
GLB açılışında BIN chunk veya harici .bin dosyası tipik olarak bir kez okunur. Sonrasında iş yalnızca JSON indekslerini çözmektir megabyte’lık veriyi her accessor için yeniden diskten çekmek gerekmez. BufferView kayıtları hafiftir (birkaç integer alan); ağır yük binary’de kalır. Bu ayrım JSON vs binary iş bölümünün devamıdır: organizasyon metni hafif, depo ağır; dilim tanımı organizasyon tarafında, octet’ler binary tarafında.
Spec dili: validator ve loader uyumu
Adres ile yorum ayrılınca her araç aynı soruları sorar: «bufferView geçerli mi? ofset + uzunluk buffer sınırını aşıyor mu? accessor’ın beklediği bayt hacmi dilimle uyumlu mu?» Accessor sayfasındaki «nereden + nasıl» özeti burada mühendislik gerekçesine dönüşür iki katman birleşince hata mesajları anlamlı olur («bufferView #2 taşma» vs «accessor tip uyuşmazlığı»). Tek tabloda birleştirilmiş tasarımda hata ayıklama zorlaşır.
Alternatif tasarım neden ölçeklenmez?
Accessor’a doğrudan buffer + byteOffset + byteLength
yazmak kısa vadede cazip görünür. Uzun vadede iki sorun çıkar:
- Tekrarlayan adres alanları: Aynı dilimi kullanan birden fazla accessor aynı ofset/uzunluk üçlüsünü tekrarlar DRY ihlali ve export tutarsızlığı riski.
- Segmentasyon kaybı: «Bu buffer’ın hangi aralıkları mantıksal blok?» sorusunun cevabı accessor listesine dağılır; merkezi dilim haritası kaybolur.
BufferView ara katmanı bu iki sorunu çözer: adres bir kez tanımlanır, accessor yalnızca indeksle referans verir. Kısaca: bufferView, «depo» ile «okuma kuralı» arasına adresleme katmanı koyar. Bu katman olmadan accessor ya tüm buffer’ı okumaya zorlanır ya da her accessor’a tekrarlayan ofset/uzunluk alanları yazılır ikisi de ölçeklenebilir değildir. Liman analojisi bu zinciri farklı metaforla anlatır accessor · liman; 8. bölüm dosya sistemi karşılığını verir.
BufferView Bir Dosya Sistemi Gibidir
§7 mühendislik gerekçesini sayılarla anlattı; bu bölüm aynı zinciri hafızada tutmak için somut bir metafor sunar. Binary buffer sayfasında liman / konteyner analojisi vardır; accessor sayfası onu «etiket, bölüm, konteyner» diye özetler. Dosya sistemi metaforu aynı üçlüyü farklı imgelerle tekrarlar ikisi çelişmez, birbirini tamamlar: liman lojistik, dosya sistemi adresleme vurgusunu öne çıkarır.
Soyut kavramları somutlaştırmak için üçlü analoji:
- Buffer = sabit disk: Ham depolama; içeriğin «ne» olduğunu disk etiketi söylemez yalnızca kapasite ve ham bloklar vardır.
- BufferView = klasör / bölüm: «Bu aralık position alanı», «şu aralık indeks alanı» gibi sınırlar çizer. Klasör dosya içeriğini değiştirmez; yalnızca organizasyon sağlar.
- Accessor = dosya okuma kuralı: «Bu klasördeki baytları float üçlü olarak oku», «ushort skalar listesi say» der çevirmen metaforunun dosya sistemi karşılığı.
Listedeki üç rol: disk, bölüm, okuma kuralı
Madde listesi özetidir; her satır glTF’deki farklı bir soruya karşılık gelir. Liste maddelerini tekrarlamak yerine roller şöyle düşünülebilir:
Disk (buffer) yalnızca «depolama medyası»dır. buffers[i]
kaydı kapasite ve verinin fiziksel kaynağını tarif eder GLB içindeki chunk, harici
.bin veya URI. Diskin üzerinde «position.txt» veya «indices.bin» gibi anlamlı
dosya adları yoktur; yalnızca ardışık sektörler (octet’ler) vardır. Bu,
veri havuzu
metaforunun dosya sistemi karşılığıdır: tek imaj, etiketsiz bloklar.
Klasör / bölüm (bufferView) disk imajı üzerinde «şu LBA aralığı benim
alanım» diyen partition kaydıdır. Export sonrası siz «bu position alanı» diye adlandırsanız
da JSON’da bufferView kaydı yalnızca byteOffset ve byteLength
taşır klasör adı spec’te yoktur. Klasör, diskteki baytları silmez veya taşımaz; yalnızca
sınır çizer. Aynı diskte birden fazla partition olabilir (§6); her biri
farklı mantıksal segment.
Okuma kuralı (accessor) seçilen partition’a «struct parser» uygular: kaç alan, hangi tip, kaç kayıt. Dosya sisteminde bir uygulamanın «bu klasördeki veriyi CSV mi JSON mu okuyacağı» gibi partition içeriği hâlâ ham bayt, anlam accessor tarifinde gelir. Aynı partition farklı parser’larla okunabilir (nadir); farklı partition’lar aynı parser’ı kullanabilir (3072×VEC3 float hem position hem normal diliminde §5 JSON örneği).
Metaforu adım adım okumak
Bir glTF dosyasını «disk imajı + partition tablosu + okuma programı» gibi düşünün:
- Disk (buffer):
buffers[0]kapasite (byteLength), ham bloklar binary chunk’ta. Disk formatı «vertex» veya «UV» bilmez (buffer kördür). - Partition / klasör (bufferView):
bufferViews[i]«disk üzerinde LBA X’ten Y bayt» benzeri; mantıksal bölüm sınırı. İçerik hâlâ ham; klasör adı «position» değildir, yalnızca ofset/uzunluk vardır. - Okuma programı (accessor):
accessors[j]«bu bölümdeki veriyi struct olarak şöyle parse et». Program partition’ı seçer, parse kuralını uygular.
Primitive ve mesh katmanı metaforun üstünde durur: «hangi program hangi amaçla çalıştırılsın?» dosya sisteminde «hangi uygulama hangi dosyayı açsın?» gibi. glTF’de bu «POSITION için accessor #0» cümlesidir; bufferView hâlâ yalnızca partition’dır.
Analojinin sınırları
Metafor öğreticidir, bire bir spec değildir. Analoji mükemmel değildir glTF’de «klasör içinde alt klasör» yoktur, yalnızca düz ofset/uzunluk vardır fakat «buffer tek, dilimler çok» fikrini hafızada tutmak için işe yarar. Aşağıdaki farklar bilinçli olarak not edilir:
- glTF’de «klasör içinde alt klasör» yoktur yalnızca düz
byteOffset/byteLength; hiyerarşi JSON indeksleriyle kurulur, bufferView içinde değil. - Dosya sisteminde silme/yeniden adlandırma vardır; glTF statiktir bufferView kaydı export anında yazılır, runtime’da değişmez.
- «Dosya uzantısı» yoktur; tip accessor
componentTypeile gelir, bufferView’de değil. - Partition tablosu disk başına bir kez okunur; glTF’de birden fazla
buffersgirişi «birden fazla disk» gibi düşünülebilir her biri kendi bufferView dilimlerine sahiptir.
Hex editör perspektifi: disk tek, harita JSON’da
Dosya sistem metaforunun en pratik testi hex editördür. GLB’nin BIN chunk’ını veya .bin dosyasını açtığınızda gördüğünüz şey «disk imajı»dır: sürekli octet akışı, anlamsız tekrarlar, float bit desenleri. Tek başına bakmak «burada position var» demeye yetmez tıpkı dd ile kopyalanmış ham disk görüntüsünde klasör ağacını görmemek gibi.
JSON’daki bufferViews tablosu ise «partition tablosu + ofset defteri»
rolündedir:
hangi disk (buffer indeksi), hangi başlangıç (byteOffset), hangi
uzunluk (byteLength). Hex editörde imleci 36864. bayta taşıdığınızda gördüğünüz
octet’ler, JSON’da «bufferView #1» ile tanımlanan bölüme denk gelir fakat anlam hâlâ
accessor kaydında. Disk imajı + partition tablosu + okuma programı üçlüsü bir arada anlamlı
olur; biri eksikse «random bytes» hissi kalır
(Accessor Lens
demo · yanlış gözlük fikriyle paralel adres doğru, yorum yanlış olunca da benzer
kaos).
Sınırları bilmek analojiyi güvenli kılar: metafor spec detayını taşımaz, «buffer tek, dilimler çok» fikrini taşır. Hex editörde tüm diski görürsünüz; JSON bufferView kayıtları hangi bölümün hangi okuma programına ait olduğunu söyler disk imajına bakmak tek başına yetmez.
JSON organizasyonu ile bağ
JSON yapı
blokları sayfasında «organizasyon katmanı» anlatıldı: nodes,
meshes, materials ilişki haritasıdır «sahne nasıl kurulur?»
sorusuna cevap verir. BufferView bu haritanın binary tarafındaki adres
defteridir
«ham octet’ler diskte nerede?» sorusuna cevap verir. İkisi aynı dosyada yaşar fakat farklı
soru türlerine hizmet eder; karıştırmak «Windows Explorer ile partition tablosunu aynı
şey sanmak» kadar yanıltıcı olabilir.
Zincir aşağı iner; veri en altta kalır:
- Sahne / mesh (organizasyon): «Bu primitive hangi accessor’ları
kullanır?»
attributes,indicesindeksleri. - Accessor (okuma kuralı): «Seçilen dilimi nasıl parse edeyim?»
componentType,type,count. - BufferView (adres): «Parse edeceğim octet’ler diskte nerede?»
buffer,byteOffset,byteLength. - Buffer (depo): «Octet’lerin kendisi» URI/chunk,
byteLength.
Dosya sistemi metaforuyla: Explorer «hangi uygulama hangi dosyayı açsın» der (primitive →
accessor); okuma programı «dosyayı nasıl parse et» der (accessor); partition tablosu «dosya
diskte hangi blokta» der (bufferView); disk imajı ham depodur (buffer). Semantic adlar
(POSITION vb.) Explorer’daki «dosya adı»na benzer kullanıcıya anlamlı,
partition
tablosunda değil (accessor · etiket değildir).
Bu bağ §6 ile birlikte okunmalıdır: tek disk (buffer #0), dört partition (bufferView 0…3), her partition için ayrı okuma programı (accessor). Export aracı «diski bir kez yaz, tabloyu JSON’a koy» mantığıyla çalışır; web loader «diski bir kez oku, tablodan dilim seç» mantığıyla (7. bölüm · yükleme). Üçlü zincirin özeti 10. bölümde tekrarlanır; runtime adım sırası 9. bölümde kısaca verilir GPU upload bu metaforun dışındadır; dilim seçimi bittiğinde accessor typed veri üretmiştir, gerisi motor katmanıdır.
Runtime’da BufferView Ne Olur?
Bu bölüm kısa tutulur GPU upload, VBO/IBO ayrımı veya Three.js attribute bağlama işlenmez. Yalnızca loader’ın mantıksal sırası sabitlenir:
Runtime’da bufferView genelde «alt array view» veya bellek aralığı seçimi olarak düşünülebilir fiziksel kopya şart değildir. Accessor bu aralık üzerinde adım boyutu ve tip hesabı yapar. Sonuç, motorun geometri veya animasyon modülüne gidecek typed dizilerdir; bu sayfanın sınırı burada biter.
Accessor runtime bölümü benzer bir hat çizer; orada vurgu «yorumlama»dadır. Burada vurgu «dilim seçimi»dir ikisi birleşince loader’ın binary tarafı tamamlanır.
Accessor Tek Başına Çalışamaz
Serinin dört dosya yapısı sayfasını birleştiren cümle budur. Accessor mükemmel bir okuma kuralı yazabilir:
FLOAT · VEC3 · count 1000
Fakat soru hâlâ açıktır: «Hangi byte?» BufferView olmadan accessor kördür ne okuyacağını bilir, nereden okuyacağını bilmez. Buffer olmadan bufferView boştur adres vardır, octet yoktur. Üçlü birlikte anlam kazanır:
Accessor olmadan buffer anlamsızdır ters yönde de doğrudur: bufferView olmadan accessor adres bulamaz. İki yönlü bağımlılık tek cümlede sıkıştırılabilir: yorum adres olmadan, adres octet olmadan, octet yorum olmadan tek başına sahne anlamı üretmez. Bu bölüm dosya yapısı serisinin kapanış tablosunu ve sonraki kanalı sabitler; GPU, primitive attribute API’si veya vertex layout detayı işlenmez.
Karşılıklı körlük: eksik halka
Zincirin her halkası bir sonrakine muhtaçtır; biri eksikse loader anlamlı okuma yapamaz:
- BufferView yok, accessor var: «1000 × VEC3 float» kuralı yazılıdır; fakat kuralın uygulanacağı dilim belirsizdir tüm buffer mı, ortadaki segment mi? (accessor · eksik halka).
- Accessor yok, bufferView var: «36864. bayttan 36864 octet» adresi
bellidir; fakat o octet’lerin float mı indeks mi olduğu bilinmez hex dump körlüğü
sürer
(4. bölüm · dördüncü satır). - Buffer yok, bufferView var: Adres defteri vardır, depo yoktur partition tablosu disk imajı olmadan anlamsızdır (3. bölüm · buffer taşır).
- JSON organizasyonu yok: Binary katmanlar okunabilir olsa bile «hangi accessor hangi mesh’te?» sorusu cevapsız kalır organizasyon JSON yapısı sayfasının konusudur; bu sayfa binary zincirini tamamlar.
BufferView bu tabloda ortadaki köprüdür: buffer ile accessor arasında «nereden?» sorusunu çözer. Accessor sayfası «nasıl?»yu anlattı; bu sayfa «hangi dilim?»yi tamamladı birlikte «ham bayt + dilim + yorum» iskeleti oluşur.
Dosya yapısı serisinin büyük tablosu
Dört dosya yapısı sayfası okuma sırasıyla farklı vurgular taşır; birleşince tek tablo ortaya çıkar. Özet madde listesi:
- JSON Structure: Sahneyi organize eder.
- Buffer: Veriyi saklar.
- BufferView: Verinin konumunu gösterir.
- Accessor: Verinin nasıl okunacağını söyler.
Aynı bilgi tablo biçiminde her satır ilgili sayfaya gider:
| Katman | Ana soru | Holodepth sayfası |
|---|---|---|
| JSON Structure | Sahne nasıl organize edilir? · indeksler · ilişki haritası | JSON yapısı |
| Buffer | Ham veri nerede? · etiketsiz octet havuzu | Binary bufferlar |
| BufferView | Havuzun hangi bayt aralığı? · dilim / pencere | bu sayfa |
| Accessor | Baytlar nasıl okunur? · tip · count · biçim | Accessor mantığı |
Binary buffer · JSON/buffer tablosu yalnızca ilk iki satırı içeriyordu; accessor ve bufferView satırları sonraki sayfalarla dolduruldu. Runtime (loader GPU hattı, sahne graph) bu tabloda yoktur bilinçli sınır; motor pipeline ayrı kanaldadır (9. bölüm · kısa özet).
İki sıra: seri okuma vs binary okuma
Tablo karışıklığını önlemek için iki «sıra»yı ayırın:
- Seri okuma sırası (öğretim): JSON → buffer → accessor → bufferView Holodepth dosya yapısı sayfalarının yayın sırası; her sayfa bir katmanı derinleştirir.
- Binary okuma sırası (loader): buffer → bufferView → accessor octet’e fiziksel ulaşım aşağıdan yukarı; organizasyon (JSON, primitive) yukarıdan aşağı accessor indeksini seçer, sonra binary zincir devreye girer.
İkisi çelişmez: önce «sahne haritasını» okursunuz, sonra «seçilen accessor hangi dilimi, hangi kuralı» sorusunu binary tarafta çözersiniz. Bu sayfa serinin son halkası olarak adres dilimini tamamlar; accessor sayfası yorum dilimini, buffer sayfası depoyu, JSON sayfası organizasyonu.
Sonraki adım: geometri verileri kanalı
Dosya yapısı dörtlüsü tamamlandığında elinizde şu iskelet vardır: ham bayt + dilim + yorum. Sonraki adım seride geometri verileri kanalıdır vertex, indeks, normal, UV gibi kavramlar artık bu iskeletin üzerine oturur. Position «nedir?» sorusu artık «hangi semantic + hangi accessor + hangi bufferView + hangi buffer octet’leri» cümlesine bağlanır; fakat vertex attribute sistemi, interleaved layout, GPU attribute slot’ları ve Three.js BufferAttribute API’si bu sayfada işlenmez.
Bu sayfa o iskeletin adres halkasını tamamlar. Primitive attribute bağlama
(«POSITION: accessor #0»), sahne graph detayı ve runtime mesh oluşturma ayrı
sayfalarda kalır bilinçli sınır, çakışmayı önler. Kapatırken hedeflenen cümle:
«Buffer büyük bir bayt havuzudur; bufferView bu havuz içerisindeki belirli bir bölgeyi
tanımlar; accessor o bölgeyi okuma kuralına sokar; JSON ise hangi kuralın hangi mesh’te
kullanıldığını organize eder.»
Demo · BufferView Scanner
Metin «bufferView ne yapar?» sorusunu cevaplar; bu laboratuvar aynı buffer, farklı
dilim hissini yaşatır. Accessor Lens’te octet’ler sabitken yorum
değişiyordu; burada yorum sabit kalır değişen okunan bölgedir. Soldaki
buffer #0 şeridi tek havuzu temsil eder; ortadaki sürüklenebilir pencere bir
bufferView dilimidir; sağ panel byteOffset /
byteLength
ile hangi segmentte olduğunuzu gösterir.
Pencereyi sürükleyin veya BufferView #0…#3 düğmelerine basın: Position, Normal, UV ve Index bölgeleri aynı buffer içinde yan yana durur §6’nın görsel karşılığı. Three.js sahnesi segmente göre güncellenir (köşe vurgusu, normal okları, UV renk, wireframe). JSON Anatomy → Binary Memory → Accessor Lens zincirinin doğal devamı: «Accessor hangi bayt aralığını okuyor?»
Pencereyi sürükleyin veya bufferView seçin · buffer sabit kalır
Buffer #0 · dilim tarayıcısı
byteLength: 720 · tek havuz
Seçili dilim · bufferView kaydı
Segment geri bildirimi
Bu demo ne hissettirir? Buffer verinin tamamıdır; bufferView o verinin hangi kısmına baktığınızı belirler. Pencere Position’dan Index’e kaydıkça aynı havuzun farklı mantıksal bölgelerini okursunuz kopya yok, yalnızca dilim değişir. Dosya yapısı serisi: JSON harita · binary depo · accessor yorum · bufferView adres.