Three.js · Sahne
Sahne (Scene): Three.js evreninin temeli
Three.js ile çalışırken ilk kurduğunuz yapı çoğu zaman
THREE.Scene olur: mesh, ışık, grup ve yardımcı nesneler bu kökte
toplanır. Sahne ekrana piksel basmaz; evrende neyin var olduğunu,
nesnelerin üst–alt ilişkisini ve ortak transform kurallarını tanımlar; yani
projenizin içerik ve düzen katmanıdır.
Holodepth üçlüsünde roller birbirini tamamlar: sahne yapıyı tutar, kamera hangi kesitin ekrana yansıyacağını seçer, renderer bu kesiti GPU ile çizer. Kamera ve renderer'ın ayrıntıları kamera ve renderer sayfalarında; bu metinde üçlünün sahne ayağını okuyorsunuz.
Aşağıdaki tablo üçlüyü tek bakışta özetler. Sonrasında scene graph,
Object3D, eksenler, scene.traverse(), ortam özellikleri
(background, fog, environment) ve sahne +
kamera + renderer'ı birleştiren minimal kurulum örneğine geçilir; kamera
matrisleri veya WebGL hattının içi burada tekrar anlatılmaz.
Sahne, Kamera ve Renderer (Kavramsal Hatırlatıcı)
| Bileşen | Teknik Karşılık | Ana Sorumluluk ve İşleyiş |
|---|---|---|
| Sahne (Scene) | THREE.Scene |
Tüm 3D nesneleri (mesh), ışık kaynaklarını ve çevresel efektleri (arka plan rengi, sis) barındıran merkezi veri ağacıdır (Scene Graph). Sisteme eklenen her öğenin konumunu ve birbirleriyle olan hiyerarşik ilişkisini bellekte tutar. |
| Kamera (Camera) | THREE.PerspectiveCamera |
Sonsuz koordinat sistemindeki nesnelerin, kullanıcının ekranına hangi açı, mesafe ve görüş alanıyla (FOV) yansıtılacağını belirler. 3D uzayı matematiksel bir perspektifle 2D düzleme (ekrana) kusursuzca iz düşüren projeksiyon aracıdır. |
| Renderer (İşleyici) | THREE.WebGLRenderer |
Sahnedeki veri hiyerarşisini ve kameranın bakış açısını referans alarak kaputun
altındaki ağır çizim
işlemlerini yürütür. GPU (grafik işlemci) gücünü kullanarak vektörel verileri
piksellere dönüştürür
ve nihai görüntüyü HTML <canvas> elementine basar.
|
Sahne: Evrenin Konteyneri ve Veri Ağacı
Sahne (Scene) Nedir?
Three.js mimarisinde sahne, uzay boşluğunu temsil eden basit bir kap değil, uygulamanızın
veri yönetim
ve organizasyon merkezidir. Teknik olarak bir THREE.Scene nesnesi;
içine eklediğiniz
tüm 3D modelleri (mesh), ışık kaynaklarını, yardımcı çizgileri (helpers) ve mantıksal
grupları bellek üzerinde
devasa bir liste halinde tutar. Arka plan renginden (background) sisteme dahil olan küresel
sise (fog) kadar tüm
çevresel etmenler bu merkezden yönetilir.
Scene Graph: Matematiksel Hiyerarşi
Sahneye eklenen nesneler düz bir liste (array) olarak değil, ebeveyn-çocuk (parent-child) ilişkisine dayanan bir ağaç yapısı, yani Scene Graph olarak organize edilir. Bu yapı, karmaşık 3D animasyonların ve modüler tasarımın temelini oluşturur.
- Göreceli Koordinatlar: Bir
Groupoluşturup içine araba parçalarını (tekerlekler, gövde) çocuk (child) olarak eklerseniz, ana grubu 10 birim ileri taşıdığınızda tüm parçalar kendi aralarındaki mesafeleri koruyarak grupla birlikte hareket eder. - Matris Çarpımı: Render motoru sahneyi çizerken en üstten (kök) başlar ve aşağı doğru inerek her ebeveynin dönüşüm matrisini çocuklarına uygular. Dünyayı (parent) döndürdüğünüzde, içindeki ağaçlar (child) doğal olarak dünya ile birlikte döner.
Object3D ve Ortak Transform Sistemi
Three.js'in temel mimari felsefesinde, uzayda var olan her şey aynı soydan gelir.
Scene nesnesinin
kendisi de dahil olmak üzere, sahneye eklenen kameralar, ışıklar ve geometriler
Object3D ana sınıfından türetilir
(inheritance).
Bu soy ağacı sayesinde, sahne üzerindeki her nesne standart ve evrensel bir kontrol mekanizması olan Transform Arayüzünü paylaşır:
.position(Vektör tabanlı x, y, z koordinat yerleşimi).rotation(Euler açıları ile nesne ekseninde dönme).scale(Orantılı veya eksen bağımsız boyutlandırma)
Kartezyen Uzay ve "Sağ El Kuralı" (Right-Hand Rule)
Three.js evreni, başlangıç noktası (0, 0, 0) origin olan ve sonsuzluğa uzanan üç temel matematiksel vektör (eksen) üzerine inşa edilmiştir. 3D uzayda nesneleri konumlandırırken yönünüzü kaybetmemek için bilgisayar grafiklerinin evrensel standardı olan Sağ El Kuralı'nı (Right-Hand Coordinate System) kullanmalısınız:
- X Ekseni (Yatay Düzlem): Sağ elinizin başparmağını sağa doğru uzatın. Pozitif (+) değerler nesneyi sağa, negatif (-) değerler ise sola hareket ettirir. Geliştirici araçlarında standart olarak Kırmızı Eksen ile temsil edilir.
- Y Ekseni (Dikey Düzlem): İşaret parmağınızı doğrudan gökyüzüne doğrultun. Pozitif (+) değerler nesneyi yukarıya, negatif (-) değerler aşağıya (yerçekimi yönüne) hareket ettirir. Standart olarak Yeşil Eksen ile temsil edilir.
- Z Ekseni (Derinlik Düzlemi): Orta parmağınızı kendinize (ekrandan dışarıya) doğru bükün. Pozitif Z değerleri nesneyi kameraya yaklaştırırken, negatif Z değerleri nesneyi ekranın içine doğru iterek uzaklaştırır. Standart olarak Mavi Eksen ile temsil edilir.
Kritik İpucu: Projeye ilk başladığınızda kamera ve eklendiğiniz obje (örneğin bir küp) varsayılan olarak tam merkeze (0,0,0) yerleşir. Kamera nesnenin içinden baktığı için ekran simsiyah kalır. Bu yüzden ilk adım daima kamerayı Z ekseninde (örn: camera.position.z = 5) geriye çekmektir.
AxesHelper köken noktasından çıkan üç ok: Three.js dünya uzayında X kırmızı, Y yeşil, Z mavidir; sağ el kuralıyla aynı kod renkleri. Izgara yalnızca derinlik sezgisi içindir; eksenler asıl referanstır. Sahne editöründeki renkli oklarla bire bir aynı sözdizimi değildir; amaç «hangi eksen hangi renk»i görmek ve kamerayı serbestçe çevirmektir.
Ağaç İçinde Gezinme (Traversal) Mekanizması
Scene Graph, nesneleri iç içe (ebeveyn-çocuk) bir ağaç yapısında sakladığı için basit bir
for döngüsüyle tüm elemanlara ulaşmak mümkün değildir. Sahneye dışarıdan
yüklediğiniz karmaşık bir GLTF modelinin (örneğin yüzlerce parçadan oluşan bir otomobilin)
içindeki belirli materyalleri değiştirmek veya gölge ayarlarını topluca güncellemek
istediğinizde scene.traverse() metodunu
kullanırsınız.
Bu metod, kök düğümden (scene) başlayarak tüm alt dalları (children) derinlemesine tarar (depth-first search) ve verdiğiniz geri çağırma fonksiyonunu (callback) ağaçtaki her bir nesne için tek tek çalıştırır.
// Örnek: Sahnedeki tüm Mesh (Geometri+Materyal) nesnelerini tespit et ve gölge dökümünü aç
let meshCount = 0;
scene.traverse((object) => {
// Nesne bir mesh ise (örneğin boş bir Group veya Light değilse)
if (object.isMesh) {
meshCount++;
object.castShadow = true; // Her mesh'in gölge atmasını sağla
object.receiveShadow = true; // Her mesh'in gölge kabul etmesini sağla
}
});
console.log(`Sahne ağacı tarandı. Toplam mesh sayısı: ${meshCount}`);
Kavramsal Not: Sahne Eşittir "Atmosfer"
Scene nesnesini sadece bir sepet
olarak düşünmek hatadır. O aynı zamanda evrenin fiziksel atmosferidir. Uzayın arka plan
rengi (.background), objelerin üzerine düşen küresel
ışık yansımaları (.environment) ve derinlik hissi
veren çevresel sis (.fog) gibi tüm "atmosferik"
kararlar doğrudan kök düğüm olan sahnede tanımlanır. Bu özelliklerin kodsal entegrasyonu
ve performans etkileri için Görünüm ve Çevre Ayarları başlığını inceleyebilirsiniz.
Temel Metotlar ve Sahne Yönetimi
Sahne yönetimi (Scene Management); evrene nesne ekleyip çıkarma, küresel atmosferi belirleme
ve performans optimizasyonu süreçlerini kapsar. Aşağıdaki metotlar doğrudan
THREE.Scene ve Object3D sınıflarının temel API'sini yansıtır.
(Kamera matrisleri, gölge haritası hesaplamaları veya PBR ışık motoru detayları kendi özel
bölümlerinde işlenmektedir.)
1. Nesne Yönetimi: Ekleme, Çıkarma ve Temizleme
Sahne grafiğine (Scene Graph) nesne bağlamak veya bağlantısını koparmak için kullanılan
birincil komutlardır.
Kritik Performans Notu: scene.clear() veya
scene.remove() komutları, nesneleri sadece sahneden (görünürlükten) çıkarır;
onları RAM (bellek) ve GPU (VRAM) üzerinden tamamen silmez. Bellek sızıntılarını (memory
leak) önlemek için kullanılmayan Geometri ve Materyallerin
.dispose() metoduyla manuel olarak
temizlenmesi zorunludur.
const cube = new THREE.Mesh(geometry, material);
scene.add(cube); // Küpü sahne ağacına ekler (Ekranda görünür)
scene.remove(cube); // Küpü sahne ağacından çıkarır (Ekranda gizlenir)
scene.clear(); // Sahneye bağlı TÜM çocuk (child) nesneleri koparır
// Not: clear() sonrası geometry.dispose() ve material.dispose() çağrılmalıdır.
2. Görünüm Ayarları: Atmosfer ve Çevre
Sahnenin küresel görünüm özellikleridir. .background boşluktaki zemin rengini veya dokusunu belirler. .fog, kameradan uzaklaştıkça nesnelerin silikleşerek derinlik kazanmasını (z-depth fade) sağlar. .environment ise sahnedeki tüm fiziksel tabanlı (PBR) materyallerin üzerine düşecek küresel (360 derece) ışık ve yansıma verisini (genellikle bir HDR dokusu üzerinden) topluca tanımlar.
scene.background = new THREE.Color(0x111122); // Uzay boşluğunu koyu mavi yapar
scene.fog = new THREE.FogExp2(0x111122, 0.02); // Derinlik arttıkça artan eksponansiyel sis
// HDR Çevre Yansıması (Image-Based Lighting)
// scene.environment = hdrTexture; // Detaylar materyal/ışık konusunda işlenecektir.
3. Performans ve Hata Ayıklama (Override Material)
Özellikle binlerce nesneden oluşan karmaşık projelerde (örneğin dev bir şehir modeli), FPS düşüşlerinin karmaşık materyallerden mi yoksa aşırı poligon sayısından mı (vertex bottleneck) kaynaklandığını test etmek için kullanılır. Sahnede yüzlerce farklı renk/doku atanmış olsa bile, bu metot aktifken her şey tek bir test materyaliyle çizilir.
// Sahnedeki TÜM nesneleri, kendi materyallerini ezerek yarı saydam kırmızı ile çizer
scene.overrideMaterial = new THREE.MeshStandardMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.5,
wireframe: true // Poligon (üçgen) yapısını görmek için kullanışlıdır
});
// Test/Debug işlemi bittikten sonra eski haline döndürmek için:
// scene.overrideMaterial = null;
4. Sahne Seviyesinde Performans ve Optimizasyon
Sahnede binlerce nesne olduğunda GPU'nun gereksiz hesaplamalar yapmasını engellemek, 60 FPS hedefini korumanın en kritik adımıdır. Three.js'in sağladığı yerleşik optimizasyon tekniklerinin sahne hiyerarşisindeki rolleri şunlardır:
- Frustum Culling (Görüş Alanı Ayıklaması): Three.js doğuştan akıllıdır. Kameranın o anki bakış açısının (Frustum) dışında kalan, yani ekranın arkasında veya çok uzağında olan nesneler için işlemci gücü harcanmaz; bu nesneler çizim aşamasına (render pipeline) gönderilmez. Bu işlem otomatiktir ve sahne tarafında ekstra kod yazmanızı gerektirmez.
- LOD (Level of Detail - Detay Seviyesi): Nesne kameradan uzaklaştıkça, yüksek çözünürlüklü (milyon poligonlu) modelin yerine otomatik olarak daha düşük poligonlu basit bir versiyonunun sahneye yerleştirilmesi mantığıdır. Performansı dramatik şekilde artırır.
-
Instancing (Örneklendirme):
Ormandaki binlerce ağacı veya yağmur damlalarını tek tek
add()metoduyla sahneye eklemek performansı çökertir. Bunun yerine tek bir geometri oluşturulupInstancedMeshsınıfı kullanılarak GPU'ya "Bu tek ağacı al, verdiğim şu 10.000 farklı koordinatta tek seferde (Single Draw Call) çiz" komutu verilir. -
Katmanlar
(
object.layers): Kamera ve nesneler arasında görünürlük filtrelemesi yapmanızı sağlar. Toplam 32 kanallı bir radyo sistemi gibi çalışır. Örneğin ana 3D dünyayı Katman 0'a, üzerine binen 3D Arayüz (UI) elemanlarını Katman 1'e eklerseniz, farklı kameraların sadece belirlediğiniz katmanları "dinlemesini" sağlayabilirsiniz.
// Nesneyi 1. kanala (katman) taşıyoruz
uiObject.layers.set(1);
// Ana kameranın 1. kanalı dinlemesini (görmesini) kapatıyoruz
mainCamera.layers.disable(1);
// Arayüz kamerasının ise SADECE 1. kanalı dinlemesini sağlıyoruz
uiCamera.layers.enable(1);
uiCamera.layers.disable(0); // Varsayılan katman 0'ı kapat
5. Gölge Bayrakları (Sahne - Renderer İletişimi)
Gerçek zamanlı gölgeler donanım için çok ağır işlemlerdir ve varsayılan olarak kapalıdır. Gölgeleri aktif etmek sadece ışık kaynağını ayarlamakla bitmez; sahne grafiğindeki nesnelerin de bu fiziksel olaya katılıp katılmayacağını açıkça belirtmeniz gerekir.
Gölge haritalarının kalitesi (resolution) veya ışık türleri kendi sayfalarında incelense de, sahne seviyesindeki birincil görev; hangi geometrinin bir engel oluşturup gölge fırlatacağına (castShadow) ve hangi yüzeyin üzerine gölge düşmesini kabul edeceğine (receiveShadow) karar vermektir.
// 1. Adım: Motor seviyesinde gölge algoritmasını uyandır (Renderer görevi)
renderer.shadowMap.enabled = true;
// 2. Adım: Sahnedeki her bir nesneye gölge fizik kurallarını uygula (Sahne görevi)
scene.traverse((object) => {
if (object.isMesh) {
object.castShadow = true; // Işığı kes ve gölge fırlat (örn: ağaç gövdesi)
object.receiveShadow = true; // Üzerine düşen gölgeyi göster (örn: zemin)
}
});
Sahne büyüdükçe traverse maliyeti ve draw call sayısı artar; sahne
yönetimi yalnızca görsel düzen değil,
performans mühendisliği konusudur. Renderer’ın kare başına bu sahneyi
nasıl işlediği
renderer giriş
sayfasında kalır.
Üçlü pratikte renderer.render(scene, camera) ile birleşir; aşağıdaki
örnek bu çağrıyı minimal bir kurulumda gösterir.
Tam örnek: sahne + kamera + renderer
Aşağıdaki blok, yukarıdaki bağlamı tek dosyada toplayan minimal bir kurulumdur; sahne kurulduktan sonra kamera ve renderer ile animasyon döngüsüne bağlanır.
Bu sürümde PerspectiveCamera çoğu zaman scene.add(camera) ile
grafiğe eklenmez; yine de renderer.render(scene, camera) satırında ikili
birlikte kullanılır. İsterseniz kamerayı da sahneye ekleyerek tek kökten
traverse ile yönetebilirsiniz.
import * as THREE from 'three';
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0c12);
const camera = new THREE.PerspectiveCamera(
50,
window.innerWidth / window.innerHeight,
0.1,
100
);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x5ec8ff })
);
scene.add(mesh);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(2, 3, 4);
scene.add(light);
function animate() {
requestAnimationFrame(animate);
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
Demo sabitleri tablosu (editor örneği)
Aşağıdaki tablo, üstteki tam
editor kodundaki sayısal değerlerin ön haritasıdır. Bu sayfada
canlı WebGL demosu yoktur; sabitler doğrudan gösterilen main.js bloğundan
okunur. Diyagram ile
birlikte kullanın.
| Sahne / rol | Parametre | Değer | Tür |
|---|---|---|---|
Scene · ortam |
scene.background |
new THREE.Color(0x0a0c12) |
🔒 Sabit |
PerspectiveCamera |
fov |
50 |
🔒 Sabit |
aspect |
window.innerWidth / window.innerHeight |
↔ Pencereye bağlı | |
near / far |
0.1 / 100 |
🔒 Sabit | |
camera.position |
z = 5 (x, y varsayılan 0) |
🔒 Sabit | |
WebGLRenderer |
Oluşturucu seçenekleri | { antialias: true } |
🔒 Sabit |
setPixelRatio |
Math.min(window.devicePixelRatio, 2) |
↔ Cihaza bağlı (üst sınır 2) | |
Mesh · geometri |
BoxGeometry |
1 × 1 × 1 |
🔒 Sabit |
Mesh · materyal |
MeshStandardMaterial.color |
0x5ec8ff |
🔒 Sabit |
DirectionalLight |
renk · yoğunluk · position |
0xffffff · 1 · (2, 3, 4) |
🔒 Sabit |
| Animasyon döngüsü | mesh.rotation.y artışı |
+= 0.01 / kare |
🔒 Sabit |
| Modül | import |
three (örnek varsayım; bundler / CDN projenize göre) |
ℹ Bağlam |
Püf noktası: siyah ekran
Her şeyi doğru yaptığınızı düşünüyorsanız ama ekran siyah kalıyorsa: ya bakış
noktası mesh'in içinde kalmıştır (Z pozisyonunu
artırarak ayırın) ya da MeshStandardMaterial kullanıyorsanız sahneye
yeterli ışık eklememiş olabilirsiniz; PBR malzeme ışık
gerektirir.