3D Model Formatları · glTF / GLB · Animasyon Sistemi
Skinning glTF'de Kemik–Köşe Deform Sözleşmesi
«Clip oynuyor, kemikler dönüyor, mesh donuk kalıyor» çoğu zaman channel eksikliği değil, skin katmanının yokluğu veya kopukluğudur. Channels & Samplers node TRS'ini günceller; bu sayfa üçüncü soruya geçer: köşe noktaları kemik hareketini dosyada nasıl bilir?
Holodepth Animasyon hattında skinning, format tarafında üç parçanın birleşimidir:
skins[] (joint listesi + inverse bind), primitive üzerindeki
JOINTS_* / WEIGHTS_* öznitelikleri, ve mesh/node'un
skin indeksi. Runtime
SkinnedMesh / Skeleton bu sözleşmeyi sahneye çevirir;
bu sayfa dosyadaki sözleşmeyi sabitler.
Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «glTF skin bir joint node dizisi ve her joint için bir inverseBindMatrix taşır. Köşeler JOINTS/WEIGHTS ile bu dizideki slotlara bağlanır. Animasyon joint node TRS'ini hareket ettirir; deform formülü bind pozu ile canlı pose arasındadır. Skin olmadan channel yalnızca boş hiyerarşi döner.»
Bu sayfanın sınırı · komşu konularla ayrım
Bu sayfa glTF skinning dosya sözleşmesini anlatır:
skins[]: joints, inverseBindMatrices, skeletonJOINTS_0/WEIGHTS_0(ve _1) semantiğimesh/ node ↔ skin indeksi- Bind pose, joint indeksi vs node indeksi ayrımı
- 4-bone limit, Holodepth teşhis açıları
Bilinçli olarak dışarıda bırakılan konular:
- Keyframe / clip tablosu → Keyframe Mantığı
- Channel path / interpolation → Channels & Samplers
- Morph shape keys → Morph Targets
- Vertex attribute genel sözlüğü → Vertex Verileri
- Node hiyerarşisi → Node Hiyerarşisi
SkinnedMesh,Skeleton, GPU lab, JS API → Skinning System (Three.js)- Vertex shader skinning matematiği derinliği → Shader & WebGL dalları
Kısa ayrım: Skinning (Format) «dosyada kemik–köşe bağı nedir?» · Skinning System (Runtime) «SkinnedMesh nasıl deforme eder?» · Channels «joint node nasıl animate edilir?»
Animasyon hattı üçüncü soru
| Katman | glTF nesnesi | Soru | Sayfa |
|---|---|---|---|
| 1 · Örnekler | animations[] |
Hareket hangi örneklerle saklanır? | Keyframe Mantığı |
| 2 · Bağ | channels · samplers | Örnekler nereye / nasıl uygulanır? | Channels & Samplers |
| 3 · Deform | skins · JOINTS/WEIGHTS | Kemikler geometriyi nasıl eğer? | Skinning (bu sayfa) |
| 4 · Şekil | morph targets | Yüz / şekil anahtarı nasıl? | Morph Targets |
Skinning nedir? (Format dilinde)
Zihin modeli: iskelet askısı + kumaş düğmeleri
- Joint node askı çubuğu: TRS ile hareket eder.
- Inverse bind «kumaş bu askıya nasıl gerildi?» ölçüsü.
- JOINTS / WEIGHTS her kumaş noktasının hangi askılara, ne kadar tutunduğu.
- Channel askıyı döndürür; skin kumaşı askıya bağlar.
DCC'de skinning «paint weight + bind» sürecidir. glTF'de süreç bitmiş sonuçtur: hangi köşenin hangi joint slotuna hangi ağırlıkla bağlı olduğu binary'de durur; paint brush yoktur. Bu yüzden web'de weight düzeltemezsiniz; yeniden export gerekir.
Skinning şunların hiçbiri değildir:
- Keyframe tablosu değil hareket örnekleri Keyframe sayfasında
- Channel path değil «rotation'a yaz» Channels sayfasında
- Morph shape değil delta pozisyon Morph Targets'ta
- SkinnedMesh API değil Three.js Skinning System sayfasında
- Physics / cloth sim değil format dışı
Channel «kemik nereye gitti?» der. Skin «köşe o kemiği ne kadar dinliyor?» der. İkisi olmadan karakter ya boş hiyerarşi döner ya da donuk mesh kalır.
skins[]: joint kataloğu
Kök JSON'daki skins dizisinin her elemanı bir iskelet tanımıdır. Tipik
alanlar:
"skins": [{
"name": "Character_Armature",
"joints": [2, 3, 4, 5, 6, …],
"inverseBindMatrices": 42,
"skeleton": 1
}]
joints:nodes[]indekslerinin sıralı listesi (joint slot sırası)inverseBindMatrices:MAT4accessor indeksi; uzunluk = joints uzunluğuskeleton(isteğe bağlı): ortak kök node indeksi (armature root)
Holodepth kritik ayrım: joint slot indeksi (0…N−1,
joints dizisindeki konum) ile node indeksi
(nodes[] içindeki gerçek numara) aynı şey değildir.
JOINTS_0 attribute'u joint slot yazar; channel
target.node ise node indeksidir. Karıştırmak «yanlış kemik dönüyor»
semptomunun bir numaralı nedenidir.
Skinsiz dosya geçerlidir
Statik prop'larda skins yoktur. Skin «zorunlu katman» değil; karakter /
organik deform ihtiyacında gelir. «Animasyon var = skin var» da yanlıştır: root node
translation animate edilebilir, skin olmadan mesh katı taşınır.
Inverse bind matrices: bind pozu sözleşmesi
Bind pose, mesh'in «giydirildiği» referans pozudur. Her joint için bir inverse bind matrix (IBM), o joint'in bind anındaki dünya (veya skin uzayı) transformunun tersidir. Deform formülünün özü:
// Kavramsal (runtime uygular; dosya matrisi taşır)
skinned = Σ (weight_i × jointMatrix_i × IBM_i × bindPosition)
Dosya yalnızca IBM accessor'ını taşır; canlı jointMatrix her karede
node hiyerarşisinden hesaplanır. IBM yanlışsa (yanlış uzay, yanlış sıra, eksik
joint) mesh «patlar», «içe çöker» veya bind'den asla çıkmaz. Bu semptomlar channel
keyframe'inden bağımsızdır: Idle clip bile bozuk IBM ile çöker.
Count uyumu
inverseBindMatrices accessor count =
joints.length olmalıdır. Eksik veya fazla IBM bozuk dosyadır.
Accessor tipi MAT4, bileşen tipi tipik FLOAT'tur.
Accessor Mantığı okuma kurallarını verir; bu sayfa
«neden MAT4 dizisi?» sorusunu sorar.
Bind vs rest vs t0
Bind pose export anındaki skin referansıdır. Rest pose node'ların statik TRS'idir. Clip'in t=0 keyframe'i üçüncü bir poz olabilir. Üçü hizasızsa oynatma başında «bir kare snap» görülür ( Keyframe · rest pose). Skinning teşhisinde önce IBM bütünlüğüne, sonra rest/t0 hizasına bakın.
JOINTS_* /
WEIGHTS_* öznitelikleri
Skinned primitive'in attributes haritasında en az bir çift bulunur:
| Attribute | Tip (tipik) | Anlam |
|---|---|---|
JOINTS_0 |
VEC4 (UNSIGNED_BYTE / SHORT) |
Joint slot indeksleri (en fazla 4) |
WEIGHTS_0 |
VEC4 float |
Ağırlıklar; genelde toplam ≈ 1 |
JOINTS_1 / WEIGHTS_1 |
aynı | Ek 4 etki (8-bone); opsiyonel |
Genel attribute sözlüğü Vertex Verileri'ndedir; burada semantik netleşir: JOINTS değeri skin.joints dizisindeki sıra numarasıdır, node indeksi değildir. WEIGHTS_0.x, JOINTS_0.x slotuna aittir; bileşen hizası bozulursa yanlış kemik «yağlanır».
Ağırlık toplamı
Pratikte köşe başına ağırlıklar normalize edilir (toplam 1). Spec her validator'un aynı sıkılığı uygulamaz; 0.97…1.03 aralığı yaygındır. Sıfır toplamlı köşe «hiçbir kemiğe bağlı değil» demektir: o köşe bind'de donar veya orijine çöker. Holodepth envanter: WEIGHTS sum histogramı (pipeline tool) bozuk paint'i erken yakalar.
4-bone (VEC4) limiti
Core pratikte köşe başına 4 joint etkisi (JOINTS_0) standarttır. Daha
fazla etki için JOINTS_1 gerekir; birçok runtime yalnızca _0'ı garanti
eder. Export «8 influence» DCC ayarı web'de sessizce 4'e kırpılabilir: omuz/kalça
kırışması artar. Bu, Three.js kemik limiti anlatımının
(Skinning System · kemik limiti) format yüzüdür:
dosyada kaç set attribute var?
Mesh / node ↔ skin indeksi
Skin'i mesh'e bağlayan tipik yol: bir nodes[i] hem
mesh hem skin indeksi taşır. Skin indeksi
skins[] elemanına işaret eder. Primitive attributes JOINTS/WEIGHTS
taşımazsa skin indeksi anlamsızlaşır; JOINTS varsa ama node.skin yoksa loader
skinned mesh üretemeyebilir.
"nodes": [{
"name": "Body",
"mesh": 0,
"skin": 0
}]
Bir dosyada birden fazla skin olabilir (ayrı ekipman, ayrı karakter). Aynı skin'i paylaşan birden fazla mesh de mümkündür (LOD, giysi katmanı). Holodepth: «kaç skin?» ile «kaç skinned mesh node?» sayılarını ayrı raporlayın.
skeleton alanı
İsteğe bağlı skeleton, joint hiyerarşisinin ortak köküne işaret eder.
Runtime iskeleti bu kökten gezinebilir. Eksikliği her zaman hata değildir; joints
listesi yeterlidir. Yanlış skeleton kökü helper çiziminde veya pose reset'te sapma
üretir; deform formülünün kendisi joints + IBM + weights üçlüsüne dayanır.
Skin vs channel: iki farklı «kemik» dili
Animasyon channel'ı joint node'unun TRS'ini yazar. Skin, köşeleri joint slot'larına bağlar. Aynı fiziksel kemik iki dilde yaşar:
| Soru | Channel | Skin |
|---|---|---|
| Kim hareket eder? | target.node (node indeksi) |
Joint slot → joints[slot] → node |
| Ne değişir? | Node TRS | Köşe pozisyonu (deform) |
| Veri nerede? | samplers output | IBM + JOINTS/WEIGHTS |
| Yoksa ne olur? | Kemik dönmez | Mesh dönmez / katı kalır |
Holodepth teşhis cümlesi: «SkeletonHelper dönüyor, yüzey duruyor» → skin / weights sorunu. «Yüzey de helper da duruyor» → channel / clip sorunu. «Yüzey patlıyor» → IBM / slot indeksi sorunu.
Export: bind, kırpma, kayıp
DCC'deki IK, constraint ve control bone'lar glTF'e çoğu zaman bake edilmiş joint TRS + sabit skin weights olarak düşer ( Keyframe · bake). Skin weights bake edilmez: paint sonucu olduğu gibi taşınır (veya influence limiti ile kırpılır).
- Apply bind atlanursa IBM ile mesh uzayı uyuşmaz
- Non-deformer bone joints listesine girerse boş slot şişer
- Mirror / negatif scale IBM ve normal/tangent ile birleşir ( Tangent notu)
- Çoklu armature yanlış skin indeksine bağlanırsa yanlış iskelet giydirilir
FBX→glTF dönüşümünde joint sırası değişebilir; JOINTS indeksleri eski sıraya göre kaldıysa patlama görülür. Holodepth: dönüşüm sonrası joints sırası + IBM count + max(JOINTS) < joints.length üçlüsünü doğrulayın.
Loader köprüsü: format sınırı
GLTFLoader skins + JOINTS/WEIGHTS + node.skin üçlüsünü
SkinnedMesh + Skeleton + Bone ağacına çevirir.
Bu çevirinin API yüzü
Skinning System sayfasındadır. Format okuyucusu için
yeterli soru: dosyada skin var mı, attributes tam mı, IBM count uyumlu mu, joint
slot aralığı geçerli mi?
| glTF | Anlam | Runtime (Three.js özet) |
|---|---|---|
skins[] |
Joint kataloğu + IBM | Skeleton |
joints[] → nodes |
Kemik hiyerarşisi | Bone ağacı |
| node.mesh + node.skin | Giydirilmiş mesh | SkinnedMesh |
| JOINTS / WEIGHTS | Köşe bağları | skin attributes / GPU |
Holodepth perspektifleri çoğu dokümanda olmayan açılar
«Skinning = weights» özeti üretim teşhisini yarım bırakır. Aşağıdakiler sık, az yerde derin işlenir.
Root motion vs skinned walk
Karakter «yürüyor» sanılır ama yalnızca root node kayıyorsa ayaklar kayar (slide). Skin + bacak joint channel'ları yoksa bu beklenen davranıştır. Keyframe sayfasındaki «mesh animate olmuyor» notunun tamamlayıcısı: skin var mı, bacak joint'leri channel hedeflerinde mi?
Joint slot taşması
JOINTS değeri ≥ joints.length ise tanımsız erişimdir. Export hatası veya
joints listesi kısaltması sonrası artığından kalır. Validator kaçırabilir; max(JOINTS)
taraması Holodepth envanterinin parçası olmalıdır.
Paylaşılan skin, farklı mesh
Giysi ve beden aynı skin'i paylaşırsa tek iskelet iki yüzeyi eğer. Ayrı skin + ayrı armature ise iki iskelet senkronu gerekir (çift clip veya retarget). Format ikisini de destekler; ürün senkron politikası runtime'dadır.
JOINTS var, skin yok
Bazı bozuk export'lar attribute bırakıp node.skin yazmaz. Dosya
«skinned gibi» görünür ama loader static mesh üretir. Tersine skin var, JOINTS yok:
boş deform. İki yönlü tutarlılık şarttır.
TBN + skin
Skinning pozisyonu eğer; normal/tangent de joint matrisleriyle dönmelidir. Yalnızca POSITION skinlenip TBN sabit kalırsa ışık «yüzeyde kayar». Format attribute seti tam olsa bile runtime shader yolu eksik olabilir; teşhiste format mı shader mı ayırın ( Tangent Verileri ).
Altı soruluk skin teşhisi
| Soru | Yeşil ise | Kırmızı ise bak |
|---|---|---|
skins.length > 0? |
İskelet tanımı var | Export / yanlış asset |
| node.skin + JOINTS/WEIGHTS? | Giydirme tam | Tek taraflı kopukluk |
| IBM count = joints? | Bind hizalı | Patlama / çökme |
| max(JOINTS) < joints.length? | Slot geçerli | OOB / remap |
| WEIGHTS toplamı ≈ 1? | Paint sağlıklı | Donuk / uçan köşe |
| Joint node'lar channel hedefi mi? | Hareket → deform zinciri | Yalnızca root / yanlış node |
Holodepth içgörüsü
Skinning debug'unda önce shader'a veya mixer'a değil üçlü sözleşmeye bakın: skins.joints + IBM, JOINTS/WEIGHTS, node.skin. Üçü yeşilse sorun runtime/GPU yolundadır; biri kırmızıysa dosya sözleşmesi bozuktur. Channel yeşil + skin kırmızı = «kemik dönüyor, deri duruyor» klasik vakasıdır.
Skinning'den sonra
Kemik–köşe bağı netleşince sıradaki format sorusu şekil anahtarlarıdır:
- Morph Targets delta geometri, weights channel
- Runtime deform Skinning System
- Oynatma AnimationMixer
Format okuyucusu özeti: skin = joint kataloğu + IBM; köşe = JOINTS/WEIGHTS; node.skin = giydirme bağı. Channel askıyı döndürür, skin kumaşı tutturur.