Tarayıcıda Three.js + USDC
Diyelim ki Maya veya Houdini'den aldığınız bir .usdc dosyanız var ve bunu bir Three.js sahnesinde göstermek istiyorsunuz. Ben de bu durumla karşılaştım. Yakın zamana kadar seçenekler pek iyi değildi. Dosyayı çevrimdışı olarak glTF'ye dönüştürebilir, OpenUSD'nin bir WASM derlemesini çalıştırabilir ya da vazgeçip farklı bir format kullanabilirdiniz.
Bu rehber, @cinevva/usdjs kullanarak USDC'yi doğrudan JavaScript'te nasıl ayrıştıracağınızı ve elde edilen verileri Three.js'e nasıl aktaracağınızı gösteriyor.
USDC Nedir?
USD dosyalarının üç çeşidi vardır. USDA, insanlar tarafından okunabilen ve hata ayıklaması kolay olan ancak ayrıntılı metin sürümüdür. USDC (bazen "Crate" olarak adlandırılır), kompakt olduğu ve yerel araçlarda hızlı yüklendiği için prodüksiyon iş akışlarında kullanılan ikili formattır. USDZ ise USDC ile dokuları içeren ve Apple'ın AR Quick Look için kullandığı bir zip arşividir.
Ancak bir sorun var: USDC, tescilli bir ikili formattır. Pixar, referans uygulamasını C++ ile yazdı ve bugüne kadar onu okuyabilen saf JavaScript tabanlı bir çözüm yoktu. Bu durum değişmeye başlıyor: Alliance for OpenUSD, Aralık 2025'te OpenUSD sahne verilerinin nasıl yapılandırıldığını, birleştirildiğini ve aktarıldığını belgeleyen, onaylanmış ilk standart olan Core Specification 1.0'ı yayımladı; 1.1 revizyonu üzerinde de şimdiden çalışılıyor. Ancak referans uygulama hâlâ Pixar'ın C++ kod tabanında bulunuyor. Bu nedenle JavaScript'ten bu formata erişmenin pratik yolu hâlâ ayrı bir okuyucu kullanmak.
Bu Neden Önemli Olabilir?
Film veya görsel efekt iş akışlarından gelen içeriklerle çalışması gereken 3D web uygulamaları geliştiriyorsanız USD ile mutlaka karşılaşırsınız. Sanatçılar Maya, Houdini veya Blender'dan dışa aktarım yapar ve bu çıktılar çoğunlukla USDC formatındadır.
@cinevva/usdjs öncesinde üç seçeneğiniz vardı. USDC'yi metin formatına dönüştürmek için usdcat çalıştırabilirdiniz; ancak bu, derleme sürecine ek bir adım ekler ve ikili formatın kompaktlığını ortadan kaldırırdı. OpenUSD veya TinyUSDZ'yi WebAssembly olarak derleyebilirdiniz; ancak bu da paketinize megabaytlarca veri ekler ve iş parçacığı desteği için özel sunucu başlıkları gerektirirdi. Ya da USDZ'yi işleyebilen ancak sınırlı USDC desteğine ve çok temel birleştirme yeteneklerine sahip Three.js'in yerleşik USDLoader'ını kullanabilirdiniz.
Artık dördüncü bir seçenek var: USDC'yi yerel olarak JavaScript'te ayrıştırmak.
Nasıl Çalışır?
@cinevva/usdjs kütüphanesi, USD'nin temel işlevlerini TypeScript ile yeniden uygular. USDC ayrıştırıcısını, Pixar'ın C++ kaynak kodunu inceleyip Crate formatı belirtimini JavaScript'e uyarlayarak geliştirdim. Davranışın belirsiz olduğu durumlarda OpenUSD'nin yaptığını esas alıyoruz.
Pratikte şöyle görünür:
import { parseUsdcToLayer } from '@cinevva/usdjs';
// USDC dosyasını getir
const response = await fetch('/model.usdc');
const buffer = await response.arrayBuffer();
// Ayrıştır
const layer = parseUsdcToLayer(buffer, { identifier: 'model.usdc' });
// Artık primler, özellikler ve meta veriler içeren yapılandırılmış bir katmanınız var
console.log(layer.pseudoRoot.children);WASM yok. Yerel kod yok. Yalnızca baytları okuyup yapılandırılmış bir temsil oluşturan JavaScript var.
Three.js'e Bağlamak
USD'yi ayrıştırmak, sorunun yalnızca yarısıdır. USD kavramlarını da (primler, dönüşümler, ağ şemaları) Three.js nesnelerine dönüştürmeniz gerekir.
Aşağıda bir USDC dosyasını yükleyip Three.js ağları oluşturan temel bir örnek yer alıyor:
import * as THREE from 'three';
import { UsdStage, parseUsdcToLayer } from '@cinevva/usdjs';
async function loadUsdcToThree(url: string, scene: THREE.Scene) {
// 1. Getir ve ayrıştır
const buffer = await fetch(url).then(r => r.arrayBuffer());
const layer = parseUsdcToLayer(buffer, { identifier: url });
// 2. Bir sahne alanı oluştur (referanslar varsa birleştirmeyi yönetir)
const stage = UsdStage.open(layer);
// 3. Prim ağacını dolaş
for (const prim of stage.traverse()) {
// Geometri olmayanları atla
if (prim.typeName !== 'Mesh') continue;
// Geometri verilerini al
const points = prim.getAttribute('points')?.value;
const faceVertexIndices = prim.getAttribute('faceVertexIndices')?.value;
const faceVertexCounts = prim.getAttribute('faceVertexCounts')?.value;
if (!points || !faceVertexIndices || !faceVertexCounts) continue;
// Three.js geometrisine dönüştür
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position',
new THREE.Float32BufferAttribute(points.flat(), 3)
);
// USD, faceVertexCounts + faceVertexIndices kullanır; Three.js ise düz bir indeks dizisi ister
// Üçgenleştirilmiş ağlarda bu işlem basittir:
geometry.setIndex(Array.from(faceVertexIndices));
geometry.computeVertexNormals();
// Ağ oluştur
const material = new THREE.MeshStandardMaterial({ color: 0x888888 });
const mesh = new THREE.Mesh(geometry, material);
// Dönüşümü uygula
const xform = getWorldTransform(prim);
mesh.matrix.fromArray(xform);
mesh.matrixAutoUpdate = false;
scene.add(mesh);
}
}
function getWorldTransform(prim): number[] {
// Basitleştirilmiş sürüm: pratikte üst öğe dönüşümlerini birleştirmeniz gerekir
const xformOp = prim.getAttribute('xformOp:transform');
if (xformOp?.value) {
return xformOp.value.flat();
}
return [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
}Bu örnek basitleştirilmiştir. Gerçek kodun dönüşüm yığınlamasını (USD primleri birlikte birleştirilen birden fazla xformOp niteliğine sahip olabilir), alt bölüm yüzeylerini (catmullClark alt bölümüne sahip ağlar gerçek alt bölüm işlemi gerektirir), malzemeleri (UsdPreviewSurface parametreleri Three.js MeshStandardMaterial ile eşleştirilir), dokuları (varlık yollarının çözümlenmesi ve yüklenmesi gerekir) ve iskelet animasyonunu (UsdSkel bağlamalarının SkinnedMesh biçimine dönüştürülmesi gerekir) işlemesi gerekir.
Tüm bunların birlikte nasıl çalıştığını görmek istiyorsanız @cinevva/usdjs-viewer paketine göz atın. Bu, eksiksiz bir referans uygulamadır.
Birleştirme Sandığınızdan Daha Önemlidir
Tek bir USDC dosyasını ayrıştırmak işin kolay kısmıdır. Gerçek USD sahneleri; alt katmanların, referansların, yüklerin ve varyantların birlikte çalıştığı birleştirme sistemini kullanır.
Bir otomobil modeli düşünün. Gövde body.usdc dosyasına, tekerlekler wheel.usdc dosyasına referans verir ve "sport" ile "sedan" yapılandırmaları için varyantlar bulunur. Nihai sahne, çalışma zamanında tüm bu parçalardan bir araya getirilir.
Bunu şu şekilde yönetebilirsiniz:
import { UsdStage, parseUsdcToLayer, FetchResolver } from '@cinevva/usdjs';
// Referans verilen dosyaların nasıl getirileceğini bilen bir çözümleyici oluştur
const resolver = new FetchResolver({
baseUrl: '/assets/',
});
// Birleştirme özelliğiyle aç
const stage = UsdStage.open(rootLayer, { resolver });
// Bir varyant seçimi ayarla
stage.setVariantSelection('/Car', 'bodyStyle', 'sport');
// Şimdi birleştirilmiş sahneyi dolaş
for (const prim of stage.traverse()) {
// Çözümlenmiş referansları ve seçili varyantı görürsünüz
}Çözümleyici, referans verilen USDC dosyalarını gerektiğinde getirir. Birleştirme JavaScript'te gerçekleştirilir ve usdcat --flatten komutundan elde edeceğiniz düzleştirilmiş sahneyi üretir.
Performans
Açık konuşalım: USDC'yi JavaScript'te ayrıştırmak, yerel C++ kodundan daha yavaştır. WASM ve derleme adımlarını atlamanın karşılığı budur.
Pratikte, 10 MB'tan küçük ve 100 bin üçgenden daha azına sahip, web'de kullanılan tipik modellerin modern donanımlarda ayrıştırılması 50-200 ms sürer. Bir yükleme göstergesi sunarsanız bu süre ilk yükleme için gayet kabul edilebilirdir.
Bunu daha hızlı hâle getirebilirsiniz. Sahnenin tamamını en başta yüklemeyin. Kök katmanı yükleyin, yapabildiğiniz kadarını işleyin ve ardından yükleri gerektiğinde getirin. Arayüzün yanıt vermeye devam etmesi için ayrıştırma işlemini bir Web Worker'a taşıyın. Tekrar ziyaretlerde anında yükleme sağlamak için ayrıştırılmış katmanları IndexedDB'de önbelleğe alın. Tam sahne aktarılırken düşük çözünürlüklü bir önizleme gösterin.
Aşağıda bir Web Worker kurulumu yer alıyor:
// worker.ts
import { parseUsdcToLayer } from '@cinevva/usdjs';
self.onmessage = async (e) => {
const { buffer, identifier } = e.data;
const layer = parseUsdcToLayer(buffer, { identifier });
// Katman verilerini serileştir (metotları değil)
const data = serializeLayer(layer);
self.postMessage(data);
};
// main.ts
const worker = new Worker(new URL('./worker.ts', import.meta.url));
worker.postMessage({ buffer, identifier: 'model.usdc' });
worker.onmessage = (e) => {
const layerData = e.data;
// layerData'dan Three.js sahnesini oluştur
};Neler Çalışıyor, Neler Çalışmıyor?
Yaygın özelliklerin çoğu çalışıyor. Geometri (ağlar, noktalar ve eğriler), sıkıştırılmış köşe dizileri de dâhil olmak üzere doğru biçimde ayrıştırılıyor. Dönüşümler, tam xformOp yığınlamasıyla çalışıyor. Malzemeler UsdPreviewSurface üzerinden PBR'a eşleniyor. Birleştirme; alt katmanları, referansları, yükleri, varyantları ve kalıtımı destekliyor. Bir çözümleyici sağlarsanız dokular çözümlenip yükleniyor. Temel iskelet animasyonu, yaygın karakter donanımlarıyla çalışıyor.
Yine de bazı eksikler var. Bu bir Hydra uygulaması değildir; dolayısıyla USD verilerini kullandığınız işleme motoruna dönüştürmek sizin sorumluluğunuzdadır. Kolaylık sağlayan metotlara sahip UsdGeomMesh benzeri tür güvenli şema API'leri yoktur. Genel primler ve niteliklerle çalışırsınız. Özelleştirmeler, yeniden konumlandırmalar ve değer klipleri gibi bazı birleştirme özellikleri henüz uygulanmamıştır. Basit UsdPreviewSurface kullanımının ötesindeki karmaşık malzeme ağlarının özel olarak işlenmesi gerekir.
Ne Zaman Kullanılmalı?
Bu çözüm; WASM derleme adımı olmadan bir web uygulamasında USD dosyaları yüklemeniz gerektiğinde, iş akışınız USDC üretiyorsa ve glTF'ye dönüştürmek istemiyorsanız, tarayıcı için bir USD görüntüleyici veya düzenleyici geliştiriyorsanız ya da USD yapısını yalnızca işlemek yerine incelemek istiyorsanız mantıklıdır.
Her uç durumu kapsayan tam OpenUSD uyumluluğuna ihtiyacınız varsa, sahneleriniz çok büyükse (100 MB+) ve yerel performans gerektiriyorsa ya da zaten bir WASM derlemesi kullanıyorsanız ve bunun karmaşıklığı projeniz için kabul edilebilirse başka bir çözüm kullanın.
Kaynaklar
Üç paket bulunur: temel ayrıştırma ve birleştirme için @cinevva/usdjs, Three.js tabanlı bir tarayıcı görüntüleyicisi için @cinevva/usdjs-viewer ve testlerde başsız PNG işleme için @cinevva/usdjs-renderer.
Belgeler için usdjs API Referansı, Pixar OpenUSD Belirtimi ve Three.js Belgeleri sayfalarına göz atın.
USDC ayrıştırıcısının Pixar'ın uygulamasıyla nasıl eşleştiğini anlamak istiyorsanız usdjs deposundaki src/usdc/PIXAR_PARITY.md dosyasına bakın.
Deneyin
Bunun nasıl çalıştığını görmenin en hızlı yolu usdjs-viewer demosunu ziyaret edip üzerine bir USDC dosyası bırakmaktır.
Kendi projenize entegre etmek için paketi yükleyin ve yukarıdaki kod örnekleriyle başlayın:
npm install @cinevva/usdjsTarayıcıda USD kullanmak mümkündür. Her zaman doğru tercih olmayabilir; ancak ihtiyaç duyduğunuzda saf JavaScript ile ayrıştırma, ilgilenmeniz gereken bir derleme adımını ve bir bağımlılığı ortadan kaldırır.
İlgili İçerikler
- Oyun geliştiricileri için WebGL temelleri — Three.js sahnelerine güç veren işleme API'si
- 2026'da Web Oyunları Teknoloji Yığını — Three.js'in WebGL/WebGPU/Wasm ekosistemindeki yeri
- Tarayıcıda 3D Açık Dünya Teknolojisi — açık dünyalar için USD dâhil 3D varlıkların akışla yüklenmesi
- Ücretsiz Oyun Varlıkları Nerede Bulunur? — Three.js ile uyumlu 3D model kaynakları