holodepth

Oyun geliştirme · Three + fizik köprüsü

Rapier / Cannon Yüzeyi: Three ile Fizik Köprüsü

Three.js sahneyi çizer; fizik motoru dünyayı simüle eder. Köprü yüzeyi bu iki dünyayı aynı ürün kimliğiyle eşler: hangi mesh hangi collider, world nasıl kurulur, kare sonunda pozisyon kimden kime akar. Bu sayfa motor seçimi ve senkron sözleşmesidir; tam fizik ders kitabı veya glTF şema derinliği değildir.

Holodepth bu yaprağı «fizik motoru nasıl yazılır?» veya ECS mimarisi dersi olarak yazmaz. Hafif entity modeli Sahne & entity hafif modeli yaprağındadır. Animasyon döngüsü ve zaman Three · Animasyon döngüsü & zaman omurgasındadır. Picking ile fizik çarpışması karıştırılmaz; isabet yüzeyi R3F · Pointer & picking (ve Three raycast omurgası) ayrı politikadır. glTF collider metadata bu kapının konusu değildir.

Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «Three görsel, fizik ayrı. Rapier veya Cannon ürün ihtiyacına göre seçilir. World ve body kurulumu tek sözleşmede yazılır. Mesh ↔ collider eşlemesi bilinçlidir. Senkron yönü mühürlenir. Sonraki kapı çarpışma tepkisi köprüsüdür.»

Köprü katmanı yazılı hâle geldiğinde ekip içi tartışmalar da kısalır: «neden top duvardan geçiyor» sorusu artık motor içi bir muamma değil, mesh ↔ collider eşleme tablosunda aranan bir satırdır.

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

Bu sayfa Three + fizikte motor yüzeyi ve senkron köprüsünü anlatır:

  • Rapier vs Cannon seçim eşiği
  • World + body kurulumu
  • Mesh ↔ collider eşlemesi
  • Tek yönlü / çift yönlü senkron politikası

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

Kısa ayrım: Bu sayfa «world nasıl kurulur ve mesh nereye bağlanır?» · Çarpışma köprüsü «temas sonrası oyun ne yapar?» · Hexovian «motor içi ve netcode mimarisi» · Picking «ışın isabeti, fizik değil».

Köprü mantığı: görsel ≠ simülasyon

Three Object3D ağacı render ve sahne hiyerarşisidir. Rapier veya Cannon World içinde rigid body, collider ve joint taşır. Üretimde ikisini aynı nesne sanmak ilk çöküş noktasıdır: mesh materyali değişir, collider sabit kalır; scale animasyonu görseldir, fizik ölçeği başka birimdedir.

Holodepth kuralı: her oyun varlığına tek ürün kimliği verin; görsel kök ve fizik handle bu kimliğe map edilir. Köprü katmanı «entity lite» yaprağındaki sözlüğü fizik tarafına uzatır.

Bu karışıklık genelde iki yerde patlar: ilki, bir mesh'in scale veya position'ını doğrudan animasyon ile değiştirip collider'ın buna otomatik uyacağını ummak; ikincisi, fizik body'sinin her karede mesh'e «senkron» olduğunu düşünüp tek yönlü akışı unutmak. Köprü katmanı bu iki varsayımı da açıkça yazılı bir sözleşmeye çevirir.

Mesh çizer; world simüle eder. Köprü sözleşmedir.

Rapier vs Cannon: ne zaman hangisi

Holodepth motor seçimini «en popüler» ile değil, ürün eşiği ile yapar. Rapier (Rust tabanlı, WASM) çoğu web 3D oyunda yüksek gövde sayısı ve stabil adım performansı için tercih edilir. Cannon.js (ve türevleri) daha hafif yüzey, eski örnek ekosistemi veya küçük sahneler için hâlâ görülür; API şekli benzer kalır: world, body, shape, step.

Rapier / Cannon · ürün notu (sürüm bağımsız yüzey)
İhtiyaç Rapier eğilimi Cannon eğilimi
Çok gövde, web WASM Güçlü aday Ölçek sınırı düşünülür
Minimal prototip, az cisim Uygun Uygun
Mevcut Cannon örnek portu Yeniden yazım Düşük sürtünme
İç motor / netcode derinliği Hexovian izleği

Bu sayfa API isimlerini sürüme göre doğrulamanızı ister; örnekler eğitim amaçlı pseudo-yüzey kullanır.

Rapier'ın WASM modülü ilk yüklemede ek bir ağ isteği ve init süresi getirir; bu, asset pipeline'daki öncelik katmanlaması ile aynı mantıkla ele alınır — fizik dünyası oyuncu etkileşime geçmeden hazır olmalı, ama sayfanın ilk boyanmasını bloklamamalıdır.

Bu sayfa API isimlerini sürüme göre doğrulamanızı ister; örnekler eğitim amaçlı pseudo-yüzey kullanır.

World kurulumu

Her iki motor ailesinde de dünya tek örnek olarak yaşar: yerçekimi vektörü, geniş faz sınırı (sleeping, CCD politikası) ve step fonksiyonu world üzerindedir. Three Scene ile bire bir eşlenmez; world yalnızca fizik varlıklarını tutar.

Holodepth: world oluşturmayı oyun başlatma fazına kilitleyin; hot reload veya çoklu canvas denemelerinde ikinci world sızıntısına izin vermeyin. Dispose / destroy yolu entity lite yaprağındaki yaşam döngüsü ile aynı cümlede yazılmalıdır.

Bir sahnede bir world; ikincisi genelde bir hata mesajı değil, sessiz bir çift simülasyondur.

Body tipleri: static, dynamic, kinematic

Static: zemin, duvar; simülasyon itmez, çarpışma alır. Dynamic: kuvvet ve çarpışmadan etkilenir; kutu, top. Kinematic: kodla taşınır, dinamik gövdeleri iter; kapı, platform, oyuncu kontrolcüsü (motor politikasına göre).

Yanlış tip seçimi «titreyen zemin» veya «uçan duvar» üretir. Holodepth: dekoratif mesh’i dynamic yapmayın; hareket eden görsel her zaman kinematic veya dynamic politikasını tek cümleyle mühürleyin.

Body tipi · ürün notu
Tip Hareket kaynağı Tipik kullanım
Static Yok Zemin, duvar, sabit dekor
Dynamic Motor (kuvvet / çarpışma) Top, kutu, düşen nesne
Kinematic Kod (transform ataması) Kapı, platform, oyuncu gövdesi

Mesh ↔ collider eşlemesi

Görsel mesh ile fizik şekli aynı dosya olmak zorunda değildir. Üretimde kaba box / sphere / capsule collider, ayrıntılı görsel mesh üzerinde sık kullanılır. Trimesh collider pahalı ve tuzaklıdır; Holodepth varsayılanı: oyun mantığı için basit primitive, vitrin için detay mesh.

Offset ve pivot uyumsuzluğu en yaygın köprü hatasıdır: collider merkezi mesh origin ile hizalanmadan senkron «kaymış» görünür. Kurulumda bir kez hizalayın; her kare düzeltmeyin.

Bileşik collider (ör. bir karakterin gövdesi için capsule + ayak için küçük bir sphere) genelde tek bir karmaşık trimesh'ten daha ucuz ve daha kararlıdır; Holodepth: karmaşık görsel geometriyi birden fazla basit şekle bölmeyi ilk tercih olarak düşünün.

Senkron politikası: kim kime?

Varsayılan (dynamic): fizik adımı sonrası body → mesh pozisyon ve rotasyon. Kinematic oyuncu: input → mesh veya body → world; dynamic dünya buna tepki verir. Çift yön: nadiren gerekir; çakışma ve jitter riski artar.

Holodepth: senkron yönünü dosya başında yorum satırı değil, ürün sözlüğünde yazın. «Her şeyi her kare iki yöne kopyala» anti-pattern’idir.

Senkron adımının fizik step() çağrısından sonra, render'dan önce tek bir yerde toplanması debug'ı kolaylaştırır — pozisyon ataması sahnenin farklı yerlerine dağılmışsa, «hangi kod bu mesh'i taşıdı» sorusu saatlerce sürebilir.

Senkron yönü mühürlenmezse debug sonsuza uzar.

Birimler, ölçek ve yerçekimi

Three sahnesinde 1 birim = 1 metre kabulü Holodepth önerisidir. Yerçekimi −9.81 Y ekseninde tipik web oyunu ayarıdır; Z-up veya farklı eksen projelerinde vektörü world kurulumunda tek seferde döndürün.

mesh.scale animasyonu collider’ı otomatik büyütmez. Ölçek değişimi collider yeniden oluşturma veya şekil parametresi güncellemesi ister; bunu köprü katmanında bilinçli yapın.

Birim tutarsızlığı genelde ilk fark edilen değil, en pahalı hatadır: yanlış ölçekli bir dünyada yerçekimi «çok güçlü» veya «çok zayıf» hissedilir, ama kök neden genelde metre biriminin bir yerde santimetre ile karıştırılmasıdır. Holodepth: proje başında birim sabitini bir kez yazın, tüm asset ve fizik parametrelerini ona göre üretin.

Güvenli köprü: simüle yüzey

Örnekler öğretim amaçlıdır; paket sürümünüzde init ve import yolunu doğrulayın. Kullanıcı girdisini world oluşturmada eval etmeyin; gövde kimliği sabit ürün sözlüğünden gelir.

Simüle · Rapier world + mesh senkron (yüzey şekli).

// Eğitim: sürüme göre init/import doğrulanır — API yüzeyi örnektir.
import * as THREE from 'three'
// import RAPIER from '@dimforge/rapier3d-compat' // projede doğrulayın

const pairs = []

export async function createRapierWorld() {
  // await RAPIER.init()
  const gravity = { x: 0, y: -9.81, z: 0 }
  // const world = new RAPIER.World(gravity)
  const world = { gravity, step() {} } // simüle
  return world
}

/** mesh + dynamic body eşlemesi — tek ürün kimliği */
export function spawnDynamicBox(world, scene, { id, position }) {
  const mesh = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshStandardMaterial({ color: '#5ec8ff' })
  )
  mesh.name = id
  mesh.position.copy(position)
  scene.add(mesh)

  // const bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(...)
  // const body = world.createRigidBody(bodyDesc)
  // const collider = world.createCollider(RAPIER.ColliderDesc.cuboid(0.5,0.5,0.5), body)
  const body = { id, translation() { return mesh.position }, rotation() { return mesh.quaternion } }

  pairs.push({ id, mesh, body })
  return { mesh, body }
}

/** Holodepth varsayılanı: step sonrası body → mesh */
export function syncMeshesFromBodies(pairList = pairs) {
  for (const { mesh, body } of pairList) {
    const t = body.translation()
    const r = body.rotation()
    mesh.position.set(t.x, t.y, t.z)
    mesh.quaternion.set(r.x, r.y, r.z, r.w)
  }
}

Simüle · Cannon world + zemin (yüzey şekli).

// Eğitim: cannon-es / cannon API yüzeyi — sürümde isimler değişebilir.
import * as THREE from 'three'
// import { World, Body, Box } from 'cannon-es'

export function createCannonWorld() {
  // const world = new World({ gravity: new Vec3(0, -9.82, 0) })
  const world = { bodies: [], gravity: { y: -9.82 }, step(dt) { void dt } }
  return world
}

export function addStaticFloor(world, scene) {
  const mesh = new THREE.Mesh(
    new THREE.BoxGeometry(20, 0.2, 20),
    new THREE.MeshStandardMaterial({ color: '#3a4558' })
  )
  mesh.position.y = -0.1
  scene.add(mesh)

  // const shape = new Box(new Vec3(10, 0.1, 10))
  // const body = new Body({ mass: 0, shape, position: new Vec3(0, -0.1, 0) })
  // world.addBody(body)
  const body = { mass: 0, mesh, syncFromMesh() { /* static: mesh sabit */ } }

  world.bodies.push(body)
  return { mesh, body }
}

export function stepAndSync(world, dt) {
  world.step(dt)
  for (const entry of world.bodies) {
    if (entry.mass > 0 && entry.mesh && entry.body) {
      entry.mesh.position.copy(entry.body.position)
      entry.mesh.quaternion.copy(entry.body.quaternion)
    }
  }
}

Köprü tuzakları

Bu tuzakların çoğu «fizik motoru bozuk» şikâyeti olarak gelir; kök neden genelde köprü sözleşmesinin bir yerde eksik yazılmış olmasıdır.

  1. Çift world: hot reload veya ikinci canvas sızıntısı.
  2. Scale körü: mesh büyür, collider eski kalır.
  3. Çift yön senkron: jitter ve enerji patlaması.
  4. Trimesh her yerde: performans ve sıkışma.
  5. Static dynamic karışımı: titreyen zemin.
  6. Picking ile fizik: tıklama collider üretmez.
  7. Motor içi derinlik: Holodepth yerine Hexovian’a kayma.

Üç köprü profili

Üç profil de aynı world/body/collider sözleşmesini paylaşır; ayrışan şey gövde sayısı ölçeği ve senkron yönüdür.

  • 01 · Köprü

    Vitrin fizik

    Motor
    Az gövde · Cannon veya Rapier
    Collider
    Box / sphere
    Risk
    Gereksiz trimesh
  • 02 · Köprü

    Web oyunu

    Motor
    Rapier WASM
    Senkron
    body → mesh
    Risk
    variable step (sonraki yaprak)
  • 03 · Köprü

    Kinematic oyuncu

    Girdi
    input → kinematic body
    Görsel
    mesh child veya aynı kök
    Risk
    Çift yön kopya

Holodepth perspektifleri

Kimlik tek

Mesh adı, entity id ve body handle aynı sözlükten gelmeli; debug log tek satırda okunur.

Motor seçimi ürün kararı

Benchmark ve gövde sayısı yazılmadan Rapier «moda» diye seçilmez. Ölçüm yoksa iki motor da aynı öznel «hissi» üretebilir; karar sayı ile değil izlenimle verilmiş olur.

Köprü, motor teorisi değil

Bu sayfa impulse matematiğini öğretmez; hangi mesh'in hangi collider'a bağlı olduğunu ve senkron yönünü mühürler. Motor içi derinlik Hexovian sınırındadır.

Teşhis maddeleri

  1. World tek örnek mi?
  2. Collider pivot hizalı mı?
  3. Senkron yönü mühürlü mü?
  4. Static / dynamic doğru mu?
  5. Scale collider’ı güncelliyor mu?
  6. Picking ile fizik karışmış mı?
  7. Motor içi / netcode Hexovian’a kaymış mı?

Holodepth içgörüsü

«Fizik çalışmıyor» çoğu zaman motor hatası değil; köprü sözleşmesi eksiktir. Önce world, body ve senkron yönünü okuyun; impulse matematiğine atlamayın.

Sonraki kapı: çarpışma tepkisi köprüsü

World ve mesh eşlemesi oturunca soru «temas oldu, oyun ne yapar?» olur. Sonraki sayfa Çarpışma tepkisi köprüsü olayları ve response hook’larını anlatır; tam fizik ders kitabı değildir.