3D Model Formatları · glTF / GLB · Animasyon Sistemi
Channels & Samplers glTF'de Örnekleri Hedefe Bağlama
«Clip var, keyframe var, ama kemik oynamıyor» çoğu zaman bağ katmanında kopar: Keyframe Mantığı zaman–değer tablosunu tanımlar; bu sayfa ikinci soruya geçer: örnekler hangi node'un hangi özelliğine, hangi interpolasyonla gidecek?
glTF animasyonunda iki köprü vardır: sampler «zaman + değer + nasıl ara değer» üçlüsünü taşır; channel «bu sampler'ı şu node'un şu path'ine uygula» der. İkisi birlikte keyframe'i anlamlı harekete çevirir; biri eksikse dosyada veri vardır ama sahne değişmez.
Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz:
«Her channel bir sampler indeksine ve bir target (node + path) işaret eder.
Sampler input/output accessor'ları keyframe'i okur; interpolation
(LINEAR, STEP, CUBICSPLINE) ara değer
politikasını belirler. Oynatma hâlâ runtime işidir; format yalnızca bağ
sözleşmesini yazar.»
Bu sayfanın sınırı · komşu konularla ayrım
Bu sayfa glTF channel / sampler bağ mantığını anlatır:
channels[]·samplers[]indeks ilişkisitarget.node+target.path- Interpolation enum ve semantik farkları
- CUBICSPLINE tangent düzeni (format katmanı)
- Kanal envanteri, paylaşım, Holodepth perspektifleri
Bilinçli olarak dışarıda bırakılan konular:
- Clip / zaman–değer örneği temeli → Keyframe Mantığı
JOINTS/WEIGHTS, inverse bind → Skinning- Morph target geometri / shape key → Morph Targets
- Node hiyerarşisi kurulumu → Node Hiyerarşisi
- TRS / matrix statik transform → Transform Verileri
AnimationMixer, track API, crossfade → AnimationMixer- glTF pipeline clip oynatma → Animation Clips
Kısa ayrım: Keyframe (Format) «tablo nedir?» · Channels & Samplers (Format) «kim, nasıl interpolate?» · AnimationMixer (Runtime) «sahneye nasıl uygulanır?»
Animasyon hattı ikinci soru
| Katman | glTF nesnesi | Soru | Sayfa |
|---|---|---|---|
| 1 · Örnekler | animations[] · zaman/değer |
Hareket hangi örneklerle saklanır? | Keyframe Mantığı |
| 2 · Bağ | channels · samplers | Örnekler nereye ve nasıl uygulanır? | Channels & Samplers (bu sayfa) |
| 3 · Deform | skins · joints | Kemikler geometriyi nasıl eğer? | Skinning |
| 4 · Şekil | morph targets | Yüz / şekil anahtarı nasıl? | Morph Targets |
İki sütun: sampler veri, channel hedef
Zihin modeli: kablo + priz
- Sampler elektrik kablosu: zaman, değer, geçiş tipi taşır.
- Channel priz: «bu kabloyu şu node'un şu yuvasına tak».
- Clip dağıtım kutusu: birden fazla kablo + priz çifti.
- Runtime anahtar: hangi clip'in enerjisi sahneye gidecek.
Bir animasyon clip'i içinde samplers ve channels dizileri
birlikte yaşar. Sampler tek başına «kime gidecek?» bilmez; channel tek başına «hangi
keyframe?» bilmez. Holodepth okuma sırası: önce sampler envanteri (kaç veri
köprüsü var), sonra channel envanteri (kaç hedef bağlandı), sonra eşleşme
(channel.sampler indeksi geçerli mi).
"animations": [{
"name": "Walk",
"samplers": [
{
"input": 12,
"output": 13,
"interpolation": "LINEAR"
},
{
"input": 12,
"output": 14,
"interpolation": "LINEAR"
}
],
"channels": [
{
"sampler": 0,
"target": { "node": 5, "path": "rotation" }
},
{
"sampler": 1,
"target": { "node": 5, "path": "translation" }
}
]
}]
Örnekte iki channel aynı input accessor'ını (indeks 12) paylaşır:
rotation ve translation aynı zaman çizelgesinde ilerler. Output accessor'ları
farklıdır (13 vs 14) çünkü değer tipi ve anlamı farklıdır. Bu paylaşım yaygın ve
geçerlidir.
Keyframe «ne zaman, ne değer?» sorusunu yanıtlar. Channel «hangi node'un hangi alanı?» sorusunu yanıtlar. Sampler «ara değer nasıl?» sorusunu yanıtlar. Üçü birlikte «hareket» olur.
Channel: target sözleşmesi
Her channel nesnesi iki alan taşır: sampler (dizin) ve
target. Target iki alt alandır:
node:nodes[]dizisindeki hedef indekspath: animate edilecek özellik adı (enum string)
| path | Node alanı | Output tipi (özet) |
|---|---|---|
"translation" |
translation |
VEC3 |
"rotation" |
rotation |
VEC4 quaternion |
"scale" |
scale |
VEC3 |
"weights" |
morph ağırlıkları | SCALAR dizisi |
Core'da matrix path'i yoktur. Matrix-only node animate etmek için
export TRS kanallarına açmalıdır; aksi halde channel hedefi bulunamaz. Statik
transform anlamı
Transform Verileri'ndedir; bu sayfa yalnızca «hangi
path animate edilebilir» listesini sabitler.
Node indeksi geçerliliği
target.node sahnedeki gerçek bir node'a işaret etmelidir. Export'ta
silinen kemik, birleştirilen rig veya yanlış indeks remap «animasyon var ama
görünmüyor» üretir. Holodepth envanter sorusu: channel sayısı kadar
nodes[target.node] var mı? Node adı eşleşmesi JSON'da zorunlu değildir;
yalnızca indeks sözleşmesi geçerlidir.
Node Hiyerarşisi ile birlikte okuyun: animate edilen
node ile mesh'in skin joint listesi farklı kavramlardır (Skinning
sayfası).
weights path önizlemesi
weights path'i morph target ağırlıklarını animate eder; geometri
tanımı morph sayfasındadır. Burada yalnızca not: weights channel'ı olan clip,
keyframe output'unun uzunluğu hedefteki morph sayısıyla uyumlu olmalıdır. Uyumsuzluk
sessiz kırılma veya kısmi uygulama üretebilir.
Sampler: input, output, interpolation
Sampler üç alanla keyframe okuma politikasını tanımlar:
input: zaman accessor indeksi (SCALAR, saniye)output: değer accessor indeksi (path'e göre tip)interpolation: ara değer modu
Zaman ve değer accessor semantiği Keyframe · input/output bölümündedir. Bu sayfa «okuduktan sonra nasıl birleştirilecek» sorusuna odaklanır.
Interpolation enum
| Değer | Davranış (özet) | Tipik kullanım |
|---|---|---|
LINEAR |
İki key arası doğrusal / slerp (rotation) | Genel TRS, çoğu export |
STEP |
Son key değeri bir sonrakine kadar sabit | Discrete switch, poz değişimi |
CUBICSPLINE |
Hermite spline; tangent verisi gerekir | Az key ile yumuşak eğri |
Interpolation path başına sampler'da tanımlıdır. Aynı node'un rotation'ı LINEAR, translation'ı STEP olabilir (nadir ama geçerli). Runtime her track için ayrı politika uygular; mixer bunu clip yüklerken track metadata'sından alır.
LINEAR ve STEP: iki farklı zaman hissi
LINEAR çoğu karakter hareketinin varsayılanıdır. Translation ve scale için bileşen bazlı linear interpolation; rotation için quaternion slerp beklenir (spec uyumu loader'a bağlıdır, ama hedef bu yöndedir). Seyrek key + LINEAR = köşeli hareket; dense bake + LINEAR = pürüzsüz hareket.
STEP «t anına kadar önceki değeri tut» modudur. Morph weights anahtarlaması, kapı aç/kapa pozları, UI state geçişleri için uygundur. STEP ile LINEAR'ı aynı clip'te karıştırmak bilinçli tasarımdır: gövde LINEAR yürürken yüz ifadesi STEP ile poz değiştirir.
LINEAR ≠ easing API
DCC'deki «ease in/out» eğrisi glTF'de çoğu zaman ya CUBICSPLINE tangent ya da
dense LINEAR bake olarak görünür. Three.js'teki easing fonksiyonları
Lerp & Easing runtime katmanıdır; dosyada
easeInOutCubic alanı yoktur. Format LINEAR der; ürün kodu bunun üstüne
ek politika koyabilir, ama bu dosya sözleşmesini değiştirmez.
STEP ve «hold» frame
STEP'te son keyframe değeri, bir sonraki keyframe zamanına kadar geçerlidir. Loop sınırında ilk/son key uyumsuzsa «bir karelik sıçrama» görülür; bu keyframe kenar sürekliliği sorunudur ( Keyframe · döngü sınırı), interpolation hatası değil.
CUBICSPLINE: tangent üçlüsü ve output şişmesi
CUBICSPLINE seçildiğinde output accessor düzeni değişir. Her keyframe
için output'ta üç ardışık değer beklenir:
- in-tangent (giriş eğimi)
- value (asıl key değeri)
- out-tangent (çıkış eğimi)
Yani «3 keyframe» sandığınız output aslında 9 öğe (VEC3 için 27 float) olabilir.
Holodepth: accessor count görünce önce interpolation'a bakın; aksi halde
«fazla key var» yanlış teşhisi üretirsiniz.
// CUBICSPLINE, N key için output öğe sayısı = 3 × N
// translation (VEC3): her öğe 3 float → toplam 9N float
output[3*i + 0] = in_tangent_i
output[3*i + 1] = value_i
output[3*i + 2] = out_tangent_i
Tangent uzayı value ile aynı boyuttadır (VEC3 için VEC3 tangent). Rotation CUBICSPLINE'da quaternion tangent taşır; debug zordur. Export araçları bazen CUBICSPLINE'ı otomatik üretir, bazen LINEAR'a düşer; pipeline envanterinde path başına interpolation dağılımını saymak faydalıdır.
CUBICSPLINE vs dense LINEAR
| Yöntem | Dosya | Debug | Risk |
|---|---|---|---|
| Dense LINEAR | Büyük | Kolay | Gereksiz byte |
| CUBICSPLINE | Küçük (seyrek key) | Zor | Tangent / count hatası |
| STEP | Küçük | Orta | Yanlış path'te köşe |
İndeks bağlama: channel ↔ sampler
channel.sampler bir tam sayı indeksidir; samplers dizisindeki
elemana işaret eder. Geçersiz indeks (negatif, samplers.length dışı)
bozuk dosyadır. Bir sampler birden fazla channel tarafından referans alınabilir mi?
Core şemada yasak değildir; pratikte nadirdir ve yan etki riski yüksektir (aynı
output'un iki farklı node'a yazılması).
Yaygın desen: her (node, path) çifti için ayrı sampler, çoğu zaman aynı input'u paylaşır. Alternatif: translation/rotation/scale için üç ayrı sampler, üç ayrı channel; hepsi input 12'yi gösterir. Bu, TRS kanallarının zaman kaymasını önler.
Yetim sampler / channel
- Channel yok, sampler var: veri taşınır ama uygulanmaz (ölü veri)
- Channel var, sampler geçersiz: bozuk dosya
- Channel var, target.node geçersiz: sessiz no-op veya loader hatası
Validator her yetim sampler için uyarmayabilir. Holodepth envanter: kullanılan sampler
indekslerinin kümesi ile samplers.length karşılaştırması. Fazla sampler
= optimizasyon fırsatı veya export artığı.
TRS kanal paketi: eksik path bilinçli olabilir
Bir kemik için üç ayrı channel beklemek yaygın bir varsayımdır; zorunluluk değildir. Yalnızca rotation animate edilip translation sabit bırakılabilir ( Keyframe · kısmi kanal). Holodepth: «eksik kanal = bozuk» demeden önce sanat niyetini sorun.
Root motion export'larında pelvis translation + bacak rotation ayrımı tipiktir. Scale kanalı çoğu karakterde hiç yoktur; varsa aynalanma veya squash animasyonu içindir. Scale + rotation birlikte animate edildiğinde pivot kayması hissedilebilir; bu transform sırası ( Transform) ile birleşen semptomdur.
Aynı node, çoklu path
Aynı target.node için translation, rotation ve scale ayrı channel'lardır.
Her birinin kendi sampler'ı vardır; interpolation path başına farklı olabilir. Runtime
aynı karede üç alanı günceller; sıra motor içindedir (genelde TRS birleştirme
matrix'e gider). Format sıra taşımaz.
Loader köprüsü: track adı ve format sınırı
GLTFLoader channel + sampler çiftini motor track'ine çevirir: hedef node adı veya UUID, path string, keyframe dizileri, interpolation. Bu çeviri formatı değiştirmez; okunabilir API üretir. Track adlandırma loader sürümüne bağlı olabilir; ürün kodu track'i isimle değil node+path ile bulmak daha kararlıdır.
Derin oynatma, crossfade, weight Animation Clips ve AnimationMixer sayfalarındadır. Bu sayfa yalnızca «dosyada hangi bağ var» sorusunu kapatır: channel envanteri yeşil değilse mixer ayarlamak zaman kaybıdır.
| glTF | Anlam | Runtime (Three.js özet) |
|---|---|---|
| animation clip | channels + samplers paketi | AnimationClip |
| channel.target | node + path | track hedefi |
| sampler interpolation | ara değer modu | track interpolation |
| input / output | keyframe verisi | times / values dizileri |
Holodepth perspektifleri çoğu dokümanda olmayan açılar
Resmi spec tabloları doğrudur; üretimde aşağıdaki ayrımlar sık görülür, az yazılır.
Doğru keyframe, yanlış node
Clip dolu, sampler LINEAR, ama target.node mesh node'una işaret ediyor;
skinned karakterde hareket görünmez. Kemik animasyonu joint node'larına bağlanmalıdır.
Teşhis: channel envanterinde hedef node'un skin / joint ilişkisi (Skinning
ile birlikte).
Rotation flip: interpolation + quat
LINEAR quaternion interpolation kısa yol (slerp) bekler; uzun yol seçilirse veya normalize edilmemiş quat varsa 180° civarı «flip» görülür. Semptom channel/sampler katmanında başlar; çözüm çoğu zaman export quat düzeni veya CUBICSPLINE tangent tutarlılığıdır, shader değil.
Çift channel çakışması
Aynı (node, path) için iki channel aynı clip'te tanımlıysa son yazılan veya loader sırası kazanır; davranış belirsizleşir. Merge / re-export araçları bazen duplicate üretir. Envanter: (node, path) çiftlerini kümeleyin; tekrar varsa temizleyin.
Interpolation varsayılanı tuzağı
Eksik interpolation alanı spec'te LINEAR kabul edilir (uygulama
uyumuna güvenin). Export bazen STEP yazar, viewer LINEAR sanar. Dosyada enum'u açık
yazmak Holodepth standardıdır; «varsayılan»a güvenmeyin.
weights output uzunluğu
Morph sayısı 8 iken weights output 5 öğe taşıyorsa kısmi yüz ifadesi veya sessiz
truncation olur. Channel path weights ise output accessor
count ile hedef morph dizisi uzunluğunu karşılaştırın (Morph Targets
sayfası geometriyi, bu sayfa bağ uzunluğunu sorar).
Altı soruluk bağ teşhisi
| Soru | Yeşil ise | Kırmızı ise bak |
|---|---|---|
channel.sampler geçerli mi? |
Bağ var | Bozuk indeks |
target.node var mı? |
Hedef sahne içi | Silinmiş kemik / remap |
path core enum mu? |
Animate edilebilir alan | Matrix-only / typo |
| Interpolation beklenen mi? | Doğru geçiş hissi | STEP/LINEAR karışıklığı |
| CUBICSPLINE output 3×N mi? | Tangent hizalı | Count / bake hatası |
| (node, path) tekrarı yok mu? | Tek sahiplik | Duplicate channel |
Holodepth içgörüsü
«Keyframe doğru, sahne hareketsiz» vakalarının çoğu channel envanterinde çözülür: hedef node doğru mu, path TRS/weights mi, sampler indeksi geçerli mi, aynı (node, path) iki kez yazılmış mı? Mixer'a geçmeden önce bu dört satırı yeşile boyayın.
Bağ katmanından sonra
Örnekler hedefe bağlandıktan sonra sıradaki soru deformdur: kemik rotation channel'ı vardır ama mesh nasıl eğilir?
- Skinning joints, inverseBindMatrices, vertex weights
- Morph Targets shape keys, weights channel detayı
- Runtime AnimationMixer
Format okuyucusu özeti: sampler = veri + interpolasyon; channel = hedef; clip = paket. Keyframe tabloyu yazar, channel prizi takar, skinning ve morph görünür hareketi tamamlar.