Three.js · Renderer
Renderer: piksel işleme merkezi
Three.js'te ekrana görüntü basan katman WebGLRenderer'dır (veya
alternatif renderer sınıfları). Ağır iş CPU'da değil GPU'da
yürür; her karede render(scene, camera) ile o anki sahne ve kamera
durumu okunur, piksel tamponuna yazılır ve sonuç <canvas> üzerinden
sayfaya taşınır. Renderer sahne grafiğini güncellemez; yalnızca
çıktı üretir.
Holodepth üçlüsünde roller birbirini tamamlar: sahne yapıyı tutar, kamera hangi kesitin çizileceğini seçer, renderer bu kesiti GPU ile işler. Bu metinde üçlünün çıktı ve yürütme ayağını okuyorsunuz; sahne grafiği ve kamera matrisleri kardeş sayfalarda kalır.
Aşağıda render hattının özeti, requestAnimationFrame döngüsü,
setSize / pixel ratio, shadowMap bayrakları, API tablosu ve
tam kurulum örneği var; ışık türleri, materyal modelleri veya
scene.traverse burada tekrar anlatılmaz.
WebGLRenderer ve Görüntüleme Hattı (Render Pipeline)
WebGLRenderer ve GPU Donanımı
Three.js ekosisteminde WebGLRenderer,
matematiksel matrisleri
(sahne, modeller, kamera açıları) ekranda görebileceğimiz piksellere dönüştüren
motor (yürütücü
katman) olarak görev yapar. Bu sınıf, grafik kartınızın (GPU) gücünü web
tarayıcısına taşıyarak
işlemleri gerçekleştirir ve üretilen nihai görüntüyü bir HTML <canvas>
elemanı olan .domElement özelliği üzerinden sayfaya
(DOM) enjekte eder.
Geleneksel web geliştirme süreçlerinden farklı olarak, 3D grafiklerin çizimi iki kritik donanım felsefesi üzerine inşa edilmiştir:
- Paralel Hesaplama Performansı: Standart JavaScript (CPU üzerinde) işlemleri sırayla (tek şeritli bir yol gibi) yürütür. GPU ise donanımsal olarak binlerce küçük çekirdekten oluşan devasa çok şeritli bir otoyol gibidir. Ekranda gördüğünüz sahnenin her bir pikseli için (örneğin 1080p ekranda 2 milyondan fazla piksel) ışık, materyal ve derinlik hesabı yapılması gerekir. Bu devasa veri yükü JavaScript ile "tek tek" boyanamayacağı için WebGLRenderer bu işleri GPU çekirdeklerine dağıtır ve aynı anda (paralel olarak) hesaplatır.
-
Donanım Hızlandırması (Hardware
Acceleration):
WebGLRenderer, canvas üzerinde düşük seviyeli bir WebGL Bağlamı (Context) açar ve çizim komutlarını tarayıcı aradan çekilecek şekilde doğrudan GPU sürücülerine iletir. HTML Canvas 2D API'sinde olduğu gibi her karedefillRect()fonksiyonu çağırmazsınız. Akıcı bir performans (60 FPS), bu donanım hattının sürekli ve kesintisiz beslenmesiyle mümkündür.
Sistemin asgari düzeyde nasıl çalıştığını görmek için Sahne girişindeki tam örneği inceleyebilir; 2D çizim metodolojisi ile 3D WebGL mimarisi arasındaki yapısal farklar için Canvas vs WebGL dokümanına başvurabilirsiniz.
Salt Okunur (Read-Only) Mimari: Renderer Sahneyi Değiştirmez
Three.js mimarisini kavrarken yapılan en yaygın hata, işleyicinin (Renderer) dünyadaki
fiziksel nesneleri
hareket ettirdiğini düşünmektir.
WebGLRenderer kesinlikle sahne
grafiğini (Scene
Graph) veya nesnelerin durumunu (State) değiştirmez.
Renderer, bir fotoğraf makinesinin deklanşörü gibi çalışır. Sadece o anki deklanşör anında;
Scene
nesnesinin içindeki koordinatları (kim nerede duruyor?) ve Camera nesnesinin
bakış açısını (nereden
bakılıyor?) salt okunur (read-only) olarak alır. Bu iki veri paketini
birleştirerek bir 2D
görüntü (fotoğraf) üretir. Animasyonlu bir nesneyi döndürmek istiyorsanız, bu işlemi
Renderer'da değil, doğrudan
nesnenin kendi özellikleri (örn: mesh.rotation.y)
üzerinden yapmalısınız.
Bir Karenin (Frame) Anatomisi: İşlem Boru Hattı
Animasyon döngünüzün içindeki renderer.render(scene, camera) satırı her saniye
60 kez (60 FPS)
çağrıldığında, donanım seviyesinde sırasıyla şu grafik boru hattı (Graphics Pipeline)
işletilir:
- 1. Ayıklama (Culling): Kameranın görüş açısından (Frustum) çıkan nesneler tespit edilir ve bu kare için işlem sırasından düşürülür.
- 2. Matris Çözümleme (Transform): Ekranda kalan her bir nesnenin 3D uzaydaki X, Y, Z koordinatları, kameranın projeksiyon matrisi ile çarpılarak 2D ekran (piksel) koordinatlarına çevrilir.
- 3. Vertex Shader & Işıklandırma: Geometrilerin köşe noktaları hesaplanır. Eğer sahnede ışıklar varsa (PBR), nesnelerin kameraya olan açılarına göre gölge ve aydınlanma değerleri GPU üzerinde saptanır.
- 4. Rasterizasyon (Fragment Shader): Matematiksel alanlar, ekrandaki piksellere (kırmızı, yeşil, mavi renk değerlerine) dönüştürülür.
-
5. Derinlik (Z-Buffer) ve Yazma:
Hangi pikselin önde, hangisinin arkada kaldığı (Z-Index) hesaplanır, varsa saydamlık
(blending) harmanlanır
ve nihai sonuç ekrandaki
<canvas>elementine fırlatılır.
(Matris Verisi) Görünürlük
(Frustum Culling) Işık & Materyal
(Vertex Shader) Rasterizasyon
(Fragment Shader) Z-Buffer & Blending
(Derinlik ve Saydamlık) Canvas
(Nihai Çıktı)
Yukarıdaki şema, renderer.render()
fonksiyonunun çağrıldığı o
milisaniyelik zaman diliminde ekran kartının (GPU) arka planda yürüttüğü matematiksel sırayı
temsil eder. Ham
koordinat verisi önce filtrelenir (Görünürlük), ardından donanım seviyesinde ışıkla
harmanlanır ve en son
tarayıcının anlayabileceği 2D piksellere (Rasterizasyon) dönüştürülerek ekrana basılır.
Render Döngüsü (Animation Loop): Kalp Atışı
Sahneyi ve kamerayı kurup işleyiciyi (Renderer) hazırlamak, fotoğraf makinesini tripoda bağlamak gibidir; deklanşöre basılmadığı sürece ekranda hiçbir şey göremezsiniz. Eğer uygulamanız statik bir mimari görselleştirme değilse (yani dönen bir model, karakter animasyonu veya fare etkileşimi içeriyorsa), motorun sürekli olarak yeni kareler (frame) çizmesi gerekir.
Bunu JavaScript'te while veya setInterval gibi tehlikeli,
işlemciyi kilitleyen döngülerle yapamayız. Bunun yerine, tarayıcının ekran yenileme hızına
(genellikle saniyede 60 kez) doğrudan senkronize çalışan, performansı mükemmel şekilde
optimize eden yerleşik requestAnimationFrame metodunu kullanırız. Bu,
Three.js uygulamanızın kalp atışıdır.
function animate() {
// Tarayıcıya "bir sonraki boş karede bu fonksiyonu tekrar çalıştır" emrini verir.
// Sekme arkaplana atıldığında veya ekran kapandığında otomatik olarak duraklayarak pili korur.
requestAnimationFrame(animate);
// Varsa animasyon mantıkları buraya yazılır
// (Örn: cube.rotation.y += 0.01)
// O anki güncel durumun fotoğrafını çek ve canvas'a bas
renderer.render(scene, camera);
}
// Kalp atışını ilk kez başlatır
animate();
Yukarıdaki blokta scene ve camera değişkenlerinin önceden
tanımlanmış olduğu varsayılır. Bu kısacık kod parçası, donuk bir 3D modeli alıp yaşayan,
etkileşimli bir dünyaya dönüştüren temel mühendisliktir. Bu döngünün, WebGL motorunun piksel
(pixel ratio) ve boyut ayarlamalarıyla birlikte nasıl entegre edildiğini görmek için
sayfanın sonundaki Tam Kurulum ve
Render Döngüsü bloğunu inceleyebilirsiniz. Zaman (Delta Time) bazlı gelişmiş
animasyon hesaplamaları ise "Zaman ve Hareket" bölümünde ele alınacaktır.
Kritik kurulum parametreleri
new THREE.WebGLRenderer({ … }) satırındaki seçenekler, canvas ve WebGL
bağlamının ilk an nasıl açılacağını belirler; çoğu seçenek
sonradan değiştirilemez; gerekirse renderer yeniden oluşturulur. Görsel kalite,
şeffaflık ve GPU tercihi burada; piksel oranı ve boyut
bir sonraki alt başlıkta,
gölge ve renk uzayı
tam örnekte tamamlanır.
- Antialias: Kenar ve eğimli yüzeylerde görülen tırtıklanmayı
(aliasing) azaltır; çokgen kenarları daha yumuşak görünür.
{ antialias: true }ek GPU maliyeti getirir — mobilde pil ve ısınma için bazenfalsebırakılır; masaüstü ve vitrin sahnelerinde sık açık tutulur. Kapalıyken sonradan post-processing ile AA mümkün olabilir; burada yalnızca oluşturucu bayrağı anlatılır. - Alpha:
alpha: trueiken WebGL tamponu şeffaf olabilir; çizilmeyen veya yarı saydam piksellerde altta sayfanın CSS arka planı görünür. Tam opak sahne için geneldesetClearColor(ve gerekirse alpha kanalı) ile birlikte düşünülür — bu, sahnebackgroundyaklaşımından farklı bir katmandır. Şeffaf canvas, 3B içeriği HTML/CSS katmanlarıyla kompozisyon için kullanılır (ör. sayfa düzeni üzerinde canvas, HUD). - powerPreference: Tarayıcıya hangi GPU profilini tercih
ettiğinizi bildirir; garanti değildir — son söz tarayıcı ve işletim
sistemindedir. Çift GPU'lu dizüstülerde
"high-performance"bazen ayrık (dedicated) kartı seçtirir;"low-power"pil ömrünü korur. Yoğun sahnelerdehigh-performanceyaygındır; ölçüm yapmadan her projede açmak şart değildir.
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
powerPreference: 'high-performance',
});
Ekran Netliği: Piksel Yoğunluğu (Pixel Ratio) ve Boyutlandırma
WebGLRenderer'ın ürettiği görüntünün donanımsal olarak ne kadar keskin olacağını ve ekranda ne kadar fiziksel alan kaplayacağını belirleyen iki kritik yapılandırma aşaması vardır:
-
Piksel Yoğunluğu (setPixelRatio):
Modern mobil cihazlar ve Retina (Yüksek DPI) monitörler, standart ekranlara kıyasla aynı
alana çok daha
fazla piksel sığdırır. Motorun işleme çözünürlüğünü ekranla eşleştirmezseniz 3D
görüntünüz bulanık (çamurlu)
çıkar. Ancak, çözünürlüğü kontrolsüzce artırmak GPU'nun hesaplama yükünü eksponansiyel
olarak artırarak FPS
düşüşüne yol açar. Bu darboğazı önlemek için endüstri standardı olan
setPixelRatio(Math.min(window.devicePixelRatio, 2))formülü kullanılır. Bu akıllı limit, cihazın doğal keskinliğini yakalarken performansı korumak adına çizim çarpanını maksimum 2 ile sınırlar. -
Çizim Alanı (setSize):
setSize()metodu, HTML<canvas>elementinin tarayıcı içindeki genişlik ve yükseklik değerlerini ayarlar. Tam ekran (fullscreen) bir deneyim yaratırken genellikle tarayıcı penceresinin güncel ölçüleri (window.innerWidthvewindow.innerHeight) referans alınır. Kullanıcı pencere boyutunu değiştirdiğinde görüntünün sünmemesi veya pikselleşmemesi için, bu boyutların tarayıcının yerleşikresizeolayında (event listener) sürekli güncellenmesi gerekir.
Gölgeler ve Performans Maliyeti
Gerçek zamanlı gölge hesaplaması (Shadow Mapping), WebGL hattındaki en pahalı işlemlerden biridir. Motor, sahneyi önce kameranın gözünden, ardından sahnede gölge atan her bir ışığın gözünden tekrar çizer. Bu nedenle renderer.shadowMap.enabled = true komutu projeye ciddi bir ek maliyet getirir. Optimizasyon kuralı şudur: Yalnızca gerçekten gölgeye ihtiyacı olan ana ışıkları (castShadow) ve gölgeyi üzerine alması gereken büyük yüzeyleri (zemin, duvar gibi receiveShadow) manuel olarak belirleyin.
Teknik Tablo: Renderer API Özeti
| Metot / Özellik | Kavramsal Açıklama | Mimari Sorumluluk (Neden Önemli?) |
|---|---|---|
.render(scene, camera) |
O anki sahneyi, belirtilen kameranın perspektifinden hedefe çizer. | Sistemin kalbidir; requestAnimationFrame döngüsü içinde sürekli
çağrılarak animasyonu
var eder. |
.domElement |
Renderer'ın arka planda oluşturduğu fiziksel <canvas> HTML
öğesidir. |
3D dünyayı normal web sayfasına (DOM'a) bağlamak (append) için köprü görevi görür. |
.shadowMap |
Gölge haritası (Shadow Map) algoritmalarının yönetim objesidir. | Gerçekçi sahne aydınlatması için .enabled = true yapılmalı ve uygun
filtreleme (PCFSoft
vb.) seçilmelidir. |
.setClearColor() |
Her yeni kareden önce tuvalin (tamponun) hangi renkle temizleneceğini belirler. | Eğer scene.background kullanılmıyorsa, evrenin temel arkaplan
rengini oluşturmak için
bir alternatiftir. |
.outputColorSpace |
Çıktı renk uzayını (Color Space) tanımlar (ör.
THREE.SRGBColorSpace).
|
Fiziksel materyallerin (PBR) ve kaplamaların (Texture) monitörde soluk görünmemesi, doğru gamma değerleriyle ekrana basılması için kritiktir. |
Tam Kurulum ve Render Döngüsü
Şimdiye kadar anlatılan WebGLRenderer ayarlarının (renk uzayı, piksel
yoğunluğu, donanım seçimi ve gölge hesaplamaları) tek bir modern, üretime (production) hazır
konfigürasyon bloğunda nasıl birleştiğini aşağıda görebilirsiniz.
// 1. Renderer Sınıfını Başlat ve Donanım Parametrelerini Gir
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
powerPreference: 'high-performance'
});
// 2. Çözünürlük ve Ekran Boyutunu Ayarla
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// 3. Renk Uzayı ve Fiziksel Işık/Gölge Ayarları
renderer.outputColorSpace = THREE.SRGBColorSpace; // Işıkların soluk görünmesini engeller
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Gölgelerin kenarlarını yumuşatır
// 4. Üretilen WebGL Canvas'ını HTML Sayfasına (DOM) Yerleştir
document.body.appendChild(renderer.domElement);
// 5. Animasyon Döngüsünü Kur (Scene ve Camera değişkenleri tanımlı kabul edilir)
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
Holodepth Mimari Notu: Kesin 16.6ms Bütçesi
Akıcı bir 3D deneyimi, saniyede 60 kare (60 FPS) hızında çalışmalıdır. Bu matematiği tersten kurduğumuzda, GPU ve CPU'nun ekranı silip, yeni ışıkları hesaplayıp, matrisleri çarpıp resmi çizmek için sahip olduğu süre tam olarak 16,6 milisaniyedir. Eğer sahnenize milyonlarca poligon (vertex) veya onlarca dinamik ışık eklerseniz, motor bu 16.6ms barajını aşar ve uygulama "kasmaya" (frame drop) başlar. Three.js'te ustalığın %80'i kod yazmak değil, görsel kaliteden ödün vermeden bu matematiksel işlem bütçesini (Draw Call ve Vertex limitlerini) kontrol altında tutabilmektir.