Three.js · Kamera Türleri
ArrayCamera (Dizi Kamera)
ArrayCamera; Tek Ender, Çoklu Kamera Görünümü
Yarış simülasyonunda dikiz aynası, dört oyunculu bölünmüş ekran veya güvenlik odasındaki dörtlü
monitör; hepsi aynı tuvalde birden fazla bakış ister. İzleyici tek pencerede
kalır; her bölge farklı kamera konumu, FOV veya kadrajla çizilir. Bu, çevreyi küp dokusuna
yazan CubeCamera veya tek kadrajlı ana oyun kamerasından farklı bir ihtiyaçtır:
amaç aynı karede, yan yana okunabilir görünümler.
Three.js'te bunu ArrayCamera ile kurarsınız: önceden tanımlı
alt kameralar (PerspectiveCamera veya gerektiğinde
OrthographicCamera) ve her birine bağlı viewport ile ekranın
hangi dikdörtgeninin kime ait olduğunu belirlersiniz. Uygulama tarafında çoğu zaman
tek renderer.render(scene, arrayCamera) çağrısı yeterlidir; dört
ayrı döngü ve elle senkron yerine motor, aynı sahneyi bölgelere sırayla işler. Tek bakışlı
kadraj ve FOV için
PerspectiveCamera; canlı yansıma / küp haritası
için
CubeCamera.
Bu sayfa ArrayCamera'ya özeldir: split-screen mantığı, alt kamera + viewport
anatomisi, etkileşimli demo, dörtlü monitör örneği, teknik tablo ve sınırlar (iç döngü,
post-process).
View / projection dili için
Kamera giriş sayfasına
dönün.
Çoklu bakış açısı ve split-screen mantığı
ArrayCamera, ekranın belirli bölgelerini farklı alt kameralara tahsis eder.
Her alt kamera (sub-camera), yalnızca kendisine ayrılan viewport
dikdörtgeni
içinde sahneyi görür; böylece dört oyunculu bölünme, izleme monitörü veya dikiz aynası
düzeni tek sahne üzerinde birleşir.
Kullanım senaryoları; ortak ihtiyaç: aynı sahne grafiği, farklı kadrajlar;
her bölge kendi viewport ve alt kamera parametreleriyle çizilir.
-
Yarış Oyunları ve Simülasyonlar: Ana kamera ön camdan yolu gösterirken,
aynı ekranın kenarında
küçük dikdörtgen bir dikiz veya yan ayna görünümü bulunur. Kokpit içindeki radar veya
harita ekranları
genellikle Ortografik
Kamera ile üstten, yol ise
perspektif kamerayla izlenir. Mimarinin güçlü yanı; ayrı
render()döngüleri kurmak yerine, tüm bu farklı bakış açılarının tek bir çağrıda (sync) ekrana çizilmesidir. Kritik Detay: Her alt kameranınaspect(en-boy) oranı, kendi tahsis edildiği küçük bölgenin (viewport) boyutlarına göre ayarlanmalıdır. -
Çok Oyunculu Bölünmüş Ekran (Split-Screen): İki veya dört oyuncunun
aynı fiziksel dünyada
gezindiği yerel co-op (yan yana) oyun deneyimleridir. Ekran yatay, dikey veya çeyrek
dilimlere bölünür. Her
oyuncuya atanan alt kameranın pozisyonu ve rotasyonu o oyuncunun kumandasına (input)
göre güncellenir. Bu tür
projelerde 3B dünya
ArrayCameraile paylaşımlı render edilirken, can barı ve menü gibi arayüz katmanları (UI) genellikle HTML/CSS tarafında tutulur. Çevrimiçi oyunlarda bu yöntem yerine her istemcide tek bir kamera kullanılması daha standarttır. - Güvenlik ve Gözetim Sistemleri: Tek bir monitörde veya web sayfasında 4, 8 veya 16 farklı sanal güvenlik kamerasından gelen canlı yayının aynı anda izlenmesidir. Operatör, ekranı bölen ızgara (grid) yapısı sayesinde tesisin her köşesini aynı anda kontrol edebilir. Sahnedeki geometriler ortaktır, sadece alt kameraların konumları farklıdır. Üretim (Production) Notu: Alt görünümlerin sayısı arttıkça maliyet katlanacağı için, bu panellerde düşük çözünürlük veya kademeli güncelleme (throttle) teknikleri tercih edilmelidir (detaylar aşağıdaki performans uyarısındadır).
- VR Prototipleme ve Çoklu Monitör Geliştirme: Tam kapsamlı bir WebXR oturumu başlatmadan önce, tarayıcı ekranını ikiye bölerek "sol göz / sağ göz" stereo yerleşimini test etmek veya dev ekran duvarları (video wall) için asimetrik projeksiyonları simüle etmek amacıyla kullanılır. Aşağıdaki bölümlerde açıklanan çok bölgeli ve çok bakışlı (multi-viewport) sistemlerin kavramsal temeli bu kullanım senaryosuna dayanır.
Kritik nüans: tek
render() çağrısı, içeride birden çok geçiş
ArrayCamera ile yaptığınız tek
renderer.render(scene, arrayCamera) çağrısı, uygulama düzeyinde
“tek draw” anlamına gelmez. WebGLRenderer içinde her alt kamera
için sırayla viewport ayarlanır ve çizim listesi o bakış açısıyla
yeniden işlenir; yani motor tarafında internal bir döngü vardır.
Kazanç çoğunlukla API ve akış sadeleşmesi (tek çağrı, aynı kare
zamanı, daha az el yapımı senkron) ve doğru ayarlandığında daha tutarlı
pencerelemedir; “GPU yükü görünüm sayısıyla çarpılır” satırıyla da örtüşür.
Bu desen WebXR stereo mantığına da yakındır: her göz için ayrı
projeksiyon ve dikdörtgen, tek kare ömründe eşleştirilir; ArrayCamera
köken itibarıyla bu tür çok bölgeli, çok bakışlı düzenlere dayanır; VR
dışında split-screen ve izleme panelinde aynı okuma geçerlidir.
Yapısal anatomi: alt kameralar ve viewport
ArrayCamera, bir dizi PerspectiveCamera (nadiren
OrthographicCamera) nesnesini bir arada tutan bir kapsayıcı
kameradır. En kritik parça, her alt kameranın tuval üzerindeki yerini belirleyen
viewport ayarıdır.
-
Viewport (Görüş Bölgesi): Her alt kameraya atanan
viewport, render edilecek görüntünün ana tuval (canvas) üzerinde hangi piksel sınırlarına —(x, y, genişlik, yükseklik)— yerleşeceğini belirler. Bu dörtlü parametre, grafik motoruna (GPU) projeksiyonu tam olarak hangi dikdörtgenin içine sığdıracağını söyler. WebGL mimarisinde koordinat düzleminin başlangıç noktası (orijin) standart HTML/CSS alışkanlıklarının aksine sol alt köşedir (bu ayrım aşağıdaki paragrafta detaylandırılmıştır). Tarayıcı penceresi yeniden boyutlandırıldığında (resize), bu piksel tabanlı alanların mutlaka yeniden hesaplanması gerekir. Mimarideki En Kritik Kural: Görüntünün ezilmesini veya sündürülmesini engellemek için, ilgili alt kameranınaspect(en-boy) oranı kesinlikle tahsis edilen viewport'ungenişlik / yükseklikoranına eşit olmalıdır (bkz. uygulama kodu). Ayrıca, bir kameranın çizdiği piksellerin komşu panele taşmasını fiziksel olarak kesmek için genellikleviewportile birlikte makas testi (scissor test) uygulanır; bu konunun teknik ayrıntıları aşağıdaki özel not kutusunda yer almaktadır. -
Senkronizasyon (Eşzamanlı İşleme): Mimarinin en güçlü yanlarından biri,
tüm alt kameraların
tamamen aynı
Scene(Sahne) grafiğini ortaklaşa kullanmasıdır. Ekranı dörde bölmek; sahnedeki nesneleri kopyalamayı veya donanımı yoran dört ayrırender()döngüsü kurmayı gerektirmez. Sistemdeki her alt kamera bağımsız birerObject3Dnesnesidir; dolayısıyla kendi konumuna (position), dönüş açısına (rotation) ve lens ayarlarına (fov,near,farveya ortografik sınırlara) sahiptir. Oyun fiziği ve animasyonlar saniyede bir kez (her karede) güncellenir ve tüm kameralar bu "ortak zaman anını" kendi bağımsız kadrajlarından çizer. Oyuncu A ile Oyuncu B'nin aynı dünyada eşzamanlı olarak farklı noktalara bakabilmesi (split-screen) bu mimari ayrım sayesinde mümkün olur. Bu sistem, çevresel yansıma dokuları üretenCubeCamera'nın aksine, doğrudan ekrana bölünmüş görsel veri basmak için optimize edilmiştir.
Normalize tuval koordinatları (WebGL): Viewport genelde tuvale göre
0–1 arası ifade edilir; (0, 0) köşe
sol alt, (1, 1) sağ üsttür (y ekseni
yukarı doğru büyür). CSS ile üst/sol köşeden konumlandırma alışkanlığı olanlar için bu
fark önemlidir: aynı “üstteki panel” WebGL’de yüksek y değerine karşılık
gelir.
İleri: viewport ve scissor
Viewport: Projeksiyonu bu dikdörtgene sığdırır; yani “kamera görüntüsü hangi piksel alanına yayılacak?”
Scissor (makas) testi: Çizimin yazılacağı piksel alanını kırpar; çoklu alt render’da genelde viewport ile birlikte kullanılır ki bir alt görünüm komşu bölgelere taşmasın. Three.js çoklu bakış yollarında bu ikisi pratikte sık yan yana gelir.
Viewport + scissor birlikte: Viewport, NDC’den ekrana
projeksiyonun hangi dikdörtgende ölçekleneceğini söyler; scissor ise
raster aşamasında renk ve derinlik yazımını hangi piksel alt kümesine
kısıtlar. Döngülü render() yazarken ikisini çoğu zaman
aynı piksel dikdörtgeninde eşleştirmek, komşu panele taşmayı ve
“hayalet” fragment’leri kesmek için en güvenli kalıptır.
Derinlik tamponu (tek hedef): Varsayılan çerçeve tamponunda tipik olarak tek bir depth buffer paylaşılır; her alt geçiş yalnızca kendi viewport alanındaki piksellere yazar. Paneller birbirinden ayrık olduğu sürece bir panelin derinlik değeri komşunun piksellerini budamaz; bu, çoklu bakışta doğruluk için önemlidir. Aynı panel içinde üst üste binen yüzeylerde z-fighting algısı yine oluşabilir; çoklu bakış bunu tek başına çözmez.
Etkileşimli demo: tek sahne, dört bakış
Aşağıda aynı sahne ortak: zemin ızgarası, merkezde anker küp (biraz daha büyük; yüz tonları + hafif emissive, belirgin kenar), köşede eksen okları (X/Y/Z). Dört alt kamera öğretici set: Front / Right / Top / Free (Türkçe: ön · sağ · üst · serbest orbit). Ön / sağ hafif yukarı, üst tam tepe değil (ufak X/Z offset); blueprint düzü yerine 3B derinlik okunur. Renkli küre ve sahnedeki görüş çizgileri hangi alt kameranın ankere baktığını gösterir; köşe etiketinin üzerine gelince hem etiket hem çizgi hem de tuval kenarında viewport glow ile eşleşme güçlenir.
Üstteki şema, 2×2 Front / Right / Top / Free düzenini özetler (kavramsal). Alttaki canlı demo aynı mantıkla tuvali viewport’lara böler; köşe yazıları WebGL normalize düzlemde (0,0) sol alt, (1,1) sağ üst köşesine karşılık gelir.
Tek render();
ArrayCamera; her alt kamerada çizim tamponu pikseli
viewport.
Bu demo yalnızca ArrayCamera + tek render()
yolunu gösterir: aynı sahne, alt kameraların her birinde tanımlı
piksel viewport ile tek çağrıda çizilir. Üretimde
alternatif olarak her kamera için döngüde setViewport /
setScissor + ayrı render() da kullanılabilir; bu sayfa o
kalıbı teoride anlatır, arayüzde ise yalnızca ArrayCamera vardır.
Görünüm sayısı 1 / 2 / 4 olarak değiştikçe hem viewport düzeni hem de
aktif alt kamera sayısı güncellenir. GPU, kaç panel olursa olsun sahneyi her görünüm
için yeniden rasterize eder; ArrayCamera’nın pratik kazancı çoğu
projede tek çağrı ve daha sade senkronizasyon tarafındadır. İlk
yüklemede tek görünüm seçilidir; 2 veya 4 paneli radyo ile açarak
düzeni inceleyebilirsiniz.
Aynı karede çoklu bakış: Tek render() ile tüm alt
kameralar aynı zaman damgasında işlendiği için çoklu viewport
düzenleri genelde stabil ve okunaklı kalır. Hizasız küp veya ızgara
çoğu zaman aspect / projeksiyon ile viewport pikselinin uyuşmamasıdır;
doğrulama ve ince ayar için
Son karar (doğrulama
ve demo kapsamı) bölümüne bakın.
İpucu: Az sayıda viewport ve statik sahnelerde fark küçük olabilir;
ancak kamera sayısı arttıkça ArrayCamera avantajı daha belirgin hale gelir.
Özellikle dört panelde küp veya ızgara hizası “biraz kaymış” görünüyorsa önce
viewport ile aspect / projeksiyon eşleşmesine bakın
(aşağıdaki tablo, notlar ve kontrol listesi).
Bağlantı: Her köşe etiketi, aynı renkteki alt kamera küresi ve ankere giden çizgi ile eşleşir. Fareyi etiketin veya o paneldeki sahnenin üzerine getirince vurgu artar; hangi viewport’un hangi bakışa ait olduğunu bir bakışta kapatırsınız.
Üstteki etkileşimli sahne (diagram-array-camera.js, kök
data-array-camera-demo) ile aynı sayıları ön harita
tabloda topladık; aşağıdaki kod özeti demodaki anker, klip düzlemleri, alt kamera
yerleşimi ve viewportNorm → piksel dönüşümünü hatırlatır. Ara yüzde
değişenler HUD satırında; kalan satırlar dosyadaki sabitlerdir.
Tür sütunu: ekran kontrolleri ile kaynak koddaki değerleri ayırır.
| Sahne / rol | Parametre | Değer | Tür |
|---|---|---|---|
| Ortak · renderer | WebGLRenderer |
antialias: true, alpha: false,
powerPreference: "high-performance"
|
🔒 Sabit |
| Piksel oranı / renk | min(devicePixelRatio, 2) · çıkış
SRGBColorSpace (destekleniyorsa) ·
setClearColor(0x05060c)
|
🔒 Sabit | |
| Ortak · sahne | Scene.background |
0x05060c |
🔒 Sabit |
| Işıklar | AmbientLight |
0xffffff, yoğunluk 0.42 |
🔒 Sabit |
DirectionalLight |
0xffffff · 1.15; konum (4, 9, 6) |
🔒 Sabit | |
| Zemin | GridHelper |
Boyut 16, bölüm 32; renkler
0x3a4a6a / 0x1a2030; position.y =
-0.6
|
🔒 Sabit |
| Anker küp | BoxGeometry / çoklu yüz |
Kenar 1.32; merkez yaklaşık y = 0.35 ·
MeshStandardMaterial (yüz başına ton + hafif emissive)
|
🔒 Sabit |
| Çerçeve + eksen | EdgesGeometry · AxesHelper |
Kenar opaklık 0.88; eksen uzunluk 1.58 (küp ile
hizalı) |
🔒 Sabit |
| Alt kamera · ortak | PerspectiveCamera |
FOV 40°, clip 0.08 … 80 |
🔒 Sabit |
Renk kodları · COLORS |
front 0x5ec8ff · side 0xc86bff ·
top 0x7dff9a · orbit 0xff9f6e
|
🔒 Sabit | |
viewportNorm → piksel · resize /
updateAspects
|
0–1 yerleşim userData.viewportNorm; çizim tamponu
canvas.width / height ile
subCamera.viewport ve aspect = pw/ph
|
🔒 Sabit | |
Dört panel yerleşimi · normalize (x,y,w,h) |
Örn. 4 görünüm: üst sıra (0,0.5,0.5,0.5),
(0.5,0.5,0.5,0.5); alt sıra (0,0,0.5,0.5),
(0.5,0,0.5,0.5) — WebGL sol alt köşe
|
🔒 Sabit | |
Yardımcı + çizgi · küre · Line |
Küre yarıçap 0.17; çizgi opaklığı taban 0.28
(hover’da artar) |
🔒 Sabit | |
| Front / Right / Top | position + lookAt(origin) |
(0, 1.2, 4) · (4, 1.2, 0) ·
(0, 5, 0.01); origin = (0, 0.35, 0)
|
🔒 Sabit |
| Free (orbit) | dairesel yörünge | Yarıçap 6.15; açı += dt×0.058; dikey
y ≈ 1.48 + sin×0.34; lookAt(origin)
|
🔒 Sabit |
| HUD | Görünüm sayısı | ArrayCamera + tek render() · 1 /
2 / 4 panel
|
🔧 HUD |
// diagram-array-camera.js — Sayfa Demosu Sabitleri (üstteki tablo ile; özet)
const COLORS = {
front: 0x5ec8ff,
side: 0xc86bff,
top: 0x7dff9a,
orbit: 0xff9f6e,
};
const NEAR = 0.08;
const FAR = 80;
const CUBE_SIZE = 1.32;
const ORIGIN = new THREE.Vector3(0, 0.35, 0); // anker (küp merkezi)
// Alt kamera şablonu: FOV 40° — viewport pikseli resize’ta userData.viewportNorm’dan
// aspect = (norm.z * bufW) / (norm.w * bufH); updateProjectionMatrix()
// Bakış konumları (lookAt → ORIGIN)
// Front (0, 1.2, 4) · Right (4, 1.2, 0) · Top (0, 5, 0.01)
// Free: orbit yarıçap 6.15; orbitAng += dt * 0.058; y = 1.48 + sin(orbitAng * 0.38) * 0.34
// ArrayCamera: new THREE.ArrayCamera(subCameras.slice(0, viewCount));
// renderer.render(scene, arrayCamera); // 1 panel: doğrudan subCameras[0]
“Sahne yok” gibi; ne zaman endişe?
ArrayCamera yolunda yalnızca köşe yazıları görünüp 3B içerik boş
hissediliyorsa, bu çoğu zaman “sahne yok” değil; tek
render() içinde viewport / projeksiyon / bakış vektörü zinciri
tam oturmamış demektir. Aynı sahneyi hata ayıklamak için döngüde her kamera için
ayrı render() denemek de yaygındır; bu demoda yalnızca
ArrayCamera yolu gösterilir.
Kontrol listesi (üretimde de aynı):
- Viewport (r170, WebGLRenderer + ArrayCamera)
Alt kameranın
viewportdeğeri bu yolda çizim tamponu pikseli olarakgl.viewport’a iletilir; 0–1 normalize bırakırsanız pratikte birkaç piksel alanına sıkışır ve sahne “yok” görünür. Bu demoda yerleşimuserData.viewportNorm(0–1, sol alt orijin) olarak tutulur;resizesonrasısubCamera.viewport.set(nx*bufW, ny*bufH, nw*bufW, nh*bufH)ile piksele çevrilir. Çoklurender()döngüsündesetViewport/ makas ile aynı ölçeği koruyun. - Aspect + matris
Her alt görünüm için
aspect= o panelin viewport piksel eni ÷ boyu; ardındanupdateProjectionMatrix()— atlanırsa veya viewport ile uyumsuzsa küp/ızgara “kaymış” veya sıkışmış görünür. Çoklurender()döngüsünde her iterasyondasetViewport/setScissorile aynıw,hüzerinden hesaplayın. - Bakış
position+lookAt(veya eşdeğeri) sahneye kilitlenmezse “boş” veya tek renk alan hissi oluşur.
Viewport, aspect ve
(alternatif) döngüde çoklu render()
Dört görünümde bazı panellerde küpün hafif yan kaymış veya
ızgaranın tam oturmamış görünmesi çoğu zaman “kamera kötü” değil,
genişlik ÷ yükseklik ile çizim alanının uyuşmamasıdır: yani
camera.aspect güncellenmeden viewport değişmiş demektir. Bu demoda
resize sonrası her alt kamera için
aspect = viewportGenişliği / viewportYüksekliği ve
updateProjectionMatrix() uygulanır.
Çoklu render() kullanırken (genel kural): her alt görünüm
için, o pass’ten hemen önce sırayla şunların tutarlı olması gerekir:
renderer.setViewport(x, y, w, h)ve gerekiyorsarenderer.setScissor(x, y, w, h)ile aynı dikdörtgen;setScissorTest(true)komşu bölgelere taşmayı keser.camera.aspect = w / hardındancamera.updateProjectionMatrix()— atlanırsa projeksiyon yanlış en-boy oranında kalır ve sahne “kaymış” görünür.
Bu tür algı farkları eğitim ve keşif içeriğinde genelde sorun teşkil etmez; ürün veya stüdyo demosunda ise son ince ayar (tam senkron pipeline, sabit zaman adımı vb.) tercih edilebilir. Bu sayfadaki dört bakış (ön, sağ, hafif tilt üst, orbit) üretim tarafında da tutarlı, okunaklı bir set olarak düşünülebilir.
Son karar: doğrulama, ince hizalama ve demo kapsamı
Kalan fark ne? Viewport / aspect düzeltmelerinden sonra
görüntü belirgin şekilde daha stabil; bariz bir hata kalmaması
beklenir. Motor ve sürüme göre viewport piksel yuvarlaması veya
kayan nokta hassasiyeti kaynaklı çok ince farklar görülebilir; bu
tür durumlar çoğu eğitim demosunda pratik sorun teşkil etmez. Bu bir
bug değildir; “piksel mükemmel” hizalama gerekiyorsa ek doğrulama ve
sabit çözünürlük senaryoları düşünülür.
Sistem doğru mu? Pratik doğrulama: 1 görünümde tek panel tutarlı; 2 görünümde düzen simetrik; 4 görünümde her bakış doğru eksen / açıdan okunuyorsa, kamera dönüşümü + projeksiyon hattı tutarlı demektir. Ön bakış net ve ankere kilitli; sağ eksen okunabilir; üst tam düz değil, hafif tilt; derinlik için doğru tercih; serbest orbit dinamik bakış hissi verir. Bu set salt “tutorial” değil; ürün / eğitim içeriğinde rahatlıkla kullanılabilecek düzeyde okunaklıdır.
Ek model gerekir mi? Hayır; bu demodaki amaç zengin sahne göstermek değil, viewport + ArrayCamera render hattını okunaklı göstermektir. Fazla obje dikkati dağıtır; mevcut sade küp + ızgara + eksen bu hedef için uygun seçimdir.
İsteğe bağlı “bir üst seviye” dokunuşlar (hiçbiri zorunlu değildir): aktif viewport’ta hafif vurgu, hover’da kamera → küp çizgisinin güçlenmesi, köşe etiketlerinde kısa giriş animasyonu. Canlı demoda fareyle panel / sahne üzerinde glow ve çizgi opaklığı zaten güncellenir; ekstra animasyon tamamen tercihe bağlıdır.
Uygulama: dörtlü bölünme kurulumu
Aşağıdaki örnek, ekranı dört eşit panele böler; her alt kamera farklı bir konumdan sahneye
bakar. Üretimde pencere oranı değişince her alt kameranın aspect ve
viewport değerlerini güncellemeyi unutmayın. Canlı demodaki
(diagram-array-camera.js)
yerleşim ve hata ayıklama notları için bölüm 3’teki kontrol listesine bakın.
// diagram-array-camera.js ile aynı fikir:
// — yerleşimi 0–1 (sol alt) userData.viewportNorm’da tut
// — ArrayCamera yolunda subCamera.viewport = çizim tamponu pikseli + aspect = pw/ph
const subCameras = [];
const origin = new THREE.Vector3(0, 0.35, 0); // anker (demodaki küp merkezi)
const layoutsNorm = [
new THREE.Vector4(0, 0.5, 0.5, 0.5),
new THREE.Vector4(0.5, 0.5, 0.5, 0.5),
new THREE.Vector4(0, 0, 0.5, 0.5),
new THREE.Vector4(0.5, 0, 0.5, 0.5),
];
const positions = [
new THREE.Vector3(0, 1.2, 4),
new THREE.Vector3(4, 1.2, 0),
new THREE.Vector3(0, 5, 0.01),
new THREE.Vector3(3.5, 1.5, 3.5), // Free: demoda orbit; burada örnek sabit bakış
];
function applyViewportPixels(subCamera, norm, bufW, bufH) {
subCamera.userData.viewportNorm = norm.clone();
const pw = norm.z * bufW;
const ph = norm.w * bufH;
subCamera.aspect = pw / Math.max(1, ph);
subCamera.updateProjectionMatrix();
subCamera.viewport.set(norm.x * bufW, norm.y * bufH, pw, ph);
}
for (let i = 0; i < 4; i++) {
const subCamera = new THREE.PerspectiveCamera(40, 1, 0.08, 80);
subCamera.position.copy(positions[i]);
subCamera.lookAt(origin);
const canvas = renderer.domElement;
applyViewportPixels(subCamera, layoutsNorm[i], canvas.width, canvas.height);
subCameras.push(subCamera);
}
// Her resize / setSize sonrası: layoutsNorm[i] ile applyViewportPixels(...) tekrar
// 2. ArrayCamera
const camera = new THREE.ArrayCamera(subCameras);
// 3. Render döngüsünde tek çağrı
renderer.render(scene, camera);
Teknik tablo: ArrayCamera avantajları
| Özellik | Geleneksel çoklu render | ArrayCamera yaklaşımı |
|---|---|---|
| GPU / çağrı düzeni | Her görünüm için ayrı render döngüsü veya manuel viewport yönetimi | Tek render() içinde çoklu görünüm; viewport atamaları
çerçevelenmiş akış |
| CPU / JS gecikmesi | Döngüde birden çok .render() — senkronizasyon zorlaşabilir |
Tek çağrı; tüm alt görünümler aynı kare zamanında planlanır |
| Senkronizasyon | Kareler arasında mikro kaymalar olabilir | Aynı sahne anı; bakışlar tutarlı güncellenir |
| Kod karmaşıklığı | Manuel viewport, makaslama ve temizleme sırası | Alt kameralara viewport bağlama; ArrayCamera ile toplu kullanım
|
| GPU yükü (netleştirme) | Her alt görünüm için geometri ve piksel işi yapılır — yani sahne karmaşıklığı görünüm sayısıyla çarpılır. Kazanç, çoğunlukla tek render pipeline / tek çağrı düzeni ve daha iyi senkronizasyondadır; “bedava dört kamera” değildir. | |
Post-processing ve tam ekran geçişler
Hazır post zincirleri (ör. bloom, SSAO, TAA, tonemap) çoğu zaman tek tam ekran
dikdörtgeni ve tek kamera projeksiyonu üzerinden tasarlanır.
ArrayCamera ile birlikte kullanmak, bu geçişleri her alt görünüm için
ayrı hedef / ayrı rect düşünmeyi gerektirir; aksi halde efekt yanlış
bölgeye uygulanır veya birleştirme (kompozit) adımı eksik kalır. Yoğun post için çoklu
bakışı genelde ikinci bir tampon, düşük çözünürlüklü ortak geçiş veya son kompozitör
katmanıyla planlamak gerekir; bu yüzden bölüm 6’daki “post-processing zorlaşır”
uyarısı pratikte “pipeline’ı baştan bölersiniz” anlamına gelir.
Döngülü render() ve clear / autoClear
Bu sayfadaki canlı demo yalnızca ArrayCamera yolunu gösterir; üretimde ise
klasik desen olarak her bakış için setViewport ve çoğu zaman
setScissorTest(true) ile döngüde birden fazla render()
yazılabilir. Bu kalıpta hangi adımda renk veya derinlik temizlediğiniz
doğrudan sonucu belirler: örneğin kare başında bir kez tam ekran
clear, sonraki panellerde yalnızca clearDepth; veya ara
geçişlerde autoClear’i kapatıp yalnızca ihtiyaç duyulan bölgeleri
temizlemek. Sıra, makas ve viewport hizası; bir panelde “sahne yok” veya garip üst üste
binme hissinin sık nedenlerindendir.
Sınırlar, ne zaman kullanılmaz ve dikkat
ArrayCamera kullanışlıdır; yine de sınırları vardır. Aşağıdaki üç başlık,
bölüm 2 anatomisi ve bölüm 1’deki iç döngü uyarısıyla birlikte okunmalıdır; çoğu üretim
hatası burada toplanır.
- Homojen türler: Split-screen ve gözetimde dizinin tamamı
PerspectiveCameraolması en sorunsuz yoldur: aynı projeksiyon güncelleme kalıbı (aspect,updateProjectionMatrix()) her panele uygulanır. Bölüm 1’deki gibi ana bakış perspektif, küçük panel ortografik (harita / dikiz düzlemi) karışımı mümkündür; o zaman her alt kamera türüne göre ayrı parametre seti ve test gerekir — motor “hepsi aynı sınıf” varsayımıyla daha az sürpriz verir.CubeCameraveya render hedefi üreten kameraları bu diziye karıştırmayın; amaç ekrana bölünmüş bakıştır. - Dinamik boyutlandırma: Pencere
resizeolduğunda yalnızca ana kameranınaspect’ini güncellemek yetmez: her alt kameranınviewportpiksel dikdörtgeni (veya normalize yerleşimden türetilmiş hali) veaspect = panelGenişliği / panelYüksekliğideğeri döngüyle yeniden yazılmalı, ardındanupdateProjectionMatrix().renderer.setSizeile tuval boyutu senkron kalmazsa paneller kayar veya ezilir — demodaki 1 / 2 / 4 görünüm düzeni de aynı hesabı tetikler. Tam kalıp dörtlü kurulum örneğinde; “sahne yok” hissi çoğu zaman viewport / aspect uyumsuzluğudur (bölüm 3 kontrol listesi). - Gölge ve ışık: Işıklar ve gölge haritaları sahne için ortaktır — dört ayrı sahne ışığı kurmazsınız. Buna rağmen her alt geçişte geometri ve gölgelenebilir malzemeler yeniden çizilir; dört panel kabaca dört kez geometri maliyeti demektir (iç döngü). Gölge haritası çözünürlüğü ve ışık sayısı tek bakışa göre aynı kalsa bile toplam kare süresi artar; mobilde küçük panellerde gölgeyi kapatmak veya alt kamera sayısını düşürmek yaygındır. Profil çıkarırken 1 panel ile 4 paneli aynı sahnede karşılaştırın — API sadeleşmesi GPU’yu otomatik ucuzlatmaz.
Ne zaman (genelde) tercih etmeyin? Çoklu bakış ürün gereksinimi değilse basit yol daha az hata ve daha düşük maliyet bırakır; aşağıdakiler tipik “geri dön” işaretleridir.
- Tek bakış yeterliyse: Tek oyunculu gezinti, ürün turu veya sinematik
kamera yalnızca bir kadraj ister —
PerspectiveCamerave tekrender()yeterlidir. Çevrim içi çok oyuncuda her istemci zaten kendi ekranını çizer; sunucu tarafında dörtlü split nadirdir.ArrayCameraekler: viewport döngüsü, resize senkronu, panel başına aspect testi ve “boş köşe” hata ayıklama — ihtiyaç yoksa bu yükü almayın. - Mobil ve düşük güç: Dört çeyrek ekran telefonda okunaksızdır; parmak ve UI üst üste biner. İç döngü nedeniyle GPU maliyeti panel sayısıyla ölçeklenir; gölge ve yüksek çözünürlük küçük panellerde daha da acıtır (yukarıdaki ışık maddesi). Kalite menüsünde split-screen’i kapatmak, en fazla 2 panel veya düşük görünüm sayısı (demo 1 / 2 / 4) yaygın çözümdür — masaüstü monitör hedefliyorsanız planlayın.
- Yoğun post-processing zinciri:
EffectComposerve bloom, SSAO, renk düzeltme gibi geçişler çoğu zaman tam tuval varsayar.ArrayCameraile ham sahne bölgelere bölünür; efekt zinciri otomatik uyum sağlamaz. Seçenekler: her panel için ayrı render hedefi (RT) + kompozit, önce tüm panelleri ortak bir tampona birleştirip sonra tek fullscreen pass, veya post-process’i yalnızca ana panele uygulayıp küçük panelleri ham bırakmak. Sayfa girişinde de belirtildiği gibi bu sınır, split-screen kararında erken düşünülmelidir — sonradan eklemek mimari maliyetlidir.
Holodepth notu: neden viewport?
Varsayılan olarak renderer tüm tuvali boyar. ArrayCamera kullanırken her
alt kameraya bir çizim alanı (viewport) vermezseniz, görünümler
üst üste binebilir veya yalnızca son ayar öne çıkabilir. Viewport, GPU’ya şunu söyler:
“Bu kameranın çıktısını tuvale yalnızca şu koordinatlar arasına yaz.”; split-screen
ve çoklu monitör düzeninin teknik karşılığı budur.
Pratik hata ayıklama için bölüm 3’teki “Sahne yok” kontrol listesine bakın; özellikle
normalize mi piksel mi ve aspect güncellemesi çoğu “boş panel” vakasını
çözer.