holodepth

3D Model Formatları · glTF / GLB · Animasyon Sistemi

Morph Targets glTF'de Şekil Anahtarı Sözleşmesi

«Gülümseme DCC'de var, web'de yüz donuk» çoğu zaman mixer eksikliği değil; dosyada targets delta'larının veya weights kanalının kopukluğudur. Skinning kemikle eğer; bu sayfa dördüncü soruya geçer: şekil anahtarları dosyada nasıl saklanır ve hangi ağırlıkla karışır?

Holodepth Animasyon hattının son format katmanı morph'tur: primitive üzerindeki targets[] (delta attribute setleri), mesh/node weights (başlangıç karışımı), ve isteğe bağlı animasyon path: "weights". Runtime morphTargetInfluences bu sözleşmeyi API'ye çevirir; bu sayfa dosya sözleşmesini sabitler.

Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «glTF morph target, taban geometriye eklenecek delta attribute paketidir. Her target bir ağırlıkla ölçeklenir; sonuç lineer kombinasyondur. İsimler çoğu zaman extras/uzantıdadır; core zorunlu alan indeks sırasıdır. Skinning joint matrisiyle eğer, morph köşe delta'sıyla eğer; ikisi aynı mesh'te birleşebilir.»

Bu sayfanın sınırı · komşu konularla ayrım

Bu sayfa glTF morph dosya sözleşmesini anlatır:

  • primitives[].targets[] delta attribute'ları
  • POSITION / NORMAL / TANGENT delta
  • mesh.weights / node weights
  • Animasyon path: "weights" uzunluk sözleşmesi
  • Sparse accessor, isimlendirme, Holodepth teşhis açıları

Bilinçli olarak dışarıda bırakılan konular:

Kısa ayrım: Morph Targets (Format) «delta ve weights dosyada nasıl?» · Morph Targets (Runtime) «influences nasıl yazılır?» · Skinning (Format) «kemik–köşe bağı»

Animasyon hattı dördü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
4 · Şekil targets · weights Yüz / şekil anahtarı nasıl? Morph Targets (bu sayfa)

Morph target nedir? (Format dilinde)

Zihin modeli: taban heykel + kil yamaları

  • Taban mesh nötr heykel (attributes.POSITION).
  • Her target bir kil yaması: «gülümseme farkı», «göz kırpma farkı».
  • Ağırlık yamanın ne kadar yapıştırılacağı (0…1, bazen dışı).
  • Sonuç taban + Σ (ağırlık × delta); formül runtime'da, delta dosyada.

DCC'de «shape key / blend shape / morph» timeline kaydırıcısıdır. glTF'de karşılığı kurudur: her target, taban attribute ile aynı vertex sırasına hizalı delta accessor setidir. Absolute pozisyon kopyası değil; fark vektörüdür. Bu yüzden «hedef mesh'i ayrı GLB» sanmak yanlıştır; tek primitive içinde birden fazla delta paketi yaşar.

Morph Targets (format) şunların hiçbiri değildir:

  • Skinning değil joint matrisi yok; köşe–kemik bağı Skinning'de
  • Displacement texture değil doku zinciri Materyal Sistemi'nde
  • morphTargetInfluences API değil Three.js Morph sayfasında
  • Face rig UI / FACS paneli değil sanat aracı katmanı
  • Physics soft body değil format dışı

Skinning «iskelet askısı kumaşı eğer» der. Morph «kil yaması doğrudan köşeye eklenir» der. İkisi aynı yüzde birleşebilir: kemik çeneyi açar, morph dudağı şekillendirir.

targets[]: delta paketleri

Morph verisi meshes[].primitives[].targets dizisindedir. Her eleman bir target'tır; içinde tabanla aynı semantik anahtarlar (çoğunlukla POSITION, isteğe bağlı NORMAL, TANGENT) accessor indekslerine işaret eder.

"meshes": [{
  "weights": [0, 0, 0],
  "primitives": [{
    "attributes": {
      "POSITION": 0,
      "NORMAL": 1
    },
    "targets": [
      { "POSITION": 10, "NORMAL": 11 },
      { "POSITION": 12, "NORMAL": 13 },
      { "POSITION": 14, "NORMAL": 15 }
    ]
  }]
}]

Holodepth envanter sayıları:

  • Target sayısı = targets.length
  • Weights uzunluğu aynı sayıya eşit olmalı
  • Vertex count taban POSITION ile her target POSITION aynı count

Target sırası isimden önce gelir: indeks 0 «smile» olabilir veya olmayabilir; core zorunlu isim alanı yoktur. İsimleme aşağıda (§7).

Targetsiz dosya geçerlidir

Morph olmayan mesh core glTF'dir. Morph «zorunlu katman» değil; yüz / kas / ezilme ihtiyacında gelir. «Animasyon var = morph var» yanlıştır: yalnızca TRS channel'ı olan karakter morph taşımıyor olabilir.

Delta semantiği: ne taşınır?

Target içinde tipik attribute'lar
Anahtar Anlam Not
POSITION Konum farkı (delta) Neredeyse her zaman zorunlu pratik
NORMAL Normal farkı Işık tutarlılığı için önerilir
TANGENT Tangent farkı Normal map + morph birleşiminde

Delta, «hedef mutlak pozisyon» değildir: final = base + w × delta. Export mutlak shape yazarsa loader/glTF araçları çoğu zaman delta'ya çevirir; yanlış kalırsa «çifte ofset» (yüz iki kat şişer) görülür. Holodepth teşhisi: ağırlık 1.0'da beklenen şekil ile dosyadaki max displacement'i karşılaştırın.

NORMAL / TANGENT eksikliği

Yalnızca POSITION morph'lanıp NORMAL sabit kalırsa ışık «şekli takip etmez»: gölge eski yüzde kalır. Tangent eksikliği normal map'li yüzde benzer kayma üretir ( Tangent Verileri). Format geçerli olabilir; görsel kalite sözleşmesi eksiktir.

TEXCOORD / COLOR morph?

Core pratikte morph target'lar geometri (POSITION/NORMAL/TANGENT) odaklıdır. UV veya renk morph'u yaygın core path değildir; ihtiyaç varsa uzantı veya ayrı pipeline gerekir. «Albedo animasyonu morph'ta» varsayımı çoğu zaman yanlıştır.

weights: başlangıç karışımı

meshes[i].weights (ve bazı durumlarda node üzerindeki weights) her target için başlangıç ağırlığını verir. Uzunluk = target sayısı. Eksik weights çoğu loader'da sıfır dizi varsayılır (nötr yüz).

  • Hepsi 0: taban şekil (Idle yüz)
  • Bir tanesi 1: o target tam uygulanmış
  • Birden fazla > 0: lineer karışım (smile + blink)

Ağırlık aralığı pratikte 0…1'dir; spec dışına çıkan değerler (negatif, >1) abartılı veya ters morph üretebilir. Ürün kodu clamp edebilir; dosya sözleşmesi her zaman clamp demez.

Statik weights vs animate weights

Mesh.weights «dosya açılış pozu»dur. Animasyon target.path === "weights" kanalı zaman içinde bu diziyi ezer ( Channels · weights path). Mixer yoksa yalnızca statik weights görülür; «morph animate olmuyor» teşhisinde önce channel var mı sorun.

Animasyon: path: "weights"

Morph animasyonu ayrı bir «yüz klibi formatı» değildir; aynı animations[] içinde weights path'li channel'dır. Sampler output'u tipik olarak her keyframe'de tüm target ağırlıklarını sıralı yazar.

// Kavramsal: M target için her keyframe M SCALAR
output keyframe k: [w0, w1, …, w(M-1)]
// accessor count ≈ keyframeSayısı × M  (CUBICSPLINE'da 3× faktör)

Holodepth uzunluk kuralı: output'taki morph boyutu = targets.length. 8 target varken output 5 öğe taşıyorsa kısmi ifade veya truncation oluşur ( Channels · weights uzunluğu). Tersi (fazla öğe) tanımsız artıktır.

Channel target.node

Weights channel'ı morph'lu mesh'i taşıyan node'a (veya weights'in uygulandığı node'a) işaret etmelidir. Yanlış node indeksi «clip var, yüz oynamıyor» üretir; skinning'deki yanlış joint node tuzağının morph yüzüdür.

Interpolation ve yüz

LINEAR ağırlık geçişi yumuşak mimik verir; STEP ani ifade değişimi (karikatür / UI state) içindir. CUBICSPLINE yüz kanallarında da mümkündür; output düzeni 3× şişer ( Channels · CUBICSPLINE). Easing API dosyada yoktur; dense LINEAR veya CUBICSPLINE ile yaklaşılır.

Sparse accessor: seyrek delta

Bir gülümseme çoğu köşeyi sıfır bırakıp yalnızca ağız çevresini hareket ettirir. glTF sparse accessor ile yalnızca değişen indeksleri ve değerlerini saklayabilir; geri kalan taban (veya sıfır) varsayılır. Bu, morph binary'sini küçültmek için kritik Holodepth üretim aracıdır.

  • Kazanç: yüz / kas morph'larında ciddi boyut düşüşü
  • Risk: sparse bozulursa yanlış köşe kayar; debug zorlaşır
  • Teşhis: accessor.sparse var mı, count ile indices uyumlu mu?

Sparse mekanizmasının genel okuması Accessor / BufferView hattındadır; burada «morph için neden sık kullanılır?» sorusu sabitlenir. Draco geometriyi sıkıştırır; morph delta'ları ayrı kalır; sparse morph boyutu için birincil format içi çözümdür.

İsimlendirme: indeks önce, isim sonra

Core glTF target'lara zorunlu name vermez. İsimler pratikte:

  • mesh.extras.targetNames (yaygın extras sözleşmesi)
  • Vendor / DCC uzantı alanları
  • Loader'ın ürettiği dictionary (runtime)

Ürün kodu influences[dict["smile"]] ile isimden giderse extras kaybında kırılır. Holodepth: export sonrası isim listesini doğrulayın; yoksa indeks sözleşmesini dokümante edin. Material Slots / clip name tuzağının morph yüzü budur.

Sıra kararlılığı

Target sırası DCC export sırasına bağlıdır. «smile» indeksi 2 iken yeniden export'ta 5 olabilir. Animate weights output sırası target sırasına kilitlidir; isim değil indeks hizası bozulursa yanlış mimik çalar. Pipeline'da target sırasını kilitleyin veya isim→indeks map'ini her build'de yeniden üretin.

Morph vs skinning: aynı mesh, iki deform

İki deform katmanı
Soru Morph Skinning
Veri birimi Delta attribute JOINTS / WEIGHTS + IBM
Kontrol weights skaleri Joint node TRS
Tipik kullanım Yüz, kas, ezilme Vücut, uzuv
Animasyon path weights translation / rotation / scale

Aynı primitive hem targets hem JOINTS taşıyabilir. Uygulama sırası runtime/shader sözleşmesidir (genelde morph sonra skin veya tersi; motora bakın). Format sıra taşımaz. Teşhis: yüz bozuk → morph; kol bozuk → skin; ikisi birden → her iki envanteri ayrı yeşile boyayın.

Derin runtime karşılaştırma ve kod örnekleri Three.js Morph · vs skeletal tablosundadır; burada yalnızca dosya ayrımı sabitlenir.

Holodepth perspektifleri çoğu dokümanda olmayan açılar

«targets + weights» listesi üretim teşhisini yarım bırakır. Aşağıdakiler sık, az yerde derin işlenir.

Vertex count uyuşmazlığı

Target POSITION count ≠ taban count bozuk dosyadır. Export LOD veya decimate sonrası morph'u güncellemeyi unutursa oluşur. Semptom: loader reddi veya çöplük geometri.

Çifte delta / mutlak shape

Mutlak shape yanlışlıkla delta sanılırsa ağırlık 0.5'te bile aşırı şişme görülür. Tersine delta iki kez çıkarılmışsa morph «ters yönde» gider. DCC export seçeneklerinde «relative / absolute» anahtarına bakın.

Target şişkinliği

100+ shape key web için pahalıdır: her target vertex × float × attribute. Sparse yardımcı olur; yine de CPU/GPU morph slot limiti runtime'dadır ( Three.js · morph bütçe). Format tarafı: hangi target'lar gerçekten kullanılıyor? Kullanılmayanları dosyadan çıkarın.

Primitive başına targets

Çoklu primitive mesh'te (Material Slots) her primitive kendi targets dizisine sahip olabilir. Yüz primitive'inde morph var, gövde primitive'inde yok: geçerlidir. Tek weights kanalının hangi node/mesh'e gittiğini netleştirin; yanlış primitive'e bağlanan channel sessiz no-op üretir.

Draco + morph

Draco taban geometriyi sıkıştırır; morph target'ların Draco ile birlikte nasıl taşındığı uzantı / araç zincirine bağlıdır. «Draco açtım, morph kayboldu» semptomu sık pipeline bug'ıdır. Holodepth: compress sonrası targets.length ve weights animasyonunu yeniden doğrulayın ( Draco Mesh Compression).

Altı soruluk morph teşhisi

Morph katmanı kontrol listesi
Soru Yeşil ise Kırmızı ise bak
targets.length > 0? Şekil anahtarı var Export / yanlış mesh
Target POSITION count = taban? Hiza tamam LOD / decimate kayması
weights uzunluğu = target sayısı? Karışım tanımlı Eksik / fazla dizi
weights channel output boyutu uyumlu mu? Animate edilebilir Kısmi mimik / truncation
Channel target.node doğru mu? Doğru mesh güncellenir Yanlış node / primitive
NORMAL (ve gerekirse TANGENT) delta var mı? Işık şekli takip eder Gölge kayması

Holodepth içgörüsü

Morph debug'unda önce morphTargetInfluences'a değil targets + weights uzunluğu + weights channel üçlüsüne bakın. Üçü yeşilse sorun runtime API veya mixer'dadır; biri kırmızıysa dosya sözleşmesi bozuktur. Skin yeşil + morph kırmızı = «vücut oynar, yüz donuk» klasik vakasıdır.

Animasyon Sistemi kapanır; sıradaki dallar

Format Animasyon omurgası dört soruyla tamamlandı: keyframe → channel/sampler → skinning → morph. Sıradaki Holodepth dalları:

  1. Uzantılar grubu Draco, Basis, GPU instancing (tek uzantı derin sayfalar)
  2. Runtime morph API Morph Targets (Three.js)
  3. Runtime skin Skinning System
  4. Oynatma AnimationMixer

Format okuyucusu özeti: targets = delta paketleri; weights = karışım; path weights = zamanlı karışım. Skin askıyla eğer, morph yamayla eğer; ikisi birlikte karakteri tamamlar.