3D Model Formatları · glTF / GLB · Animasyon Sistemi
Keyframe Mantığı glTF'de Zaman Örnekli Hareket
«Animasyon var ama dosyada AnimationMixer yok» diye şaşırıyorsanız doğru yerdesiniz: glTF hareketi çalmaz, örnekler. Materyal Sistemi yüzey kartını kapattı; Animasyon Sistemi'nin ilk sorusu şudur: zaman ekseninde hangi değerler saklanır?
Holodepth Animasyon hattında dört katman vardır: keyframe (bu sayfa) zaman–değer örneklerini tanımlar; channels & samplers hangi node/özelliğe gideceğini bağlar; skinning kemik ağırlıklarıyla geometriyi deform eder; morph targets şekil anahtarlarını taşır. Bu sayfa yalnızca birinci katmanı sabitler: dosyada «klip» ve «kare» ne demektir.
Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz:
«glTF animations[] bir veya daha fazla clip taşır. Her clip,
sampler'lar üzerinden zaman (input) ve değer (output) accessor'larına bağlı
keyframe dizileridir. Oynatma, interpolasyon ve mixer runtime işidir; format
yalnızca örnekleri ve hedefleri taşır.»
Bu sayfanın sınırı · komşu konularla ayrım
Bu sayfa glTF keyframe / clip mantığını anlatır:
- Keyframe = zaman + değer örneği
animations[]clip konteyneri- Zaman alanı (saniye), örnek seyrekliği
- Değer tipleri (TRS, ağırlık) özeti
- Format vs oynatma ayrımı; Holodepth perspektifleri
Bilinçli olarak dışarıda bırakılan konular:
- Channel path, sampler interpolation enum detayı → Channels & Samplers
JOINTS/WEIGHTS, inverse bind → Skinning- Morph target ağırlıkları derinliği → Morph Targets
requestAnimationFrame, delta, FPS → Animasyon Döngüsü ve ZamanAnimationMixer, lerp, easing API → Lerp & Easing- Accessor / BufferView okuma → Accessor Mantığı
Kısa ayrım: Keyframe Mantığı (Format) «zaman–değer tablosu nedir?» · Channels & Samplers «kim, nasıl interpolate?» · AnimationMixer (Runtime) «sahneye nasıl uygulanır?»
Animasyon hattı birinci soru
| Katman | glTF nesnesi | Soru | Sayfa |
|---|---|---|---|
| 1 · Örnekler | animations[] · zaman/değer |
Hareket hangi örneklerle saklanır? | Keyframe Mantığı (bu sayfa) |
| 2 · Bağ | channels · samplers | Örnekler nereye ve nasıl uygulanır? | Channels & Samplers |
| 3 · Deform | skins · joints | Kemikler geometriyi nasıl eğer? | Skinning |
| 4 · Şekil | morph targets | Yüz / şekil anahtarı nasıl? | Morph Targets |
Keyframe nedir? (Format dilinde)
Zihin modeli: metronom + ölçü notası
- Zaman (input) metronom vuruşu: kaçıncı saniye?
- Değer (output) o anda çalınacak nota: konum, dönüş, ölçek…
- Keyframe çifti bir vuruşta hangi notanın basılacağı.
- Çalgıcı (runtime) vuruşlar arasında nasıl geçileceğini bilir; partisyon (dosya) yalnızca notaları yazar.
Animasyon yazılımında «keyframe» çoğu zaman timeline UI karesidir: kırmızı nokta, Bezier kolu, easing eğrisi. glTF'de karşılığı daha kurudur: monoton artan zaman dizisi ile hizalı değer dizisi. İkisi de binary buffer'da accessor üzerinden okunur; JSON yalnızca indeksleri ve semantiği taşır. UI'daki Bezier kolu dosyaya çoğu zaman ya bake edilmiş ara örnekler ya da CUBICSPLINE tangent verisi olarak düşer; «edit edilebilir eğri» olarak kalmaz.
Bu ayrım bilerek serttir. Interchange formatı taşıma sözleşmesidir: her motor aynı UI'yi yeniden çizmez; aynı örneklenmiş hareketi yeniden üretir. Holodepth bu yüzden keyframe'i «sanat aracı» değil «taşıma birimi» olarak okur.
Keyframe Mantığı şunların hiçbiri değildir:
- FPS / ekran karesi değil render döngüsü ayrı sayfada
- Easing fonksiyonu API'si değil interpolasyon sampler'da, uygulama runtime'da
- Skeleton rig UI değil skinning sonraki sayfa
- Physics / ragdoll değil format dışı
- State machine / blend tree değil ürün kodu katmanı
Örnek, formül değil
Birçok motor iç dünyasında «t anında f(t)» formülü vardır (sinüs sallanma, spring, procedural walk). glTF core bu formülleri taşımaz. Export anında formül bir kez değerlendirilir; sonuç zaman–değer tablosu olur. Web'de aynı salınımı parametrik tutmak istiyorsanız ya runtime'da yeniden üretirsiniz ya da bake edilmiş tabloyu oynatırsınız. İkisi farklı ürün kararıdır; dosya yalnızca ikincisini bilir.
Geometri «nerede duruyor?» sorusunu yanıtlar. Keyframe «zaman içinde nerede olacak?» sorusunun örneklenmiş cevabını taşır. Aradaki yumuşak geçiş dosyada formül değil, çoğu zaman sampler interpolasyon tipidir.
animations[]: clip
konteyneri
Kök JSON'daki animations dizisinin her elemanı bir animasyon
klibidir: isteğe bağlı name, samplers listesi,
channels listesi. Bir dosyada birden fazla clip olabilir («Idle»,
«Walk», «Attack»). Clip'ler birbirinden bağımsızdır; hangisinin çalacağı runtime
seçimidir. Format «şu anda Idle çal» demez; yalnızca «Idle diye bir clip var»
der.
"animations": [
{
"name": "Walk",
"samplers": [ /* zaman ↔ değer köprüleri: sonraki sayfa */ ],
"channels": [ /* hedef node + path: sonraki sayfa */ ]
},
{
"name": "Idle",
"samplers": [ … ],
"channels": [ … ]
}
]
Holodepth envanterinde üç sayı bilinçli ayrılır:
- Animasyon var mı?
animations.length > 0 - Kaç hareket çeşidi? clip sayısı (dizinin uzunluğu)
- Kaç kanal? her clip içindeki
channels.length(aynı Walk klibinde onlarca kemik kanalı olabilir)
«Dosyada 1 animasyon var» demek «tek kanal» demek değildir. Tersine «80 kanal» demek «80 clip» demek değildir. Raporlarda bu üç sayıyı ayrı yazın; aksi halde sanatçı / mühendis konuşması birbirini kaçırır.
Animasyonsuz dosya geçerlidir
animations yokluğu hata değildir: statik mesh core glTF'dir. Animasyon
«zorunlu katman» değil, isteğe bağlı zenginleştirmedir; tıpkı materyal uzantıları
gibi, ama burada sözleşme core'dadır (ayrı KHR adı gerekmez). Bu yüzden
«animasyonsuz GLB geçersiz» varsayımı yanlıştır; ürününüz yalnızca hareketli
asset kabul ediyorsa bu ürün kuralıdır, format kuralı değil.
Clip = ürün SKU'su
Holodepth üretim dilinde her clip bir SKU gibidir: isim, süre, hedef kemik seti, dosya içi bayt maliyeti. Katalogda «Walk_Loop_01» ile «Walk» iki farklı SKU'dur; indekse güvenmek stok kaydını karıştırır. Material Slots'taki materyal indeksi tuzağının animasyon yüzü budur: export sırası değişince «üçüncü clip» artık Attack değil Idle olabilir.
Zaman alanı: saniye ve monotonluk
Sampler input accessor'ı tipik olarak SCALAR float
zamanlardır; birim saniyedir (frame numarası değil). Değerler genelde
0'dan başlar ve sıkı artan (strictly increasing) olmalıdır.
Aynı zaman damgasının tekrarı veya geriye gidiş belirsiz interpolasyon üretir;
loader davranışı tanımsız kalabilir.
- Süre ≈ son input − ilk input (clip uzunluğu)
- Yoğun örnekleme yüksek frekanslı hareket, büyük binary
- Seyrek örnekleme küçük dosya; ara değerler interpolasyona kalır
Export «her frame 60 FPS bake» yaptığında input dizisi şişer. Sanatçı timeline'ında seyrek key, export'ta dense bake görmek yaygındır. Holodepth: dosya boyutu analizinde animasyon accessor byteLength'ini ayrı kalem olarak sayın. Çoğu «ağır GLB» aslında yoğun keyframe'dir, texture değil.
t = 0 sözleşmesi
Birçok clip 0.0'da başlar; zorunluluk değil, pratiktir. Bazı export'lar
sahne zaman çizelgesinden absülüt saniye bırakır (ör. 12.4 … 14.1). Runtime çoğu
zaman clip'i kendi başına «yeniden sıfırlar»; bazen de absülüt aralığı korur.
Holodepth teşhisi: input'un min/max'ına bakın. Beklenmeyen offset «geç başlıyor /
hiç oynamıyor» semptomunu üretebilir.
FPS ile karıştırmayın
Ekranın 60 Hz yenilenmesi ile keyframe örnek hızı aynı şey değildir. Runtime 60 FPS çizerken 10 Hz keyframe'leri interpolate edebilir. Format zamanı süreklidir; kare bütçesi Animasyon Döngüsü konusudur. «Animasyon 30 FPS export ettim, sahnem 60 FPS» cümlesi iki farklı saati aynı cümlede birleştirir; format saati saniyedir.
Döngü sınırı dosyada yok
Seamless loop için ilk ve son keyframe değerlerinin birbirine yakın olması sanat sözleşmesidir; glTF «bu clip loop'lanabilir» bayrağı taşımaz. Son kare ile ilk kare arasında ani sıçrama varsa, loop açıkken «tık» görünür. Bu, mixer loop hatası değil, örnek tablosunun kenar süreksizliğidir.
Değer alanı: ne animate edilir?
Output accessor tipi, hedefin path'ine göre değişir. Bu sayfada yalnızca değer ailesi özetlenir; path/channel eşlemesi sonraki sayfadadır. Amaç: keyframe okurken «bu float dizisi neyi temsil ediyor?» sorusunu cevaplamak.
| Hedef (özet) | Accessor tipi | Anlam |
|---|---|---|
| translation | VEC3 |
Konum (x,y,z) |
| rotation | VEC4 |
Quaternion (x,y,z,w) |
| scale | VEC3 |
Ölçek |
| weights | SCALAR dizisi |
Morph ağırlıkları (Morph sayfası) |
Quaternion keyframe'lerde «Euler timeline» beklemeyin: glTF dönüşü quat olarak
saklar. DCC Euler gösterir; export quat'a çevirir. Yanlış w işareti veya
normalize edilmemiş quat «flip» semptomu üretir; çoğu zaman sampler interpolasyon
tipi (LINEAR vs CUBICSPLINE) ile birleşir. Detay Channels
sayfasındadır.
Core'da animate edilmeyenler
Materyal factor'ları, ışık şiddeti, kamera FOV, texture offset gibi alanlar core animasyon path'i değildir. Bunlar ya uzantı + özel pipeline ile gelir ya da runtime'da ayrı animate edilir. «Albedo animasyonu GLB'de neden yok?» sorusunun cevabı çoğu zaman «core path yok»tur, loader bug'ı değil.
TRS vs matrix
Node transform Transform Verileri'nde ya TRS ya matrix'tir. Animasyon genelde TRS kanallarını hedefler. Matrix-only node'u animate etmek pipeline'da TRS'e açmayı gerektirir; format tarafında «matrix animate eden core path» yoktur. Export'ta matrix node + animasyon kombinasyonu sessizce TRS'e çevrilmiş olabilir; bu dönüşüm kaybı (shear vb.) ayrı bir pipeline riskidir.
Input / output çifti (kavram)
Her sampler bir input ve bir output accessor indeksine
işaret eder. Keyframe mantığının kalbi şudur:
input[i] = t_i // saniye
output[i] = value_i // VEC3 / VEC4 / …
// i = 0 … count-1
// t_i sıkı artar; value_i aynı sırada hizalıdır
count uyuşmazlığı (zaman 10 örnek, değer 9) bozuk dosyadır. Bu
tutarlılık
Accessor katmanında doğrulanır; animasyon sayfası
«neden iki accessor?» sorusunu sorar: çünkü zaman ile değer farklı tip ve
anlam taşır, tek interleaved «keyframe struct» core'da yoktur.
CUBICSPLINE interpolasyonda output düzeni üçlü (in-tangent, value, out-tangent) olabilir; bu, «basit keyframe» sayısını şişirir. Holodepth: dense binary görüp «çok key var» demeden önce interpolasyon tipine bakın. Bu, Channels & Samplers sayfasının konusudur.
Paylaşılan zaman ekseni
Aynı clip içinde birçok sampler aynı input accessor'ını paylaşabilir:
tüm TRS kanalları ortak zaman çizelgesine oturur. Bu hem bayt kazandırır hem de
kanallar arasında zaman kaymasını önler. Tersine, her kanalın kendi zaman
dizisi varsa «aynı clip, farklı ritim» mümkün olur; teşhiste input indekslerinin
özdeş olup olmadığına bakın.
min / max ipucu
Accessor min / max alanları animasyonda pratik teşhis
aracıdır: input max ≈ clip süresi; translation max sahne ölçeğini ifşa eder.
Eksik min/max zorunlu değildir ama Holodepth envanterinde «süre ve genlik»
özetini hızlandırır.
Format saklar, runtime çalar
glTF dosyasında loop, ping-pong, blend weight, crossfade yoktur (core). Bunlar player / mixer politikasıdır. Dosya «Walk klibi 1.2 sn, şu keyframe'ler» der; uygulamanız tekrar mı oynatacak, başka klibe mi blend edecek bilmez. Bu boşluk bilinçlidir: aynı asset viewer'da bir kez, oyunda loop, editörde scrub edilebilir.
| Katman | Sorumluluk |
|---|---|
| glTF animations | Örnekler, hedefler, interpolasyon tipi |
| Loader | Clip / track nesnelerine çevirme |
| AnimationMixer | Zaman ilerletme, ağırlık, geçiş |
| Render loop | delta ile update |
Bu yüzden «GLB'de animasyon bozuk» teşhisinde önce accessor/channel tutarlılığına, sonra mixer kurulumuna bakın. İkinci adım AnimationMixer sayfasındadır. Holodepth kuralı: dosya sözleşmesi yeşil değilse mixer'a dokunmayın; mixer yeşil değilse render loop'a dokunmayın.
Loader çevirisi (sınır)
GLTFLoader clip'leri motor nesnelerine map eder: isimler, süre, track listesi. Bu çeviri «formatı değiştirmez»; yalnızca okunabilir hale getirir. Loader'ın ürettiği clip süresi ile input max uyuşmuyorsa, sorun çoğu zaman CUBICSPLINE düzeni veya eksik kanal değil, zaman birimi / trim politikasıdır. Derin track API'si Three.js dalındadır; burada yalnızca «çeviri katmanı vardır» notu yeter.
Çoklu clip ve isimlendirme
Karakter paketlerinde onlarca clip yaygındır. name alanı isteğe bağlıdır
ama runtime seçimi için kritik pratiktir: isimsiz clip'ler indeksle seçilir; export
sırası değişince kırılır. Holodepth: clip adını DCC'de bilinçli yazın; indekse
güvenmeyin (Material Slots'taki indeks kaydırma tuzağının animasyon yüzü).
- Aynı node, farklı clip: Walk ve Idle aynı kemikleri hedefler; aynı anda çalmak mixer politikasıdır
- Farklı süreler: her clip kendi zaman 0…T aralığına sahiptir
- Paylaşılan accessor: nadiren iki sampler aynı output'u paylaşır; dikkatli olun, yan etki yaratır
Paketleme stratejileri
Üretimde üç yaygın paket görülür: (1) tek GLB, tüm clip'ler içinde; (2) mesh + skin bir GLB, clip'ler ayrı GLB/glTF; (3) clip başına dosya. Format üçünü de destekler; ürün CDN bütçesi ve önbellek politikası seçer. Holodepth: «ilk boyamada Idle yeter, Attack sonra» ise clip ayırma anlamlıdır; her şey tek istekte lazımsa birleşik paket daha ucuzdur. Bu karar keyframe mantığını değiştirmez, dağıtım katmanını değiştirir.
Export: bake, constraint, kayıp
DCC constraint'leri, IK zincirleri, procedural motion glTF'e çoğu zaman bake edilmiş keyframe olarak düşer. Dosyada «IK handle» yoktur; yalnızca sonuç TRS örnekleri vardır. Bu yüzden:
- Yeniden düzenlenebilir rig web'de yoktur (core)
- Bake aralığı / örnek hızı dosya boyutunu belirler
- Constraint bozulması export'ta «keyframe gürültüsü» olarak görünür
| Seçim | Kazanç | Bedel |
|---|---|---|
| Seyrek key + LINEAR | Küçük dosya | Keskin dönüşlerde köşe |
| Dense bake (ör. 60 Hz) | Yüksek sadakat | Büyük binary, bellek |
| CUBICSPLINE | Az örnekle yumuşaklık | 3× output, karmaşık debug |
FBX karakter pipeline'sı ile karşılaştırma FBX dalındadır; burada yalnızca glTF'nin «sonuç odaklı örnekleme» doğası sabitlenir. Bake sonrası DCC'de düzeltilen motion, web'de yeniden constraint ile «düzeltilmez»; yeniden export gerekir.
Holodepth perspektifleri çoğu dokümanda olmayan açılar
Standart anlatım «animations samplers channels» listesiyle biter. Aşağıdakiler üretimde sık, az yerde derin işlenir.
«Mesh animate olmuyor»
Node translation animate olur; skinned mesh köşeleri skinning ile hareket eder. Morph yoksa, skin yoksa, yalnızca root node kayıyorsa «karakter yürümüyor» sanılır. Keyframe vardır; deform katmanı yoktur. Teşhis: clip var mı, channel hedefi hangi node, skin var mı?
Zaman birimi tuzağı
Bazı araçlar milisaniye veya frame index export eder; glTF saniye bekler. 60× hızlı veya yavaş clip semptomu çoğu zaman birim hatasıdır, mixer değil. Input max'ı 1.2 iken «1.2 dakika» sanmak da ters yönde aynı tuzağıdır.
Negatif scale ve animasyon
Aynalanmış asset'lerde scale.x = −1 sabitse rotation keyframe'leri «ters» hissedilir. Format geçerli olabilir; sanat/pipeline karışımıdır. Transform sayfasıyla birlikte okuyun.
Yetim clip
Hiçbir channel'ı olmayan veya tüm hedefleri sahnede olmayan clip, dosyada yer kaplar ama görünmez. Validator her zaman uyarmayabilir; envanterde channel.target.node geçerliliğini sayın (Channels sayfası).
Bellek = örnek × kanal × bileşen
100 kemik × 3 TRS kanal × 300 key × float ≈ hızlıca megabyte'lar. Draco geometriyi küçültür; animasyon keyframe'lerini sıkıştırmaz (ayrı uzantılar / pipeline gerekir). «GLB hâlâ büyük» teşhisinde animations binary payını ayrı ölçün.
İsim kararlılığı
Runtime clips.find(c => c.name === "Walk") pattern'i format
name alanına bağlıdır. Export «Walk.001» üretirsa kod kırılır. Keyframe
içeriği doğru olsa da isim sözleşmesi ürün kodunun parçasıdır.
Rest pose ile clip çatışması
Node'un statik TRS'i (rest) ile clip'in ilk keyframe'i farklıysa, oynatma başlamadan önce «bir kare sıçrama» görülür. Bazı loader'lar ilk frame'i uygular; bazıları mixer start'ına kadar rest bırakır. Holodepth: export'ta rest = idle t0 hizası hedefleyin; aksi halde runtime'da bir karelik «snap» politikası yazmanız gerekir.
Kısmi kanal seti
Bir clip yalnızca rotation kanalları taşıyıp translation'ı sabitte bırakabilir. Bu geçerli ve istenen bir seyreltmedir. «Eksik kanal = bozuk dosya» varsayımı yanlıştır; eksiklik bilinçli olabilir. Teşhis: hangi path'lerin gerçekten animate edildiğini channel envanterinden okuyun.
Beş soruluk dosya teşhisi
| Soru | Yeşil ise | Kırmızı ise bak |
|---|---|---|
animations.length > 0? |
Clip var | Export / yanlış dosya |
| Input monoton artıyor mu? | Zaman geçerli | Bake / birim hatası |
| Input/output count uyumlu mu? | Hiza tamam | Accessor bozulması |
| Zaman birimi saniye mi? | Süre makul | ms / frame index |
| Hedef node TRS mi? | Animate edilebilir | Matrix-only / yanlış node |
Holodepth içgörüsü
Animasyon debug'unda önce mixer'a değil örnek sözleşmesine bakın: clip var mı, input monoton mu, input/output count uyumlu mu, zaman birimi saniye mi, hedef node TRS mi? Bu beş soru «oynamıyor / uçuyor / çok hızlı» vakalarının çoğunu dosya aşamasında sınıflandırır.
Keyframe'den sonra
Örneklerin ne olduğu netleşince sıradaki soru bağdır:
- Channels & Samplers path, interpolation, target.node
- Skinning joints, inverseBindMatrices, vertex weights
- Morph Targets shape keys / weights kanalları
- Runtime AnimationMixer
Format okuyucusu özeti: animations = clip'ler; keyframe = zaman–değer hizası; çalma = runtime. Partisyon notaları yazar, orkestra sonra gelir.