holodepth

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 Group oluş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.

Mini demo · sağ el · RGB eksenler OrbitControls · sürükle / tekerlek

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şturulup InstancedMesh sı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.

Editor örneğinin yapısı (diyagram)
Scene Mesh (Box) DirectionalLight
PerspectiveCamera scene + camera WebGLRenderer canvas

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.

scene-entry.html — Tam örnek editör bloğu (#box-code-editor-triad-full)
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.