holodepth

Three.js · Etkileşim · Raycaster · Geometri

Işın (ray) temeli: geometrik çerçeve

Web sahnesinde seçim, etiket okuma veya basit engel testi dediğinizde motorların altında çoğu zaman aynı matematiksel obje yatar: uzayda tek yönlü bir ışın (ray). Köken (origin) ve yön (direction) ile tanımlanır; skaler t parametresi ise «ne kadar ileri gittik?» ve dolayısıyla çarpışma mesafesi sorusunun ortak cevabıdır. Bu sayfa, bu dili önce soyutlar, sonra Three.js Raycaster gibi somut tüketicilere köprü kuracak şekilde ray tracing ile karışmayacak biçimde ayırır.

Okuma yolu bilinçli olarak konseptten uygulamaya doğrudur: ışının ne olduğu (1), P(t) = O + tD ile t’nin yorumu (2), köken–yön–kesişim bileşenleri (3), çarpışmadan dönen vuruş verisi (4) ve nihayet raycaster ile ray tracing ayrımı (5). Böylece aşağıdaki bölümler birbirini tekrarlamak yerine aynı hikâyenin katmanları olur.

Three.js tarafında Raycaster, kamera veya fare / dokunma gibi girdilerden türetilen ışını sahne grafiğine karşı yürütür; bu sayfada amaç API rehberi yazmak değil, neden normalize yön, neden epsilon ve neden «ilk vuruş» kavramının her yerde tekrar ettiğini göstermektir. Bu zemin oturduktan sonra, pratik seçim akışları ve sahne ölçeğinde optimizasyon ayrı metinlerde derinleştirilebilir.

Işının geometrik ontolojisi

«Ontoloji» burada felsefi bir iddia değil, pratik bir sorudur: hesap makinesine verdiğimiz şey tam olarak nedir? Bir raycaster bağlamında ışın (ray), uzayda yönlü tek boyutlu bir prob olarak ele alınır: köken (origin) adını verdiğimiz bir başlangıç noktası ve yön (direction) adını verdiğimiz bir yönelimle, «bu doğrultuda ileri tarafa bakıyorum» demenin matematiksel özüdür. Çarpışma, gölge testi veya seçim fark etmez; altında dönen çoğu rutin, bu iki veriyi aynı imza ile tüketir.

Bu yüzden ışın, sonsuz uzayı iki yöne de uzayan doğru ile karıştırılmamalıdır: doğru simetriktir; ışında ise öncelik vardır — hangi yarı uzayın «tarafım» sayılacağı, yön vektörüyle seçilir. Benzer şekilde ışın, başlangıç ve bitişle sınırlı bir segment de değildir; segmentte uzunluk sabittir, oysa ışında ileri yön başlangıçta açık uçlu kalır ve gerektiğinde yalnızca maksimum t gibi ek kısıtlarla pratikte kısaltılır (örneğin kamera yakın düzlemi veya sahne kutusu).

Zaman veya fizik modeliniz gerektiriyorsa aynı iskelet, uzay–zaman içinde ek koordinatlarla zenginleştirilebilir; fakat bu sayfanın omurgası klasik üç boyutlu Öklid uzayıdır — yani önce dünya/nesne uzayında tutarlı bir yarı doğru kurarsınız, sonra motorunuzun kalan katmanlarına devredersiniz.

Pedagojik olarak geçmiş–gelecek imgeleri işe yarar: köken, ışının doğduğu yer; yön ise ileri tarafa açılan yarı doğrunun pusulasıdır. t parametresi bu hikâyeyi sayıya çevirir; işaretli aralıkların tam yorumu ve seçim kuralları bir sonraki bölümde (Parametrik doğru: t’nin anlamı) ayrıntılandırılır — burada yalnızca şunu sabitleyin: ışın, yönlü bir yarı doğrudur; çarpışma soruları da bu yönlülük üzerinden tutarlı cevaplanır.

Parametrik doğru: t’nin anlamı

Işının üzerindeki noktalar şu yapı ile yazılır; burada O köken, D yön vektörü, t skaler parametredir:

P(t) = O + t · D

Micro demo: t parametresi değiştikçe P(t) noktası ışın üzerinde ilerler. t < 0: geri yarı doğru · t = 0: köken · t > 0: ileri yarı doğru.

t

P(t)

First hit = smallest positive t

İpucu: t’yi 0’ın altına çekip «geçmiş»e geçin; sonra 0’a geri getirin. Bu, «ilk pozitif t» kuralının neden doğal olduğunu sezdirir.

Bu denklemde t, ışını tek boyutlu bir koordinat gibi düşündüren skalerdir: O’dan başlayıp D doğrultusunda ilerlersiniz; t arttıkça uzaklaşırsınız. D birim uzunluktaysa t doğrudan öklid mesafesine denk gelir; değilse t yalnızca affin bir ölçek olur — yine de hangi yüzeyin «önde» olduğunu sıralamak için aynı ışın üzerinde tutarlı karşılaştırma yapılabilir (yön sabit kaldığı sürece).

Pratikte t, ışının yaşam çizgisi üzerindeki konumu ve aynı zamanda «bu vuruş, kökene göre nerede?» sorusunun yanıtıdır. Aralıklar şöyle yorumlanır:

  • t < 0 — geriye dönük yarı doğru: Geometrik olarak nokta, hâlâ O’nun ters yarı doğrusundadır; yani siz «ileri» baktığınız hâlde, kesişim ışının arkasında kalmıştır. Etkileşim ve seçim (picking) senaryolarında bunlar genelde elenecek adaylardır: kullanıcı ekranda gördüğü «ön» yüzey, pozitif t ile temsil edilir. Benzer şekilde, bir yüzeyden yansıyan veya gölge için yeniden fırlatılan ışınlarda, yanlışlıkla kaynak yüzeyin iç tarafını veya geçmişi saymak istemezsiniz; bu yüzden t < 0 (ve çok küçük pozitif t) eşikleri birlikte kullanılır.
  • t = 0 — kökenle çakışan vuruş: Matematiksel olarak tam O noktasıdır; «ışın henüz yola çıkmadan» bir yüzeyle örtüşüyor musunuz sorusuna denk gelir. Sayısal tarafta bu sınır, öz-çarpışma veya yüzeyle çakışan köken gibi durumlarda gürültü yaratabilir; bu yüzden üretim kodunda çoğu zaman minimum mesafe (epsilon) ile «t şu kadar küçükse sayma» kuralı eklenir — bir sonraki bölümde köken kaydırmasıyla birlikte düşünülür.
  • 0 < t < ∞ — ileri yarı doğru: Burası sahnenin fiilen tarandığı bölgedir: geometri, ışının gidebileceği yörünge üzerinde ardışık adaylar üretir; siz de bunlar arasından problem türüne göre birini seçersiniz. Görünür yüzey için tipik seçim, en küçük pozitif anlamlı t değeridir — kameraya en yakın engel. Birden fazla yüzey kesişiyorsa, hepsi pozitif t ile sıralanır; arkasındaki yüzey daha büyük t taşır. Özel durumlarda (örneğin şeffaf katmanlar, özel mantık) farklı bir t seçilebilir; fakat temel raycaster zihinsel modeli: «önce ön yüzey, t sırasıyla belirlenir».

Bileşenler: köken, yön, kesişim

A. Köken: perspektif, ortografik ve epsilon

Işının başlangıcı yalnızca bir koordinat değil; gözlemcinin bakış modeli ile bağlantılıdır. Perspektif kamerada ışınlar çoğu zaman tek bir odak çevresinden dağılır; ortografik projeksiyonda ise ışınların kökenleri bir düzlem üzerinde örneklenir ve birbirine paralel kalırlar.

Işın bir yüzeyden «sekme» veya gölge ışını gibi yeni bir ışın üretmek için yeniden fırlatılıyorsa, köken yüzeyin çok az dışına itilmelidir (örneğin 1e-4 birim gibi küçük bir epsilon). Aksi halde ışın tekrar aynı yüzeyi vurarak sayısal salınım veya shadow acne denilen tırtıklı gölgelenme hatalarına yol açabilir.

B. Yön ve normalizasyon

Yön vektörü, ışının rotasını belirler. Normalize etmek — uzunluğu 1 yapmak — t’yi çoğu testte doğrudan mesafe ölçeğine oturtur (Three.js Raycaster da yönü normalize eder). Karekök içerdiği için maliyetlidir; fakat binlerce ışında tutarlı kesişim ve karşılaştırma için pratikte sıkça tercih edilir.

C. Kesişim matematiği

Kesişim sorusu, bir önceki bölümde kurduğumuz çerçeveyi doğrudan kullanır: geometri, belirli t değerlerinde «ışın üzerindeki nokta, bu şeklin içinde mi, sınırında mı?» sorusuna indirgenir. Primitifler için yanıt çoğu zaman kapalı form (tek adımda çözülebilen denklem) veya iyi bilinen bir özel algoritma ile bulunur; karmaşık mesh’lerde ise önce kaba bir aday kümesi (örneğin hacim hiyerarşisi), sonra üçgen başına ince test gibi iki aşamalı düzenler devreye girer — burada özü, temel yapı taşlarıdır.

  • Küre (analitik çift kök): Küre, merkez C ve yarıçap R ile «P(t) ile C arasındaki uzaklığın karesi, R²’ye eşit» koşuluyla tanımlanır (yaygın gösterim: ‖P(t) − C‖² = R²). P(t) = O + tD yerine konunca bilinmeyen yalnızca t kalır; uzunluk karesini açınca ifade ikinci dereceden bir denkleme döner: at² + bt + c = 0. Diskriminantın işareti, ışının küreyi hiç kesmemesini, teğet geçmesini veya giriş–çıkış kökleriyle kürenin içinden geçişi ayırır. İki pozitif kök varsa biri küreye «yaklaşma», diğeri «ayrılma» anına karşılık gelir; hangi t’nin seçileceği, önceki bölümdeki en küçük anlamlı pozitif kuralıyla uyumludur.
  • Üçgen (düzlem + sınır): Üçgenle kesişim, zihinsel olarak iki adımdır: önce ışının üçgenin düzlemiyle kesişip kesişmediği ve düzlem paraleliyse sonsuz uzaklıkta kaldığı durumlar elenir; sonra kesişim noktasının kenarların oluşturduğu kapalı bölge içinde kalıp kalmadığı doğrulanır. Möller–Trumbore algoritması bu ikisini, mümkün olduğunca az işlemle birleştirir; çoğu uygulamada barysentrik koordinatlar ara adım olarak zaten üretilir — böylece bir sonraki bölümde anlattığımız doku ve normal verisi için zemin hazırlanmış olur. Three.js tarafında benzer fikir, Ray ile BufferGeometry örgüsü üzerinde yürütülür; motor, sahne grafiğini dolaşarak aday üçgenlere bu tür testleri uygular.

Özetle: küre örneği, «ışın + basit implicit» modelinin kuadratik yüzeyini; üçgen örneği ise GPU dostu parçalı düzlemsel dünyanın omurgasını gösterir. İkisi de aynı t dilini paylaştığı için, farklı geometriler arasında tutarlı sıralama ve seçim mümkündür.

Vuruş verisi: ışın ne raporlar?

Işın yalnızca «bir şeye çarptım» demez; çarpışma rutini, seçilen t ile birlikte vuruş kaydı (hit record) üretir. Bu kayıt, dünya uzayındaki konum (çoğu zaman O + t D ile türetilir), hangi geometri / örnek olduğu ve aşağıdaki türetilmiş alanları bir arada taşır. Bir sonraki bölümde göreceğiniz gibi, etkileşim odaklı raycaster yollarında bu paketin yalnızca bir alt kümesi de yeterli olabilir; yine de tam resim, aynı ışın dilinin nereye genişlediğini gösterir.

  • Barysentrik koordinatlar (u, v, w): Vuruş üçgen yüzeyindeyse, nokta köşelere göre benzersiz bir karışım olarak yazılır (u + v + w = 1). Bu sayısal üçlü, «üçgenin tam neresine» indiğinizi kodlar; köşe başına tanımlı öznitelikler — örneğin UV, renk, teğet — aynı ağırlıklarla birleştirilerek düzlem üzerinde sürekli bir alan elde edilir. Doku örneklemesi buraya bağlanır: UV’yi doğru yerden okumak, yalnızca dünya konumunu bilmekten ötedir; barysentrikler, Möller–Trumbore benzeri yollarla zaten elde edilmiş olabilir.
  • Yüzey normali (N): Çarpışma noktasında yüzeye dik yönelen vektördür (geometrik normal); gölgelendirme tarafında bazen gölgelendirme normali (shading normal, normal haritası vb.) ile zenginleştirilir. Klasik dağılım teriminde açı, ışın veya ışık yönü ile N arasındaki ilişkiye bağlanır; parlama (specular) ise genelde yansıma yarı vektörü gibi N’ye bağlı ikincil yönlerle incelir. Çift taraflı yüzeylerde veya ölçek işaretinde normalin yönünün (front face / back face) tutarlı seçilmesi, ışığın «içeriden mi dışarıdan mı» geldiği hissini doğrudan etkiler.
  • Materyal / yüzey özellikleri: Aynı geometri üzerinde bile farklı yüzey başına veya parça başına (submesh, material slot) davranış olabilir: metalik–dielektrik ayrımı, pürüzlülük, şeffaflık veya Three.js dünyasında MeshStandardMaterial gibi bir örnekte toplanan parametreler. Tam ray tracing hattında bu alan, bir sonraki sekmede hangi BRDF örneklemesinin yapılacağını; etkileşim hattında ise «bu nesne seçilebilir mi?», «hangi layer?» gibi motor kararlarına girdi olur — yani vuruş verisi yalnızca görüntü için değil, oyun mantığı ve UI için de taşınır.

Kısa köprü: mesafe (t) ve nesne kimliği çoğu seçim senaryosunun omurgasıdır; barysentrikler, normal ve materyal ise aynı omurgayı görsel ve davranışsal sonuçlara bağlayan uzantılardır. Hepsi, bir önceki bölümde kurduğumuz t parametresiyle uyumlu tek bir hikâyedir.

Raycaster ve ray tracing

İkisi de aynı geometrik objeyi — bu sayfada tanımladığımız ışını — paylaşır; ayrım, işin nerede bittiği ve bütçenin ne için harcandığı üzerindedir. Birinde soru çoğu zaman «şu anda ekranda veya sahnede ilk ve anlamlı vuruş nedir?» iken, diğerinde «bu vuruştan sonra ışık nerelere sızar?» sorusu zincirlenir. Aşağıdaki maddeleme, mühendislik sözleşmesini ayırt etmek içindir; biri diğerinin «düşük kaliteli» versiyonu değildir.

  • Raycaster (etkileşim / seçim / birincil sorgu): Tipik kullanım, fare veya dokunma ile ekran–dünya eşlemesi yapıp tek bir ışınla (nadiren birkaç ışınla) en öndeki nesneyi bulmaktır. Önceki bölümde anlattığımız tam vuruş paketi üretilebilir; fakat birçok uygulamada yürütme ilk pozitif t ve kimlik ile sonlanır — çünkü amaç seçim, etiket okuma veya basit engel testidir. Eski 2.5D veya ızgara tabanlı motorlarda da benzer tek atımlık prob düşünülür: ışın «bir kez sorulur», cevap alınır, döngü kapanır. GPU tarafında aynı «kim önde?» sorusu rasterleştirme ile başka yoldan çözülür; raycaster ise aynı soruyu doğrudan geometri üzerinde sorma imkânı verir.
  • Ray tracing (ışın takibi / çoğaltıcı hat): İlk vuruş başlangıç kabul edilir: yansıma için yeni bir ışın, gölge için ışığa doğru bir test ışını, kırılma için ikinci ortamda ilerleyen yeni bir hat veya Monte Carlo ile çok örnekleme — hepsi ardışık nesiller (path depth) oluşturur. Böylece yansımalı zeminler, kırılan cam, yumuşak gölgeler veya genel aydınlatma (GI) gibi etkiler, tek bir «ilk t» ötesine taşınır. Üretimde sık görülen düzen, karma hatlardır: ana görüntü raster, yansıma veya ambient occlusion gibi birkaç geçiş RT ile tamamlanır. Terim kargaşasına dikkat: arayüz kodunda «raycast» denilen şey çoğu zaman buradaki raycaster sözleşmesidir; path tracing ile karıştırmamak gerekir.

Özet: raycaster, aynı ışın dilini kısa ve hedefli sorgular için kullanır; ray tracing ise dilin çoğaltılmasıyla görüntüyü veya fiziksel dağılımı zenginleştirir. Hangisinin «doğru» olduğu değil, hangi soruya cevap verdiğiniz belirleyicidir.

Özet: döngünün özü

Bir raycaster düzenekleri, kabaca şu soruyu yüksek frekansta tekrar eder: «O noktasından D yönüne bir prob gönder; bir yüzeye çarparsan (t), neye çarptığını ve o noktanın özelliklerini bildir.» Bu zihinsel model, derinlik haritalarından seçim (picking) akışlarına kadar pek çok aracın temelidir.

Holodepth notu

Bu metin teknik derinliği özetler; diyagramlar ve etkileşimli örneklerle desteklendiğinde tam bir rehber hâline gelir. Bir sonraki adım olarak ızgara tabanlı raycasting veya Digital Differential Analyzer (DDA) gibi algoritmalarla, ışınların harita üzerinde nasıl hızlı yürütüldüğü ayrı sayfalarda işlenebilir.